diff options
| author | troido <troido@protonmail.com> | 2020-02-14 14:36:32 +0100 |
|---|---|---|
| committer | troido <troido@protonmail.com> | 2020-02-14 14:36:32 +0100 |
| commit | 4a4cdf7d148be0a2a756f323d27c0ee5b7976438 (patch) | |
| tree | 7add0a0d735f93cb1fce6ae4f0c476a0d550a3ee /src | |
| parent | 7821febc8ee4c89ca1825054e0baf39eea3a0380 (diff) | |
extract the state to save
Diffstat (limited to 'src')
| -rw-r--r-- | src/assemblage.rs | 31 | ||||
| -rw-r--r-- | src/components.rs | 5 | ||||
| -rw-r--r-- | src/componentwrapper.rs | 5 | ||||
| -rw-r--r-- | src/encyclopedia.rs | 2 | ||||
| -rw-r--r-- | src/main.rs | 38 | ||||
| -rw-r--r-- | src/parameter.rs | 11 | ||||
| -rw-r--r-- | src/room.rs | 20 | ||||
| -rw-r--r-- | src/roomtemplate.rs | 2 | ||||
| -rw-r--r-- | src/savestate.rs | 40 | ||||
| -rw-r--r-- | src/systems/mod.rs | 1 | ||||
| -rw-r--r-- | src/systems/moving.rs | 8 | ||||
| -rw-r--r-- | src/systems/save.rs | 43 | ||||
| -rw-r--r-- | src/systems/take.rs | 8 | ||||
| -rw-r--r-- | src/systems/view.rs | 8 | ||||
| -rw-r--r-- | src/template.rs | 21 |
15 files changed, 188 insertions, 55 deletions
diff --git a/src/assemblage.rs b/src/assemblage.rs index f84037c..dd84837 100644 --- a/src/assemblage.rs +++ b/src/assemblage.rs @@ -4,7 +4,9 @@ use serde_json::{Value, json}; use super::componentparameter::ComponentParameter; use super::parameter::{Parameter, ParameterType}; use super::componentwrapper::{ComponentWrapper, ComponentType}; +use super::components::Serialise; use crate::hashmap; +use crate::template::Template; type ArgumentDef = (String, ParameterType, Option<Parameter>); @@ -36,16 +38,20 @@ impl Assemblage { fn parse_definition_components(comps: &Value) -> Result<Vec<(ComponentType, HashMap<String, ComponentParameter>)>, &'static str> { let mut components = Vec::new(); for tup in comps.as_array().ok_or("components is not a json array")? { - let comptype = ComponentType::from_str(tup - .get(0).ok_or("index 0 not in component")? - .as_str().ok_or("component name not a string")? - ).ok_or("not a valid componenttype")?; - let mut parameters: HashMap<String, ComponentParameter> = HashMap::new(); - for (key, value) in tup.get(1).ok_or("index 1 not in component")?.as_object().ok_or("component parameters not a json object")? { - let param = ComponentParameter::from_json(value)?; - parameters.insert(key.clone(), param); + if let Some(name) = tup.as_str() { + components.push((ComponentType::from_str(name).ok_or("not a valid componenttype")?, HashMap::new())); + } else { + let comptype = ComponentType::from_str(tup + .get(0).ok_or("index 0 not in component")? + .as_str().ok_or("component name not a string")? + ).ok_or("not a valid componenttype")?; + let mut parameters: HashMap<String, ComponentParameter> = HashMap::new(); + for (key, value) in tup.get(1).ok_or("index 1 not in component")?.as_object().ok_or("component parameters not a json object")? { + let param = ComponentParameter::from_json(value)?; + parameters.insert(key.clone(), param); + } + components.push((comptype, parameters)); } - components.push((comptype, parameters)); } Ok(components) } @@ -109,7 +115,9 @@ impl Assemblage { Ok(arguments) } - pub fn instantiate(&self, args: &[Parameter], kwargs: &HashMap<String, Parameter>) -> Result<Vec<ComponentWrapper>, &'static str>{ + pub fn instantiate(&self, template: &Template) -> Result<Vec<ComponentWrapper>, &'static str>{ + let args = &template.args; + let kwargs = &template.kwargs; let mut components: Vec<ComponentWrapper> = Vec::new(); let arguments = self.prepare_arguments(args, kwargs)?; for (comptype, compparams) in &self.components { @@ -119,6 +127,9 @@ impl Assemblage { } components.push(ComponentWrapper::load_component(*comptype, compargs).ok_or("failed to load component")?); } + if template.save { + components.push(ComponentWrapper::Serialise(Serialise{template: template.clone()})); + } Ok(components) } } diff --git a/src/components.rs b/src/components.rs index 185459a..1f5630d 100644 --- a/src/components.rs +++ b/src/components.rs @@ -88,3 +88,8 @@ pub struct Health { pub maxhealth: i64 } +#[derive(Component, Debug, Clone)] +pub struct Serialise { + pub template: Template +} + diff --git a/src/componentwrapper.rs b/src/componentwrapper.rs index cf16213..6e11a0b 100644 --- a/src/componentwrapper.rs +++ b/src/componentwrapper.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use specs::{Builder, world::LazyBuilder}; -use crate::components::{Visible, Blocking, Player, Floor, Item, Inventory, Health}; +use crate::components::{Visible, Blocking, Player, Floor, Item, Inventory, Health, Serialise}; use crate::parameter::{Parameter, ParameterType}; @@ -94,7 +94,8 @@ components!( Player (name: String) {Player::new(name)}; Item (ent: Template, name: String) {Item{ent, name}}; Inventory (capacity: Int) {Inventory{items: Vec::new(), capacity: capacity as usize}}; - Health (health: Int, maxhealth: Int) {Health{health, maxhealth}} + Health (health: Int, maxhealth: Int) {Health{health, maxhealth}}; + Serialise (template: Template) {Serialise{template}} ); diff --git a/src/encyclopedia.rs b/src/encyclopedia.rs index 5cdf90c..920f15e 100644 --- a/src/encyclopedia.rs +++ b/src/encyclopedia.rs @@ -22,7 +22,7 @@ impl Encyclopedia { pub fn construct(&self, template: &Template) -> Result<Vec<ComponentWrapper>, &'static str> { let assemblage = self.items.get(&template.name).ok_or("unknown assemblage name")?; - assemblage.instantiate(&template.args, &template.kwargs) + assemblage.instantiate(template) } } diff --git a/src/main.rs b/src/main.rs index 4afcd0a..00f41e4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,6 +23,7 @@ mod componentparameter; mod encyclopedia; mod template; mod roomtemplate; +mod savestate; pub use self::pos::Pos; use self::gameserver::GameServer; @@ -55,15 +56,22 @@ fn main() { println!("asciifarm started"); + + let mut count = 0; loop { let actions = gameserver.update(); room.set_input(actions); room.update(); + if count % 20 == 0 { + println!("{}", room.save().to_json()); + } let messages = room.view(); for (player, message) in messages { let _ = gameserver.send(&player, message.to_json()); } + + count += 1; sleep(Duration::from_millis(100)); } } @@ -122,30 +130,22 @@ fn gen_room<'a, 'b>() -> Room<'a, 'b> { fn default_assemblages() -> Encyclopedia { Encyclopedia::from_json(json!({ "wall": { - "components": [ - ["Blocking", {}] - ], + "components": ["Blocking"], "sprite": "wall", "height": 2 }, "rock": { - "components": [ - ["Blocking", {}] - ], + "components": ["Blocking"], "sprite": "rock", "height": 10 }, "tree": { - "components": [ - ["Blocking", {}] - ], + "components": ["Blocking"], "sprite": "tree", "height": 3 }, "fence": { - "components": [ - ["Blocking", {}] - ], + "components": ["Blocking"], "sprite": "fence", "height": 1 }, @@ -163,7 +163,7 @@ fn default_assemblages() -> Encyclopedia { ]], "height": ["float", 0.1] }], - ["Floor", {}] + "Floor" ] }, "greengrass": { @@ -176,26 +176,22 @@ fn default_assemblages() -> Encyclopedia { ]], "height": ["float", 0.1] }], - ["Floor", {}] + "Floor" ] }, "ground": { - "components": [ - ["Floor", {}] - ], + "components": ["Floor"], "sprite": "ground", "height": 0.1 }, "floor": { - "components": [ - ["Floor", {}] - ], + "components": ["Floor"], "sprite": "floor", "height": 0.1 }, "bridge": { "components": [ - ["Floor", {}] + "Floor" ], "sprite": "bridge", "height": 0.1 diff --git a/src/parameter.rs b/src/parameter.rs index 56f1cbf..cca0681 100644 --- a/src/parameter.rs +++ b/src/parameter.rs @@ -1,5 +1,5 @@ -use serde_json::Value; +use serde_json::{Value, json}; use crate::template::Template; #[derive(Debug, PartialEq, Clone)] @@ -52,6 +52,15 @@ impl Parameter { }; Self::from_typed_json(typ, val) } + + pub fn to_json(&self) -> Value { + match self { + Self::String(s) => json!(s), + Self::Int(i) => json!(i), + Self::Float(f) => json!(f), + Self::Template(t) => t.to_json() + } + } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] diff --git a/src/room.rs b/src/room.rs index 9aad22d..dbcfe0d 100644 --- a/src/room.rs +++ b/src/room.rs @@ -5,7 +5,8 @@ use specs::{ World, WorldExt, DispatcherBuilder, - Dispatcher + Dispatcher, + Join }; use super::controls::Action; @@ -27,8 +28,10 @@ use super::systems::{ create::Create, take::Take }; +use crate::components::{Position, Serialise}; use crate::encyclopedia::Encyclopedia; use crate::roomtemplate::RoomTemplate; +use crate::savestate::SaveState; @@ -45,6 +48,7 @@ impl <'a, 'b>Room<'a, 'b> { templates: Vec::new(), encyclopedia }); + world.register::<Serialise>(); let mut dispatcher = DispatcherBuilder::new() .with(RegisterNew::default(), "registernew", &[]) @@ -78,7 +82,9 @@ impl <'a, 'b>Room<'a, 'b> { let y = (idx as i64) / width; for template in templates { - self.world.fetch_mut::<NewEntities>().templates.push((Pos{x, y}, template.clone())); + let mut obj = template.clone(); + obj.save = false; + self.world.fetch_mut::<NewEntities>().templates.push((Pos{x, y}, obj)); } } } @@ -96,6 +102,16 @@ impl <'a, 'b>Room<'a, 'b> { self.world.fetch_mut::<Input>().actions = actions; } + pub fn save(&self) -> SaveState { + let positions = self.world.read_component::<Position>(); + let serialisers = self.world.write_component::<Serialise>(); + let mut state = SaveState::new(); + for (pos, serialiser) in (&positions, &serialisers).join() { + state.changes.entry(pos.pos).or_insert(Vec::new()).push(serialiser.template.clone()); + } + state + } + } diff --git a/src/roomtemplate.rs b/src/roomtemplate.rs index e77fbca..cb8ae6a 100644 --- a/src/roomtemplate.rs +++ b/src/roomtemplate.rs @@ -11,7 +11,7 @@ pub struct RoomTemplate { } impl RoomTemplate { - + pub fn from_json(jsonroom: &Value) -> Result<RoomTemplate, &'static str>{ let size = ( jsonroom.get("width").ok_or("no with")?.as_i64().ok_or("with not a number")?, diff --git a/src/savestate.rs b/src/savestate.rs new file mode 100644 index 0000000..8afbbf1 --- /dev/null +++ b/src/savestate.rs @@ -0,0 +1,40 @@ + +use std::collections::HashMap; +use serde_json::{json, Value}; +use crate::Pos; +use crate::template::Template; + +pub struct SaveState { + pub changes: HashMap<Pos, Vec<Template>> +} + +impl SaveState { + + pub fn new() -> Self { + Self { + changes: HashMap::new() + } + } + + pub fn to_json(&self) -> Value { + json!({ + "changes": self.changes.iter().map( + |(pos, templates)| + (pos, templates.iter().map(|t| t.to_json()).collect()) + ).collect::<Vec<(&Pos, Vec<Value>)>>() + }) + } + + pub fn from_json(val: &Value) -> Option<Self> { + let mut changes = HashMap::new(); + for v in val.get("changes")?.as_array()? { + let pos = Pos::from_json(v.get(0)?)?; + let mut templates = Vec::new(); + for t in v.get(1)?.as_array()? { + templates.push(Template::from_json(t)?); + } + changes.insert(pos, templates); + } + Some(Self {changes}) + } +} diff --git a/src/systems/mod.rs b/src/systems/mod.rs index 6989e95..7e75706 100644 --- a/src/systems/mod.rs +++ b/src/systems/mod.rs @@ -6,4 +6,3 @@ pub mod view; pub mod remove; pub mod create; pub mod take; - diff --git a/src/systems/moving.rs b/src/systems/moving.rs index 3e7803d..f5c1b4a 100644 --- a/src/systems/moving.rs +++ b/src/systems/moving.rs @@ -11,9 +11,9 @@ use specs::{ Write }; -use super::super::pos::Pos; +use crate::pos::Pos; -use super::super::components::{ +use crate::components::{ Controller, Blocking, Position, @@ -21,11 +21,11 @@ use super::super::components::{ Moved }; -use super::super::controls::{ +use crate::controls::{ Control }; -use super::super::resources::{ +use crate::resources::{ Size, Ground }; diff --git a/src/systems/save.rs b/src/systems/save.rs new file mode 100644 index 0000000..924533a --- /dev/null +++ b/src/systems/save.rs @@ -0,0 +1,43 @@ + +use std::collections::HashMap; + +use specs::{ + Entities, + ReadStorage, + System, + Join, + Read +}; + +use crate::pos::Pos; + +use crate::components::{ + Position, + Serialise +}; + +use crate::savestate::SaveState; + +const INTERVAL: i32 = 20; + +pub struct Save(pub i32); +impl <'a> System<'a> for Save { + type SystemData = ( + Entities<'a>, + ReadStorage<'a, Position>, + ReadStorage<'a, Serialise>, + ); + + fn run(&mut self, (entities, positions, serialisers): Self::SystemData) { + self.0 -= 1; + if self.0 > 0 { + return + } + self.0 = INTERVAL; + let mut state = SaveState::new(); + for (pos, serialiser) in (&positions, &serialisers).join() { + state.changes.entry(pos.pos).or_insert(Vec::new()).push(serialiser.template.clone()); + } + println!("save {}", state.to_json().to_string()); + } +} diff --git a/src/systems/take.rs b/src/systems/take.rs index f0e3990..affa3d1 100644 --- a/src/systems/take.rs +++ b/src/systems/take.rs @@ -10,9 +10,7 @@ use specs::{ Write }; -use super::super::pos::Pos; - -use super::super::components::{ +use crate::components::{ Controller, Position, Removed, @@ -20,8 +18,8 @@ use super::super::components::{ Item }; -use super::super::controls::{Control}; -use super::super::resources::{Ground, NewEntities}; +use crate::controls::{Control}; +use crate::resources::{Ground, NewEntities}; diff --git a/src/systems/view.rs b/src/systems/view.rs index 57e2b28..2bc971e 100644 --- a/src/systems/view.rs +++ b/src/systems/view.rs @@ -11,10 +11,10 @@ use specs::{ Entity }; -use super::super::pos::Pos; -use super::super::components::{Visible, Player, Position, Inventory, New, Moved, Removed, Health}; -use super::super::resources::{Size, Output, Ground}; -use super::super::worldmessages::{WorldMessage, WorldUpdate, FieldMessage}; +use crate::pos::Pos; +use crate::components::{Visible, Player, Position, Inventory, New, Moved, Removed, Health}; +use crate::resources::{Size, Output, Ground}; +use crate::worldmessages::{WorldMessage, WorldUpdate, FieldMessage}; #[derive(Default)] diff --git a/src/template.rs b/src/template.rs index 0f846fd..5347e51 100644 --- a/src/template.rs +++ b/src/template.rs @@ -8,7 +8,8 @@ use crate::parameter::Parameter; pub struct Template { pub name: String, pub args: Vec<Parameter>, - pub kwargs: HashMap<String, Parameter> + pub kwargs: HashMap<String, Parameter>, + pub save: bool } @@ -18,7 +19,8 @@ impl Template { Self { name: name.to_string(), args: Vec::new(), - kwargs + kwargs, + save: true } } @@ -39,6 +41,19 @@ impl Template { for (key, arg) in val.get("kwargs").unwrap_or(&json!({})).as_object()? { kwargs.insert(key.to_string(), Parameter::guess_from_json(arg)?); } - Some(Template {name, args, kwargs}) + Some(Template {name, args, kwargs, save: true}) + } + + pub fn to_json(&self) -> Value { + if self.args.is_empty() && self.kwargs.is_empty() { + return json!(self.name); + } + let jsonargs: Vec<Value> = self.args.iter().map(|a| a.to_json()).collect(); + let jsonkwargs: HashMap<&String, Value> = self.kwargs.iter().map(|(k, a)| (k, a.to_json())).collect(); + json!({ + "type": self.name, + "args": jsonargs, + "kwargs": jsonkwargs + }) } } |
