summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/assemblage.rs7
-rw-r--r--src/assemblages.rs6
-rw-r--r--src/components.rs7
-rw-r--r--src/compwrapper.rs48
-rw-r--r--src/load.rs69
-rw-r--r--src/main.rs28
-rw-r--r--src/room.rs9
-rw-r--r--src/template.rs48
-rw-r--r--src/util.rs1
9 files changed, 208 insertions, 15 deletions
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<serde_json::Value>, kwargs: std::collections::HashMap<&str, serde_json::Value>) {
+ fn init_from_json(&mut self, mut args: Vec<serde_json::Value>, kwargs: std::collections::HashMap<String, serde_json::Value>) {
$(
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<serde_json::Value>, kwargs: std::collections::HashMap<&str, serde_json::Value>);
+ fn init_from_json(&mut self, args: Vec<serde_json::Value>, kwargs: std::collections::HashMap<String, serde_json::Value>);
}
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<Self, VecStorage<Self>>;
@@ -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<CompWrapper> {
+ 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<CompWrapper> {
+ 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<Box<dyn Assemblage>> {
+ parse_assemblages(data).into_iter().filter_map(|x| x).collect()
+}
+
+fn parse_assemblages(data: Value) -> Vec<Option<Box<dyn Assemblage>>> {
+ 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<String, Value> = 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<dyn Assemblage> = Box::new({
+ let o = $typ::default();
+ o
+ });
+ b
+ })}
+}
+
+fn from_args(typename: String, args: Vec<Value>, kwargs: HashMap<String, Value>) -> Option<Box<dyn Assemblage>>{
+ 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<CompWrapper>, (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<String>,
+ pub components: Vec<(String, HashMap<String, CompParam>)>
+}
+
+impl Template {
+ pub fn instantiate(&self, args: Vec<Value>, kwargs: HashMap<String, Value>) -> Option<Vec<CompWrapper>>{
+ let mut components: Vec<CompWrapper> = 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 ),* ) => {{