diff options
| -rw-r--r-- | content/encyclopediae/default_encyclopedia.json | 28 | ||||
| -rw-r--r-- | src/assemblage.rs | 15 | ||||
| -rw-r--r-- | src/componentparameter.rs | 3 | ||||
| -rw-r--r-- | src/components/mod.rs | 6 | ||||
| -rw-r--r-- | src/componentwrapper.rs | 2 | ||||
| -rw-r--r-- | src/parameter.rs | 10 | ||||
| -rw-r--r-- | src/persistence.rs | 32 | ||||
| -rw-r--r-- | src/template.rs | 2 | ||||
| -rw-r--r-- | src/world.rs | 8 | ||||
| -rw-r--r-- | todo.md | 3 |
10 files changed, 85 insertions, 24 deletions
diff --git a/content/encyclopediae/default_encyclopedia.json b/content/encyclopediae/default_encyclopedia.json index ea1684b..e682fe2 100644 --- a/content/encyclopediae/default_encyclopedia.json +++ b/content/encyclopediae/default_encyclopedia.json @@ -91,7 +91,7 @@ "height": 0.4 }, "player": { - "arguments": [["name", "string", null]], + "arguments": [["name", "string"]], "components": [ ["Visible", { "sprite": ["string", "player"], @@ -106,7 +106,7 @@ ] }, "portal": { - "arguments": [["destination", "string", null], ["dest_pos", "string", ""]], + "arguments": [["destination", "string"], ["dest_pos", "string", ""]], "components": [ ["RoomExit", {"destination": ["arg", "destination"], "dest_pos": ["arg", "dest_pos"]}], "Floor" @@ -160,7 +160,7 @@ ] }, "spawner": { - "arguments": [["template", "template", null], ["amount", "int", 1], ["delay", "int", 0], ["clan", "string", ""], ["initial_spawn", "bool", true]], + "arguments": [["template", "template"], ["amount", "int", 1], ["delay", "int", 0], ["clan", "string", ""], ["initial_spawn", "bool", true]], "components": [ ["Spawner", { "template": ["arg", "template"], @@ -172,7 +172,7 @@ ] }, "letter": { - "arguments": [["char", "string", null]], + "arguments": [["char", "string"]], "components": [["Visible", { "name": ["concat", [["string", "letter_"], ["arg", "char"]]], "sprite": ["concat", [["string", "emptyletter-"], ["arg", "char"]]], @@ -196,15 +196,33 @@ "item": ["build", "plantedradishseed"] }, "plantedradishseed": { + "arguments": [["target_time", "sometime", null]], "sprite": "seed", "height": 0.05, "name": "seed", "components": [ ["Grow", { + "delay": ["int", 100], + "target_time": ["arg", "target_time"], + "into": ["template", "radishseedling"] + }] + ] + }, + "radishseedling": { + "arguments": [["target_time", "sometime", null]], + "sprite": "seedling", + "height": 0.05, + "name": "seedling", + "components": [ + ["Grow", { "delay": ["int", 200], + "target_time": ["arg", "target_time"], "into": ["template", "radishplant"] }] - ] + ], + "extract": { + "target_time": ["Grow", "target_time"] + } }, "radishes": { "sprite": "food", diff --git a/src/assemblage.rs b/src/assemblage.rs index 8e3a349..df60b45 100644 --- a/src/assemblage.rs +++ b/src/assemblage.rs @@ -31,11 +31,16 @@ impl Assemblage { let tup = arg.as_array().ok_or(aerr!("argument is not an array"))?; let key = tup.get(0).ok_or(aerr!("argument has no name"))?.as_str().ok_or(aerr!("argument name is not a string"))?.to_string(); let typ = ParameterType::from_str(tup.get(1).ok_or(aerr!("argument has no type"))?.as_str().ok_or(aerr!("argument type not a string"))?).ok_or(aerr!("failed to parse argument type"))?; - let def = tup.get(2).ok_or("argument has no default")?; - if def.is_null() { + if let Some(def) = tup.get(2){ + arguments.push( + ( + key.clone(), + typ, + Some(Parameter::from_typed_json(typ, def).ok_or(aerr!("invalid argument default"))?) + ) + ); + } else { arguments.push((key.clone(), typ, None)); - } else { - arguments.push((key.clone(), typ, Some(Parameter::from_typed_json(typ, def).ok_or(aerr!("invalid argument default"))?))); } } Ok(arguments) @@ -159,7 +164,7 @@ impl Assemblage { None } }; - let param = value.ok_or(aerr!("argument has no value"))?; + let param = value.ok_or(aerr!(&format!("argument <{:?}> has no value", (idx, (name, typ, def)))))?; if param.paramtype() != *typ { return Err(aerr!("argument has incorrect type")); } diff --git a/src/componentparameter.rs b/src/componentparameter.rs index bcf42e9..068df76 100644 --- a/src/componentparameter.rs +++ b/src/componentparameter.rs @@ -55,7 +55,8 @@ impl ComponentParameter { Some(Parameter::String(string)) } Self::TemplateSelf => Some(Parameter::Template(template.clone())), - Self::TemplateName => Some(Parameter::String(template.name.0.clone())) + Self::TemplateName => Some(Parameter::String(template.name.0.clone())), + } } diff --git a/src/components/mod.rs b/src/components/mod.rs index b43eba1..071b5e0 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -226,4 +226,10 @@ pub struct Grow { pub into: Template } +#[derive(Component, Debug, Clone)] +#[storage(HashMapStorage)] +pub struct CreationTime { + pub time: Timestamp +} + diff --git a/src/componentwrapper.rs b/src/componentwrapper.rs index b1fd64d..345c986 100644 --- a/src/componentwrapper.rs +++ b/src/componentwrapper.rs @@ -181,7 +181,7 @@ components!( Faction (faction: String) {Faction::from_str(faction.as_str())?}; Interactable (action: String) {Interactable::from_str(action.as_str())?}; Loot (loot: LootList); - Grow (delay: Int, into: Template) {Grow{delay, into, target_time: None}}; + Grow (into: Template, delay: Int, target_time: SomeTime); Equipment () {panic!("equipment from parameters not implemented")}; ); diff --git a/src/parameter.rs b/src/parameter.rs index 829c5cf..a56dd23 100644 --- a/src/parameter.rs +++ b/src/parameter.rs @@ -3,7 +3,8 @@ use serde_json::{Value, json}; use crate::{ Template, components::item::ItemAction, - Pos + Pos, + Timestamp }; @@ -75,6 +76,13 @@ parameters!( Some((Template::from_json(item.get(0)?).ok()?, item.get(1)?.as_f64()?)) ).collect::<Option<Vec<(Template, f64)>>>()?) ({json!(v.iter().map(|(t, c)| (t.to_json(), *c)).collect::<Vec<(Value, f64)>>())}); + SomeTime (Option<Timestamp>) sometime, v + ( + serde_json::from_value::<Option<i64>>(v.clone()) + .ok()? + .map(|time| Timestamp(time)) + ) + (json!(v.map(|timestamp| timestamp.0))); ); diff --git a/src/persistence.rs b/src/persistence.rs index 2903ec6..bbf9595 100644 --- a/src/persistence.rs +++ b/src/persistence.rs @@ -3,12 +3,13 @@ use std::path::{PathBuf, Path}; use std::fs; use std::env; use serde_json; -use serde_json::Value; +use serde_json::{Value, json}; use crate::{ PlayerId, RoomId, savestate::SaveState, playerstate::PlayerState, + Timestamp, Result, aerr }; @@ -16,13 +17,12 @@ use crate::{ pub trait PersistentStorage { fn load_room(&self, id: RoomId) -> Result<SaveState>; - fn load_player(&self, id: PlayerId) -> Result<PlayerState>; + fn load_world_meta(&self) -> Result<Timestamp>; fn save_room(&self, id: RoomId, state: SaveState) -> Result<()>; - fn save_player(&self, id: PlayerId, sate: PlayerState) -> Result<()>; - + fn save_world_meta(&self, time: Timestamp) -> Result<()>; } @@ -78,6 +78,20 @@ impl PersistentStorage for FileStorage { PlayerState::from_json(&json) } + fn load_world_meta(&self) -> Result<Timestamp> { + let mut path = self.directory.clone(); + path.push("world.save.json"); + let text = fs::read_to_string(path)?; + let json: Value = serde_json::from_str(&text)?; + Ok( + Timestamp( + json + .get("steps").ok_or(aerr!("world data does not have steps"))? + .as_i64().ok_or(aerr!("timestamp not an int"))? + ) + ) + } + fn save_room(&self, id: RoomId, state: SaveState) -> Result<()> { let mut path = self.directory.clone(); path.push("rooms"); @@ -85,7 +99,6 @@ impl PersistentStorage for FileStorage { let fname = id.to_string() + ".save.json"; path.push(fname); let text = state.to_json().to_string(); - // todo: write to a temp file first write_file_safe(path, text)?; Ok(()) } @@ -97,10 +110,17 @@ impl PersistentStorage for FileStorage { let fname = id.to_string() + ".save.json"; path.push(fname); let text = state.to_json().to_string(); - // todo: write to a temp file first write_file_safe(path, text)?; Ok(()) } + + fn save_world_meta(&self, time: Timestamp) -> Result<()> { + let mut path = self.directory.clone(); + fs::create_dir_all(&path)?; + path.push("world.save.json"); + write_file_safe(path, json!({"steps": time.0}).to_string())?; + Ok(()) + } } fn write_file_safe<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> Result<()> { diff --git a/src/template.rs b/src/template.rs index cf0fee2..496d08e 100644 --- a/src/template.rs +++ b/src/template.rs @@ -42,7 +42,7 @@ impl Template { pub fn from_json(val: &Value) -> Result<Template> { if val.is_string(){ - return Ok(Self::empty(val.as_str().ok_or(aerr!("json string is not a string?"))?)); + return Ok(Self::empty(val.as_str().unwrap())); } let name = EntityType(val.get("type").ok_or(aerr!("template doesn't have 'type'"))?.as_str().ok_or(aerr!("template type not a string"))?.to_string()); let mut args = Vec::new(); diff --git a/src/world.rs b/src/world.rs index 7b02d90..ecdc540 100644 --- a/src/world.rs +++ b/src/world.rs @@ -33,12 +33,12 @@ impl <'a, 'b>World<'a, 'b> { pub fn new(encyclopedia: Encyclopedia, template_loader: WorldLoader, persistence: Box<dyn PersistentStorage>, default_room: RoomId) -> Self { World { template_loader, + time: persistence.load_world_meta().unwrap_or(Timestamp(1000000)), persistence, default_room, encyclopedia: encyclopedia.clone(), players: HashMap::new(), - rooms: hashmap!(purgatory::purgatory_id() => purgatory::create_purgatory(encyclopedia)), - time: Timestamp(1000000) + rooms: hashmap!(purgatory::purgatory_id() => purgatory::create_purgatory(encyclopedia)) } } @@ -164,6 +164,9 @@ impl <'a, 'b>World<'a, 'b> { } } } + if let Err(err) = self.persistence.save_world_meta(self.time) { + println!("{:?}",err); + } } pub fn view(&self) -> HashMap<PlayerId, WorldMessage> { @@ -176,3 +179,4 @@ impl <'a, 'b>World<'a, 'b> { views } } + @@ -3,12 +3,11 @@ - make readme - save time -- save variable arguments (health etc) - timer resource - log world events to player - draw new entities - room unloading -- relative room locations +- relative room locations? - improve error handling - doors |
