From 69ac6eb6153b016c39bbe55c85f15e3478032182 Mon Sep 17 00:00:00 2001 From: troido Date: Mon, 9 Mar 2020 16:54:26 +0100 Subject: can now include variables (like health) in serialisation --- src/assemblage.rs | 26 +++++++++++++++++++++++--- src/components/mod.rs | 7 ++----- src/components/serialise.rs | 16 ++++++++++++++++ src/componentwrapper.rs | 13 +++++-------- src/room.rs | 14 ++++++++++++-- 5 files changed, 58 insertions(+), 18 deletions(-) create mode 100644 src/components/serialise.rs (limited to 'src') diff --git a/src/assemblage.rs b/src/assemblage.rs index adf1ba5..8e3a349 100644 --- a/src/assemblage.rs +++ b/src/assemblage.rs @@ -18,7 +18,8 @@ type ArgumentDef = (String, ParameterType, Option); pub struct Assemblage { pub arguments: Vec, pub components: Vec<(ComponentType, HashMap)>, - pub save: bool + pub save: bool, + pub extract: Vec<(String, ComponentType, String)> } impl Assemblage { @@ -78,7 +79,26 @@ impl Assemblage { let mut assemblage = Self { arguments: Self::parse_definition_arguments(val.get("arguments").unwrap_or(&json!([])))?, components: Self::parse_definition_components(val.get("components").unwrap_or(&json!([])))?, - save: val.get("save").unwrap_or(&json!(true)).as_bool().ok_or(aerr!("assemblage save not a bool"))? + save: val.get("save").unwrap_or(&json!(true)).as_bool().ok_or(aerr!("assemblage save not a bool"))?, + extract: val + .get("extract") + .unwrap_or(&json!({})) + .as_object().ok_or(aerr!("assemblage extract not a bool"))? + .into_iter() + .map(|(argname, val)| { + Ok(( + argname.to_string(), + ComponentType::from_str( + val + .get(0).ok_or(aerr!("index 0 not in extract value"))? + .as_str().ok_or(aerr!("extract component name not a string"))? + ).ok_or(aerr!("extract invalid component name"))?, + val.get(1) + .ok_or(aerr!("index 1 not in extract value"))? + .as_str().ok_or(aerr!("extract member name not a string"))?.to_string() + )) + }) + .collect::>>()? }; let name = if let Some(nameval) = val.get("name") { Some(nameval.as_str().ok_or(aerr!("name not a string"))?.to_string()) @@ -161,7 +181,7 @@ impl Assemblage { components.push(ComponentWrapper::load_component(*comptype, compargs).ok_or(aerr!("failed to load component"))?); } if template.save && self.save { - components.push(ComponentWrapper::Serialise(Serialise{template: template.clone()})); + components.push(ComponentWrapper::Serialise(Serialise{template: template.clone(), extract: self.extract.clone() })); } Ok(components) } diff --git a/src/components/mod.rs b/src/components/mod.rs index c3e8d5d..b43eba1 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -5,6 +5,7 @@ pub mod faction; pub mod interactable; pub mod equipment; pub mod inventory; +pub mod serialise; pub use item::Item; pub use messages::{ @@ -16,6 +17,7 @@ pub use faction::Faction; pub use interactable::Interactable; pub use equipment::Equipment; pub use inventory::Inventory; +pub use serialise::Serialise; use specs::{ DenseVecStorage, @@ -118,11 +120,6 @@ impl Health { } } -#[derive(Component, Debug, Clone)] -pub struct Serialise { - pub template: Template -} - #[derive(Component, Debug, Clone)] pub struct RoomExit { pub destination: RoomId, diff --git a/src/components/serialise.rs b/src/components/serialise.rs new file mode 100644 index 0000000..aa79d93 --- /dev/null +++ b/src/components/serialise.rs @@ -0,0 +1,16 @@ + +use specs::{ + Component, + DenseVecStorage +}; +use crate::{ + Template, + componentwrapper::ComponentType +}; + + +#[derive(Component, Debug, Clone)] +pub struct Serialise { + pub template: Template, + pub extract: Vec<(String, ComponentType, String)> +} diff --git a/src/componentwrapper.rs b/src/componentwrapper.rs index a49ac79..b1fd64d 100644 --- a/src/componentwrapper.rs +++ b/src/componentwrapper.rs @@ -83,27 +83,24 @@ macro_rules! components { } use specs::{World, Entity, WorldExt}; - pub fn extract_parameter(typ: ComponentType, parameter: &str, world: World, ent: Entity) -> Option { + pub fn extract_parameter(typ: ComponentType, parameter: &str, world: &World, ent: Entity) -> Option { match typ { $( #[allow(path_statements)] ComponentType::$comp => { - None:: $( - ; if parameter == stringify!($paramname) { #[allow(unreachable_code, non_snake_case)] - Some(Parameter::$paramtype({ + return Some(Parameter::$paramtype({ let components = world.read_component::(); #[allow(unused_variables)] let $comp = components.get(ent)?; $extraction })) - } else { - None } )* + None:: } )* } @@ -119,7 +116,7 @@ macro_rules! components { }; // full definition minus variable exraction (pre: ($($done: tt)*) $comp: ident ($($paramname: ident : $paramtype: ident),*) $creation: expr; $($tail:tt)*) => { - components!(pre: ($($done)* $comp ($($paramname : $paramtype, {panic!(format!("can not extract {} for {}", stringify!($paramname), stringify!($comp)))}),*) $creation;) $($tail)*); + components!(pre: ($($done)* $comp ($($paramname : $paramtype, {None?}),*) $creation;) $($tail)*); }; // full definition (pre: ($($done: tt)*) $comp: ident ($($paramname: ident : $paramtype: ident ($extraction: expr)),*) $creation: expr; $($tail:tt)*) => { @@ -146,7 +143,7 @@ components!( Item (ent: Template, name: String, action: Action); Inventory () {panic!("inventory from parameters not implemented")}; Health (health: Int, maxhealth: Int); - Serialise (template: Template); + Serialise () {panic!("serialise from parameters not implemented")}; RoomExit (destination: String, dest_pos: String) { RoomExit { destination: RoomId::from_str(&destination), diff --git a/src/room.rs b/src/room.rs index e78cbd5..983ba11 100644 --- a/src/room.rs +++ b/src/room.rs @@ -38,6 +38,7 @@ use crate::{ savestate::SaveState, Template, playerstate::{PlayerState, RoomPos}, + componentwrapper::extract_parameter, Pos, PlayerId, RoomId, @@ -201,11 +202,20 @@ impl <'a, 'b>Room<'a, 'b> { } pub fn save(&self) -> SaveState { + let entities = self.world.entities(); let positions = self.world.read_component::(); let serialisers = self.world.read_component::(); let mut state = SaveState::new(); - for (pos, serialiser) in (&positions, &serialisers).join() { - state.changes.entry(pos.pos).or_insert_with(Vec::new).push(serialiser.template.clone()); + for (entity, pos, serialiser) in (&entities, &positions, &serialisers).join() { + let mut template = serialiser.template.clone(); + for (argument, component, member) in &serialiser.extract { + if let Some(parameter) = extract_parameter(*component, member.as_str(), &self.world, entity){ + template.kwargs.insert(argument.clone(), parameter); + } else { + println!("failed to extract parameter {:?} from {:?}", member, component); + } + } + state.changes.entry(pos.pos).or_insert_with(Vec::new).push(template); } state } -- cgit