From 323cd679cd29a8475c3b7486ce54ecd37620dbea Mon Sep 17 00:00:00 2001 From: troido Date: Tue, 4 Feb 2020 22:23:17 +0100 Subject: tried to implement deserialisation of entities --- src/assemblage.rs | 7 +++--- src/assemblages.rs | 6 ++--- src/components.rs | 7 +++--- src/compwrapper.rs | 48 +++++++++++++++++++++++++++++++++++++ src/load.rs | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 28 +++++++++++++++++----- src/room.rs | 9 +++++++ src/template.rs | 48 +++++++++++++++++++++++++++++++++++++ src/util.rs | 1 + 9 files changed, 208 insertions(+), 15 deletions(-) create mode 100644 src/compwrapper.rs create mode 100644 src/load.rs create mode 100644 src/template.rs (limited to 'src') diff --git a/src/assemblage.rs b/src/assemblage.rs index 8949205..a81ce82 100644 --- a/src/assemblage.rs +++ b/src/assemblage.rs @@ -1,5 +1,6 @@ +use std::any::Any; #[macro_export] @@ -21,7 +22,7 @@ macro_rules! assemblage { } #[allow(unused_variables, unused_mut)] - fn init_from_json(&mut self, mut args: Vec, kwargs: std::collections::HashMap<&str, serde_json::Value>) { + fn init_from_json(&mut self, mut args: Vec, kwargs: std::collections::HashMap) { $( if args.len() > 0 { let val = args.remove(0); @@ -54,9 +55,9 @@ macro_rules! unpack_json { } -pub trait Assemblage: Send + Sync { +pub trait Assemblage: Send + Sync + Any { fn build<'a>(&self, builder: specs::EntityBuilder<'a>) -> specs::EntityBuilder<'a>; - fn init_from_json(&mut self, args: Vec, kwargs: std::collections::HashMap<&str, serde_json::Value>); + fn init_from_json(&mut self, args: Vec, kwargs: std::collections::HashMap); } diff --git a/src/assemblages.rs b/src/assemblages.rs index c7140c9..fc0831c 100644 --- a/src/assemblages.rs +++ b/src/assemblages.rs @@ -38,11 +38,11 @@ mod tests { assert_eq!(p.name, "Joe"); p.init_from_json(vec![json!("Bob"), json!("Mike")], hashmap!()); assert_eq!(p.name, "Bob"); - p.init_from_json(vec![], hashmap!("sprite" => json!("stone"))); + p.init_from_json(vec![], hashmap!("sprite".to_string() => json!("stone"))); assert_eq!(p.name, "Bob"); - p.init_from_json(vec![], hashmap!("name" => json!("Teddy"))); + p.init_from_json(vec![], hashmap!("name".to_string() => json!("Teddy"))); assert_eq!(p.name, "Teddy"); - p.init_from_json(vec![json!("Bill")], hashmap!("name" => json!("Stan"))); + p.init_from_json(vec![json!("Bill")], hashmap!("name".to_string() => json!("Stan"))); assert_eq!(p.name, "Stan"); } } diff --git a/src/components.rs b/src/components.rs index 50cb13f..7517af9 100644 --- a/src/components.rs +++ b/src/components.rs @@ -28,7 +28,7 @@ impl Component for Position { #[derive(Debug, Clone)] pub struct Visible { pub sprite: String, - pub height: f32 + pub height: f64 } impl Component for Visible { type Storage = FlaggedStorage>; @@ -37,10 +37,10 @@ impl Component for Visible { #[derive(Component, Debug)] pub struct Controller(pub Control); -#[derive(Component, Debug)] +#[derive(Component, Debug, Clone)] pub struct Blocking; -#[derive(Component, Debug)] +#[derive(Component, Debug, Clone)] pub struct Played { pub name: String, pub is_new: bool @@ -50,3 +50,4 @@ impl Played { Played{name, is_new: true} } } + diff --git a/src/compwrapper.rs b/src/compwrapper.rs new file mode 100644 index 0000000..8028b49 --- /dev/null +++ b/src/compwrapper.rs @@ -0,0 +1,48 @@ + +use std::collections::HashMap; +use specs::{Builder, EntityBuilder}; +use serde_json::Value; +use super::components::{Visible, Blocking, Played}; + + +#[derive(Clone)] +pub enum CompWrapper{ + Visible(Visible), + Blocking(Blocking), + Player(Played) +} + +impl CompWrapper { + + pub fn build<'a>(&self, builder: specs::EntityBuilder<'a>) -> specs::EntityBuilder<'a> { + match self.clone() { + Self::Visible(c) => builder.with(c), + Self::Blocking(c) => builder.with(c), + Self::Player(c) => builder.with(c) + } + } + + pub fn parse_component(data: Value) -> Option { + let a = data.as_array()?; + if a.len() != 2 { + return None + } + let typename = a[0].as_str()?; + let params: HashMap<&str, &Value> = a[1].as_object()?.into_iter().map(|(key, val)| (key.as_str(), val)).collect(); + Self::load_component(typename, params) + } + + pub fn load_component(typename: &str, mut parameters: HashMap<&str, &Value>) -> Option { + match typename { + "Visible" => Some(CompWrapper::Visible(Visible{ + sprite: parameters.remove("sprite")?.as_str()?.to_string(), + height: parameters.remove("height")?.as_f64()? + })), + "Blocking" => Some(CompWrapper::Blocking(Blocking)), + "Player" => Some(CompWrapper::Player(Played::new( + parameters.remove("name")?.as_str()?.to_string() + ))), + _ => None + } + } +} diff --git a/src/load.rs b/src/load.rs new file mode 100644 index 0000000..186ea7e --- /dev/null +++ b/src/load.rs @@ -0,0 +1,69 @@ + +use std::collections::HashMap; +use serde_json::Value; +use super::assemblage::Assemblage; +use super::assemblages::{Player, Grass, Wall}; + +pub fn load_assemblages(data: Value) -> Vec> { + parse_assemblages(data).into_iter().filter_map(|x| x).collect() +} + +fn parse_assemblages(data: Value) -> Vec>> { + match data { + Value::String(txt) => vec![from_args(txt, Vec::new(), HashMap::new())], + Value::Array(list) => list.into_iter().map(parse_assemblages).flatten().collect(), + Value::Object(mut obj) => { + if let Some(Value::String(typename)) = obj.remove("type") { + let args = if let Some(Value::Array(a)) = obj.remove("args") {a} else {Vec::new()}; + let kwargs: HashMap = if let Some(Value::Object(o)) = obj.remove("kwargs") { + o.into_iter().collect() + } else {HashMap::new()}; + vec![from_args( + typename, + args, + kwargs + )] + } else {Vec::new()} + }, + _ => Vec::new() + } +} + +macro_rules! dynasm { + ($typ:ident) => {Some({ + let b : Box = Box::new({ + let o = $typ::default(); + o + }); + b + })} +} + +fn from_args(typename: String, args: Vec, kwargs: HashMap) -> Option>{ + let mut obj = match typename.as_str() { + "player" => dynasm!(Player), + "grass" => dynasm!(Grass), + "wall" => dynasm!(Wall), + _ => None + }?; + obj.init_from_json(args, kwargs); + Some(obj) +} + + +#[cfg(test)] +mod tests { + use super::*; + use serde_json::json; + use std::any::Any; + #[test] + fn test_assemblage_from_json() { + let mut walls1 = load_assemblages(json!("wall")); + assert_eq!(walls1.len(), 1); + let wallbox1 = walls1.pop().unwrap(); +// assert_eq!(, vec![Box::new(Wall{})]); +// assert_eq!(load_assemblages(json!("wall", ["test"], {"abc": 123})), Wall{}); + } +} + + diff --git a/src/main.rs b/src/main.rs index 646d2f3..f5d2394 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,9 @@ use std::thread::sleep; use std::time::Duration; use std::path::Path; +use std::collections::HashMap; + +use serde_json::json; mod server; mod gameserver; @@ -16,14 +19,18 @@ mod systems; mod worldmessages; mod pos; mod assemblage; +// mod load; +mod compwrapper; +mod template; use self::gameserver::GameServer; use self::server::unixserver::UnixServer; use self::server::tcpserver::TcpServer; use self::server::Server; use self::assemblages::{Wall, Grass}; -use self::util::ToJson; use self::room::Room; +use self::template::{Template, CompParam}; +use self::util::ToJson; @@ -58,14 +65,23 @@ fn main() { fn gen_room<'a, 'b>(width: i32, height: i32) -> Room<'a, 'b> { let mut room = Room::new((width, height)); - let wall = Wall{}; + let wall = Template{ + arguments: Vec::new(), + components: vec![ + ("Blocking".to_string(), HashMap::new()), + ("Visible".to_string(), hashmap!( + "sprite".to_string() => CompParam::Constant(json!("wall")), + "height".to_string() => CompParam::Constant(json!(1)) + )) + ] + }.instantiate(Vec::new(), HashMap::new()).unwrap(); for x in 0..width { - room.add_obj(&wall, (x, 0)); - room.add_obj(&wall, (x, height - 1)); + room.add_complist(&wall, (x, 0)); + room.add_complist(&wall, (x, height - 1)); } for y in 1..height-1 { - room.add_obj(&wall, (0, y)); - room.add_obj(&wall, (width - 1, y)); + room.add_complist(&wall, (0, y)); + room.add_complist(&wall, (width - 1, y)); } for x in 1..width-1 { for y in 1..height-1 { diff --git a/src/room.rs b/src/room.rs index 5eaee8e..4fcf658 100644 --- a/src/room.rs +++ b/src/room.rs @@ -28,6 +28,7 @@ use super::systems::{ controlinput::ControlInput, view::View }; +use super::compwrapper::CompWrapper; @@ -82,6 +83,14 @@ impl <'a, 'b>Room<'a, 'b> { pub fn add_obj(&mut self, template: &dyn Assemblage, (x, y): (i32, i32)) -> Entity { template.build(self.world.create_entity()).with(Position::new(Pos{x, y})).build() } + + pub fn add_complist(&mut self, template: &Vec, (x, y): (i32, i32)) -> Entity{ + let mut builder = self.world.create_entity(); + for comp in template { + builder = comp.build(builder); + } + builder.with(Position::new(Pos{x, y})).build() + } } diff --git a/src/template.rs b/src/template.rs new file mode 100644 index 0000000..d6f5c81 --- /dev/null +++ b/src/template.rs @@ -0,0 +1,48 @@ + +use std::collections::HashMap; +use serde_json::Value; +use super::compwrapper::CompWrapper; + +pub struct Template { + pub arguments: Vec, + pub components: Vec<(String, HashMap)> +} + +impl Template { + pub fn instantiate(&self, args: Vec, kwargs: HashMap) -> Option>{ + let mut components: Vec = Vec::new(); + for (compname, compparams) in &self.components { + let mut compargs: HashMap<&str, &Value> = HashMap::new(); + for (name, param) in compparams { + match param { + CompParam::Constant(val) => {compargs.insert(name.as_str(), &val); Some(())}, + CompParam::Argument(argname) => { + if let Some(argval) = kwargs.get(argname.as_str()) { + compargs.insert(name.as_str(), argval); + Some(()) + } else if let Some(idx) = self.arguments.iter().position(|x| x == name){ + if idx < args.len() { + compargs.insert(name.as_str(), &args[idx]); + Some(()) + } else { + println!("positional argument out of range"); + None + } + } else { + println!("can't find parameter value, compname: {}, name: {}, argname: {}", compname, name, argname); + None + } + } + }?; + } + components.push(CompWrapper::load_component(compname.as_str(), compargs)?); + } + Some(components) + } +} + + +pub enum CompParam { + Constant(Value), + Argument(String) +} diff --git a/src/util.rs b/src/util.rs index 7f3c7cd..d9ff32e 100644 --- a/src/util.rs +++ b/src/util.rs @@ -11,6 +11,7 @@ pub trait ToJson { fn to_json(&self) -> Value; } + #[macro_export] macro_rules! hashmap { ( $($key:expr => $value:expr ),* ) => {{ -- cgit