diff --git a/examples/toml-stuff.rs b/examples/toml-stuff.rs new file mode 100644 index 0000000..99d2bc0 --- /dev/null +++ b/examples/toml-stuff.rs @@ -0,0 +1,19 @@ +use bevy::utils::HashMap; +use serde::Deserialize; +use toml::Table; + +#[derive(Deserialize, Debug)] +enum Val { + A(String), + B(usize), + C(bool), +} + +fn main() { + let s = r#"val = "asdf" +other = 123 +final = false + "#; + let v = toml::from_str::(s).unwrap(); + println!("{:?}", v); +} diff --git a/src/tweak.rs b/src/tweak.rs index 9c99436..2a21af1 100644 --- a/src/tweak.rs +++ b/src/tweak.rs @@ -1,5 +1,6 @@ use crate::prelude::*; use bevy::asset::AsyncReadExt; +use bevy::utils::HashMap; use bevy::{ asset::{io::Reader, AssetLoader, LoadContext}, reflect::TypePath, @@ -17,7 +18,8 @@ impl Plugin for TweakPlugin { fn build(&self, app: &mut App) { app.add_systems(OnEnter(GameState::Loading), load_tweakfile); - app.init_asset::().register_asset_loader(TweakfileLoader); + app.init_asset::() + .register_asset_loader(TweakfileLoader); } } @@ -32,7 +34,7 @@ pub(crate) struct GameTweakfile { } /// Tweakfile contains tweaks made to other parts of the game -#[derive(Debug, Deserialize, TypePath, Asset)] +#[derive(Debug, Deserialize, TypePath, Asset, Default)] pub struct Tweakfile { #[serde(default)] pub audio: audio::AudioTweaks, @@ -42,6 +44,125 @@ pub struct Tweakfile { pub display2d: display2d::tweaks::Display2dTweaks, } +#[derive(Debug, Asset, TypePath)] +pub struct Tweaks(HashMap); + +impl Tweaks { + fn from_table( + table: &toml::Table, + load_context: &mut LoadContext, + base: String, + ) -> Vec<(String, TweakValue)> { + table + .iter() + .flat_map(|(k, v)| { + let key = if base.len() > 0 { + format!("{}_{}", base, k) + } else { + k.clone() + }; + match v { + toml::Value::Table(t) => Tweaks::from_table(t, load_context, key), + toml::Value::Datetime(_) => panic!("This type is not supported!"), + _ => vec![(key, TweakValue::from_toml(v, load_context))], + } + }) + .collect() + } + + fn get_handle(&self, key: &str) -> Option> { + self.0.get(key).map(|val| Handle::::from(val.clone())) + } + + fn get_int(&self, key: &str) -> Option { + self.0.get(key).map(|val| i64::from(val.clone())) + } + + fn get_float(&self, key: &str) -> Option { + self.0.get(key).map(|val| f64::from(val.clone())) + } +} + +#[derive(Debug, Clone)] +pub enum TweakValue { + Handle(UntypedHandle), + Int(i64), + Float(f64), + Bool(bool), + Str(String), + List(Vec), +} + +impl TweakValue { + fn from_toml(val: &toml::Value, load_context: &mut LoadContext) -> TweakValue { + match val { + toml::Value::String(s) => { + if std::path::Path::new(&format!("assets/{}", s)).exists() { + TweakValue::Handle(load_context.load_untyped(s).untyped()) + } else { + TweakValue::Str(s.clone()) + } + } + toml::Value::Integer(i) => TweakValue::Int(*i), + toml::Value::Float(f) => TweakValue::Float(*f), + toml::Value::Boolean(b) => TweakValue::Bool(*b), + toml::Value::Array(a) => TweakValue::List( + a.iter() + .map(|v| TweakValue::from_toml(v, load_context)) + .collect(), + ), + toml::Value::Table(_) | toml::Value::Datetime(_) => { + panic!("This type is not supported!") + } + } + } +} + +impl From for Handle { + fn from(src: TweakValue) -> Handle { + match src { + TweakValue::Handle(h) => h.clone().typed::(), + _ => panic!("{:?} is not a handle", src), + } + } +} + +impl From for String { + fn from(src: TweakValue) -> String { + match src { + TweakValue::Str(s) => s, + _ => panic!("{:?} is not a bool", src), + } + } +} + +impl From for i64 { + fn from(src: TweakValue) -> i64 { + match src { + TweakValue::Int(i) => i, + _ => panic!("{:?} is not an integer", src), + } + } +} + +impl From for f64 { + fn from(src: TweakValue) -> f64 { + match src { + TweakValue::Float(f) => f, + _ => panic!("{:?} is not a float", src), + } + } +} + +impl From for bool { + fn from(src: TweakValue) -> bool { + match src { + TweakValue::Bool(b) => b, + _ => panic!("{:?} is not a bool", src), + } + } +} + #[derive(Default)] pub struct TweakfileLoader; @@ -70,9 +191,11 @@ impl AssetLoader for TweakfileLoader { let mut bytes = Vec::new(); reader.read_to_end(&mut bytes).await?; let s = std::str::from_utf8(bytes.as_slice())?; - let mut result = toml::from_str::(s)?; - result.display3d.load_dependencies(load_context); - Ok(result) + let parsed = toml::from_str::(s)?; + let list = Tweaks::from_table(&parsed, load_context, String::new()); + let result: HashMap = list.into_iter().collect(); + // Ok(Tweaks(result)) + Ok(Tweakfile::default()) }) }