diff options
| -rw-r--r-- | content/encyclopediae/base.json | 14 | ||||
| -rw-r--r-- | content/encyclopediae/crops.json | 76 | ||||
| -rw-r--r-- | content/encyclopediae/default_encyclopedia.json | 70 | ||||
| -rw-r--r-- | content/encyclopediae/npcs.json | 64 | ||||
| -rw-r--r-- | src/assemblage.rs | 63 | ||||
| -rw-r--r-- | src/errors.rs | 20 | ||||
| -rw-r--r-- | src/fromtoparameter.rs | 11 | ||||
| -rw-r--r-- | src/item.rs | 11 | ||||
| -rw-r--r-- | src/main.rs | 2 | ||||
| -rw-r--r-- | src/parameter.rs | 114 | ||||
| -rw-r--r-- | src/parameterexpression.rs | 179 | ||||
| -rw-r--r-- | src/template.rs | 15 |
12 files changed, 244 insertions, 395 deletions
diff --git a/content/encyclopediae/base.json b/content/encyclopediae/base.json index e6806b5..1964579 100644 --- a/content/encyclopediae/base.json +++ b/content/encyclopediae/base.json @@ -23,7 +23,7 @@ "grass": { "components": [ ["Visible", { - "sprite": ["random", [ + "sprite": {"$random": [ "grass1", "grass2", "grass3", @@ -31,7 +31,7 @@ "grass2", "grass3", "ground" - ]], + ]}, "height": 0.1, "name": "grass" }] @@ -41,11 +41,11 @@ "greengrass": { "components": [ ["Visible", { - "sprite": ["random", [ + "sprite": {"$random": [ "grass1", "grass2", "grass3" - ]], + ]}, "height": 0.1, "name": "grass" }] @@ -76,14 +76,14 @@ "img": { "arguments": [["sprite", "string", ""], ["height", "float", 1.0]], "components": [ - ["Visible", {"name": ["arg", "sprite"], "sprite": ["arg", "sprite"], "height": ["arg", "height"]}] + ["Visible", {"name": {"$arg": "sprite"}, "sprite": {"$arg": "sprite"}, "height": {"$arg": "height"}}] ] }, "letter": { "arguments": [["char", "string"]], "components": [["Visible", { - "name": ["concat", ["letter_", ["arg", "char"]]], - "sprite": ["concat", ["emptyletter-", ["arg", "char"]]], + "name": {"$concat": ["letter_", {"$arg": "char"}]}, + "sprite": {"$concat": ["emptyletter-", {"$arg": "char"}]}, "height": 1.0 }]] } diff --git a/content/encyclopediae/crops.json b/content/encyclopediae/crops.json index a8c9047..0c16073 100644 --- a/content/encyclopediae/crops.json +++ b/content/encyclopediae/crops.json @@ -6,12 +6,12 @@ "height": 0.5, "components": [ ["Interactable", {"typ": "trigger", "arg": "die"}], - ["Loot", {"loot": ["list", [ - ["list", [{"type": "radishseed"}, 0.92]], - ["list", [{"type": "radishseed"}, 0.20]], - ["list", [{"type": "radish"}, 0.8]], - ["list", [{"type": "radish"}, 0.4]] - ]]}] + ["Loot", {"loot": [ + [{"$template": "radishseed"}, 0.92], + [{"$template": "radishseed"}, 0.20], + [{"$template": "radish"}, 0.8], + [{"$template": "radish"}, 0.4] + ]}] ], "flags": ["Occupied"] }, @@ -24,10 +24,10 @@ ["Timer", { "delay": 600, "spread": 0.5, - "target_time": ["arg", "target_time"], + "target_time": {"$arg": "target_time"}, "trigger": "change" }], - ["Build", {"obj": ["template", "radishseedling"]}] + ["Build", {"obj": {"$template": "radishseedling"}}] ], "extract": { "target_time": ["Timer", "target_time"] @@ -43,10 +43,10 @@ ["Timer", { "delay": 600, "spread": 0.5, - "target_time": ["arg", "target_time"], + "target_time": {"$arg": "target_time"}, "trigger": "change" }], - ["Build", {"obj": ["template", "youngradishplant"]}] + ["Build", {"obj": {"$template": "youngradishplant"}}] ], "extract": { "target_time": ["Timer", "target_time"] @@ -62,10 +62,10 @@ ["Timer", { "delay": 600, "spread": 0.5, - "target_time": ["arg", "target_time"], + "target_time": {"$arg": "target_time"}, "trigger": "change" }], - ["Build", {"obj": ["template", "radishplant"]}] + ["Build", {"obj": {"$template": "radishplant"}}] ], "extract": { "target_time": ["Timer", "target_time"] @@ -79,12 +79,12 @@ "name": "plantedseed", "components": [ ["Timer", { - "delay": ["arg", "delay"], + "delay": {"$arg": "delay"}, "spread": 0.5, - "target_time": ["arg", "target_time"], + "target_time": {"$arg": "target_time"}, "trigger": "change" }], - ["Build", {"obj": ["arg", "next"]}] + ["Build", {"obj": {"$arg": "next"}}] ], "extract": { "target_time": ["Timer", "target_time"] @@ -98,12 +98,12 @@ "name": "seedling", "components": [ ["Timer", { - "delay": ["arg", "delay"], + "delay": {"$arg": "delay"}, "spread": 0.5, - "target_time": ["arg", "target_time"], + "target_time": {"$arg": "target_time"}, "trigger": "change" }], - ["Build", {"obj": ["arg", "next"]}] + ["Build", {"obj": {"$arg": "next"}}] ], "extract": { "target_time": ["Timer", "target_time"] @@ -114,14 +114,14 @@ "arguments": [["target_time", "int", -1], ["next", "template"], ["crop", "string"], ["delay", "int"]], "components": [ ["Timer", { - "delay": ["arg", "delay"], + "delay": {"$arg": "delay"}, "spread": 0.5, - "target_time": ["arg", "target_time"], + "target_time": {"$arg": "target_time"}, "trigger": "change" }], - ["Build", {"obj": ["arg", "next"]}], + ["Build", {"obj": {"$arg": "next"}}], ["Visible", { - "name": ["concat", [["string", "young"], ["arg", "crop"], ["string", "plant"]]], + "name": {"$concat": ["young", {"$arg": "crop"}, "plant"]}, "sprite": "youngplant", "height": 0.8 }] @@ -137,10 +137,10 @@ "height": 1.0, "components": [ ["Interactable", {"typ": "trigger", "arg": "die"}], - ["Loot", {"loot": ["list", [ - ["list", [{"type": "carrotseed"}, 1.0]], - ["list", [{"type": "carrot"}, 1.0]] - ]]}] + ["Loot", {"loot": [ + [{"$template": "carrotseed"}, 1.0], + [{"$template": "carrot"}, 1.0] + ]}] ], "flags": ["Occupied"] }, @@ -150,12 +150,12 @@ "height": 1.0, "components": [ ["Interactable", {"typ": "trigger", "arg": "die"}], - ["Loot", {"loot": ["list", [ - ["list", [{"type": "cottonseed"}, 0.92]], - ["list", [{"type": "cottonseed"}, 0.20]], - ["list", [{"type": "cotton"}, 0.8]], - ["list", [{"type": "cotton"}, 0.4]] - ]]}] + ["Loot", {"loot": [ + [{"$template": "cottonseed"}, 0.92], + [{"$template": "cottonseed"}, 0.20], + [{"$template": "cotton"}, 0.8], + [{"$template": "cotton"}, 0.4] + ]}] ], "flags": ["Occupied"] }, @@ -176,11 +176,11 @@ "cottoncloth": {"sprite": "cottoncloth"} }, "templates":{ - "plantedcarrotseed": ["plantedseed", {"delay": 1800, "next": {"type": "carrotseedling"}}], - "carrotseedling": ["seedling", {"delay": 3000, "next": {"type": "youngcarrotplant"}}], - "youngcarrotplant": ["youngplant", {"crop": "carrot", "delay": 6000, "next": {"type": "carrotplant"}}], - "plantedcottonseed": ["plantedseed", {"delay": 6000, "next": {"type": "cottonseedling"}}], - "cottonseedling": ["seedling", {"delay": 18000, "next": {"type": "youngcottonplant"}}], - "youngcottonplant": ["youngplant", {"crop": "cotton", "delay": 36000, "next": {"type": "cottonplant"}}] + "plantedcarrotseed": ["plantedseed", {"delay": 1800, "next": {":template": "carrotseedling"}}], + "carrotseedling": ["seedling", {"delay": 3000, "next": {":template": "youngcarrotplant"}}], + "youngcarrotplant": ["youngplant", {"crop": "carrot", "delay": 6000, "next": {":template": "carrotplant"}}], + "plantedcottonseed": ["plantedseed", {"delay": 6000, "next": {":template": "cottonseedling"}}], + "cottonseedling": ["seedling", {"delay": 18000, "next": {":template": "youngcottonplant"}}], + "youngcottonplant": ["youngplant", {"crop": "cotton", "delay": 36000, "next": {":template": "cottonplant"}}] } } diff --git a/content/encyclopediae/default_encyclopedia.json b/content/encyclopediae/default_encyclopedia.json index 25e3d32..cf58771 100644 --- a/content/encyclopediae/default_encyclopedia.json +++ b/content/encyclopediae/default_encyclopedia.json @@ -3,25 +3,25 @@ "portal": { "arguments": [["destination", "string"], ["destpos", "string", ""]], "components": [ - ["RoomExit", {"destination": ["arg", "destination"], "dest_pos": ["arg", "destpos"]}] + ["RoomExit", {"destination": {"$arg": "destination"}, "dest_pos": {"$arg": "destpos"}}] ], "flags": ["Floor"] }, "_homeportal": { - "arguments": [["allowed", "list", ["list", []]]], + "arguments": [["allowed", "list", []]], "extract": {"allowed": ["Whitelist", "allowed"]}, "components": [ ["RoomExit", {"destination": "_home+{player}", "dest_pos": ""}], ["Interactable", {"typ": "visit", "arg": "_home+{player}"}], - ["Whitelist", {"allowed": ["arg", "allowed"]}] + ["Whitelist", {"allowed": {"$arg": "allowed"}}] ], "flags": ["Floor"] }, "builtwall": { "arguments": [["health", "int", 100]], "components": [ - ["Health", {"health": ["arg", "health"], "maxhealth": 100}], - ["Loot", {"loot": ["list", [["list", [{"type": "stone"}, 1.0]]]]}] + ["Health", {"health": {"$arg": "health"}, "maxhealth": 100}], + ["Loot", {"loot": [[{"$template": "stone"}, 1.0]]}] ], "sprite": "builtwall", "height": 2, @@ -38,7 +38,7 @@ "sprite": "dummy", "height": 1, "components": [ - ["Health", {"health": ["arg", "health"], "maxhealth": 20}] + ["Health", {"health": {"$arg": "health"}, "maxhealth": 20}] ] }, "wound": { @@ -51,16 +51,16 @@ "arguments": [["template", "template"], ["amount", "int", 1], ["delay", "int", 0], ["clan", "string", ""], ["initial_spawn", "bool", true], ["radius", "int", 0]], "components": [ ["Timer", { - "delay": ["arg", "delay"], + "delay": {"$arg": "delay"}, "spread": 0.1, "trigger": "spawn", - "target_time": ["if", [["arg", "initial_spawn"], 0, -1]] + "target_time": {"$if": [{"$arg": "initial_spawn"}, 0, -1]} }], ["Spawner", { - "template": ["arg", "template"], - "amount": ["arg", "amount"], - "clan": ["arg", "clan"], - "radius": ["arg", "radius"] + "template": {"$arg": "template"}, + "amount": {"$arg": "amount"}, + "clan": {"$arg": "clan"}, + "radius": {"$arg": "radius"} }] ] }, @@ -68,9 +68,9 @@ "arguments": [["ent", "template"], ["clan", "string", ""]], "components": [ ["Spawner", { - "template": ["arg", "ent"], + "template": {"$arg": "ent"}, "amount": 1, - "clan": ["arg", "clan"], + "clan": {"$arg": "clan"}, "radius": 0 }], ["Timer", { @@ -87,7 +87,7 @@ "flags": ["Blocking"], "components": [ ["Interactable", {"typ": "trigger", "arg": "change"}], - ["Build", {"obj": {"type": "opendoor", "save": false}}] + ["Build", {"obj": {"$template": "opendoor", "__save__": false}}] ] }, "opendoor": { @@ -96,7 +96,7 @@ "flags": ["Occupied"], "components": [ ["Interactable", {"typ": "trigger", "arg": "change"}], - ["Build", {"obj": {"type": "closeddoor", "save": false}}] + ["Build", {"obj": {"$template": "closeddoor", "__save__": false}}] ] }, "sign": { @@ -113,20 +113,15 @@ "components": [ ["Interactable", {"typ": "mine", "arg": "mining"}], ["Minable", {"total": 20, "trigger": "loot"}], - ["Loot", {"loot": ["list", [ - ["list", [{"type": "stone"}, 1.0]] - ]]}] + ["Loot", {"loot": [[{"$template": "stone"}, 1.0]]}] ] }, "spinningwheel": { "sprite": "spinningwheel", "height": 1.0, "components": [ - ["Interactable", {"typ": "exchange", "arg": ["list", [ - "spin ", - ["list", [ - ["list", ["cotton yarn", ["list", ["cotton", "cotton"]], ["list", ["cottonyarn"]]]] - ]] + ["Interactable", {"typ": "exchange", "arg": ["spin ", [ + ["cotton yarn", ["cotton", "cotton"], ["cottonyarn"]] ]]}] ] }, @@ -134,11 +129,8 @@ "sprite": "loom", "height": 1.0, "components": [ - ["Interactable", {"typ": "exchange", "arg": ["list", [ - "weave ", - ["list", [ - ["list", ["cotton cloth", ["list", ["cottonyarn", "cottonyarn", "cottonyarn", "cottonyarn", "cottonyarn"]], ["list", ["cottoncloth"]]]] - ]] + ["Interactable", {"typ": "exchange", "arg": ["weave ", [ + ["cotton cloth", ["cottonyarn", "cottonyarn", "cottonyarn", "cottonyarn", "cottonyarn"], ["cottoncloth"]] ]]}] ] }, @@ -146,11 +138,8 @@ "sprite": "sewingtable", "height": 1.0, "components": [ - ["Interactable", {"typ": "exchange", "arg": ["list", [ - "sew ", - ["list", [ - ["list", ["cape", ["list", ["cottoncloth", "cottoncloth", "cottoncloth", "cottonyarn", "cottonyarn"]], ["list", ["cape"]]]] - ]] + ["Interactable", {"typ": "exchange", "arg": ["sew ", [ + ["cape", ["cottoncloth", "cottoncloth", "cottoncloth", "cottonyarn", "cottonyarn"], ["cape"]] ]]}] ] }, @@ -158,13 +147,10 @@ "sprite": "tub", "height": 1.0, "components": [ - ["Interactable", {"typ": "exchange", "arg": ["list", [ - "dye ", - ["list", [ - ["list", ["red cape", ["list", ["cape", "reddye"]], ["list", ["redcape"]]]], - ["list", ["green cape", ["list", ["cape", "greendye"]], ["list", ["greencape"]]]], - ["list", ["blue cape", ["list", ["cape", "bluedye"]], ["list", ["bluecape"]]]] - ]] + ["Interactable", {"typ": "exchange", "arg": ["dye ", [ + ["red cape", ["cape", "reddye"], ["redcape"]], + ["green cape", ["cape", "greendye"], ["greencape"]], + ["blue cape", ["cape", "bluedye"], ["bluecape"]] ]]}] ] } @@ -239,6 +225,6 @@ } }, "templates": { - "homeportal": ["singleton", {"ent": {"type": "_homeportal"}}] + "homeportal": ["singleton", {"ent": {":template": "_homeportal"}}] } } diff --git a/content/encyclopediae/npcs.json b/content/encyclopediae/npcs.json index 592417c..5cb7a60 100644 --- a/content/encyclopediae/npcs.json +++ b/content/encyclopediae/npcs.json @@ -13,9 +13,9 @@ ["Fighter", {"damage": 2, "cooldown": 6}], ["Movable", {"cooldown": 3}], ["Faction", {"faction": "evil"}], - ["Loot", {"loot": ["list", [ - ["list", [{"type": "radishseed"}, 1.0]] - ]]}] + ["Loot", {"loot": [ + [{"$template": "radishseed"}, 1.0] + ]}] ] }, "goblin": { @@ -31,11 +31,11 @@ ["Fighter", {"damage": 5, "cooldown": 8}], ["Movable", {"cooldown": 4}], ["Faction", {"faction": "evil"}], - ["Loot", {"loot": ["list", [ - ["list", [{"type": "sword"}, 0.05]], - ["list", [{"type": "club"}, 0.1]], - ["list", [{"type": "radish"}, 0.25]] - ]]}] + ["Loot", {"loot": [ + [{"$template": "sword"}, 0.05], + [{"$template": "club"}, 0.1], + [{"$template": "radish"}, 0.25] + ]}] ] }, "troll": { @@ -51,13 +51,13 @@ ["Fighter", {"damage": 15, "cooldown": 10}], ["Movable", {"cooldown": 5}], ["Faction", {"faction": "evil"}], - ["Loot", {"loot": ["list", [ - ["list", [{"type": "stone"}, 1.0]], - ["list", [{"type": "stone"}, 0.3]], - ["list", [{"type": "pebble"}, 0.5]], - ["list", [{"type": "pebble"}, 0.5]], - ["list", [{"type": "pebble"}, 0.5]] - ]]}] + ["Loot", {"loot": [ + [{"$template": "stone"}, 1.0], + [{"$template": "stone"}, 0.3], + [{"$template": "pebble"}, 0.5], + [{"$template": "pebble"}, 0.5], + [{"$template": "pebble"}, 0.5] + ]}] ] }, @@ -87,14 +87,11 @@ "height": 1.5, "name": "crop trader", "components": [ - ["Interactable", {"typ": "exchange", "arg": ["list", [ - "buy ", - ["list", [ - ["list", ["pebble", ["list", ["radish", "radish"]], ["list", ["pebble"]]]], - ["list", ["radishseed", ["list", ["radish"]], ["list", ["radishseed", "radishseed"]]]], - ["list", ["carrotseed", ["list", ["radish"]], ["list", ["carrotseed"]]]], - ["list", ["cottonseed", ["list", ["stone"]], ["list", ["cottonseed"]]]] - ]] + ["Interactable", {"typ": "exchange", "arg": ["buy ", [ + ["pebble", ["radish", "radish"], ["pebble"]], + ["radishseed", ["radish"], ["radishseed", "radishseed"]], + ["carrotseed", ["radish"], ["carrotseed"]], + ["cottonseed", ["stone"], ["cottonseed"]] ]]}], ["MonsterAI", { "view_distance": 1, @@ -109,13 +106,10 @@ "height": 1.5, "name": "dye trader", "components": [ - ["Interactable", {"typ": "exchange", "arg": ["list", [ - "buy ", - ["list", [ - ["list", ["red dye", ["list", ["club", "club"]], ["list", ["reddye"]]]], - ["list", ["green dye", ["list", ["stone", "stone", "stone", "stone", "stone"]], ["list", ["greendye"]]]], - ["list", ["blue dye", ["list", ["sword"]], ["list", ["bluedye"]]]] - ]] + ["Interactable", {"typ": "exchange", "arg": ["buy ", [ + ["red dye", ["club", "club"], ["reddye"]], + ["green dye", ["stone", "stone", "stone", "stone", "stone"], ["greendye"]], + ["blue dye", ["sword"], ["bluedye"]] ]]}], ["MonsterAI", { "view_distance": 1, @@ -130,11 +124,8 @@ "height": 1.5, "name": "toolsmith", "components": [ - ["Interactable", {"typ": "exchange", "arg": ["list", [ - "buy ", - ["list", [ - ["list", ["pickaxe", ["list", ["carrot", "carrot", "carrot", "carrot", "carrot", "carrot", "carrot", "carrot", "carrot", "carrot"]], ["list", ["pickaxe"]]]] - ]] + ["Interactable", {"typ": "exchange", "arg": ["buy ", [ + ["pickaxe", ["carrot", "carrot", "carrot", "carrot", "carrot", "carrot", "carrot", "carrot", "carrot", "carrot"], ["pickaxe"]] ]]}], ["MonsterAI", { "view_distance": 1, @@ -154,7 +145,8 @@ "move_chance": 0.01, "homesickness": 0.3 }], - ["Movable", {"cooldown": 3}] + ["Movable", {"cooldown": 3}], + ["Interactable", {"typ": "say", "arg": "Hello"}] ] } } diff --git a/src/assemblage.rs b/src/assemblage.rs index e4554eb..9911c77 100644 --- a/src/assemblage.rs +++ b/src/assemblage.rs @@ -181,9 +181,9 @@ mod tests { ], "components": [ ["Visible", { - "sprite": ["arg", "sprite"], - "height": ["float", 0.1], - "name": ["string", "grass"] + "sprite": {"$arg": "sprite"}, + "height": 0.1, + "name": "grass" }] ] })).unwrap(); @@ -210,9 +210,9 @@ mod tests { ], "components": [ ["visible", { // no capital so invalid - "sprite": ["A", "sprite"], - "height": ["float", 0.1], - "name": ["string", "grass"] + "sprite": {"$arg": "sprite"}, + "height": 0.1, + "name": "grass" }] ] })).unwrap_err(); @@ -229,48 +229,15 @@ mod tests { ], "components": [ ["Visible", { - "sprite": ["A", "sprite"], - "height": ["string", "0.1"], - "name": ["string", "grass"] + "sprite": {"$arg": "sprite"}, + "height": "0.1", + "name": "grass" }] ] })).unwrap_err(); // assert_eq!(result, "parameter type incorrect"); } -// #[test] - fn unknown_argument_name(){ - Assemblage::deserialize(&json!({ - "arguments": [ - ["sprite", "string", "grass1"] - ], - "components": [ - ["Visible", { - "sprite": ["A", "sprits"], - "height": ["float", 0.1], - "name": ["string", "grass"] - }] - ] - })).unwrap_err(); -// assert_eq!(result, "unknown argument name"); - } - -// #[test] - fn wrong_argument_type(){ - Assemblage::deserialize(&json!({ - "arguments": [ - ["sprite", "int", 1] - ], - "components": [ - ["Visible", { - "sprite": ["A", "sprite"], - "height": ["float", 0.1], - "name": ["string", "grass"] - }] - ] - })).unwrap_err(); -// assert_eq!(result, "parameter type incorrect"); - } @@ -282,9 +249,9 @@ mod tests { ], "components": [ ["Visible", { - "sprite": ["A", "sprite"], - "height": ["float", 0.1], - "name": ["string", "grass"] + "sprite": {"$arg": "sprite"}, + "height": 0.1, + "name": "grass" }] ] })).unwrap_err(); @@ -300,9 +267,9 @@ mod tests { ], "components": [ ["Visible", { - "sprite": ["arg", "sprite"], - "height": ["float", 0.1], - "name": ["arg", "sprite"] + "sprite": {"$arg": "sprite"}, + "height": 0.1, + "name": {"$arg": "sprite"} }] ] })).unwrap(); diff --git a/src/errors.rs b/src/errors.rs index 294159c..c58f2ff 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -25,23 +25,3 @@ macro_rules! aerr { } - -#[derive(Debug)] -pub struct ParseError { - pub text: String -} -impl Error for ParseError { - fn source(&self) -> Option<&(dyn Error + 'static)> { - None - } -} -impl Display for ParseError { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "Error: {}", self.text) - } -} -#[macro_export] -macro_rules! perr { - ($($description:tt)*) => {crate::errors::ParseError{text: format!($($description)*)}} -} -pub type PResult<T> = std::result::Result<T, ParseError>; diff --git a/src/fromtoparameter.rs b/src/fromtoparameter.rs index 8d169d0..13483d7 100644 --- a/src/fromtoparameter.rs +++ b/src/fromtoparameter.rs @@ -76,7 +76,6 @@ tofrom!(i64: Int); tofrom!(f64: Float); tofrom!(bool:Bool); tofrom!(String: String); -tofrom!(Pos: Pos); tofrom!(Template: Template); tofrom!(PlayerId(String)); @@ -177,3 +176,13 @@ where Parameter::List(vec![self.0.to_parameter(), self.1.to_parameter(), self.2.to_parameter()]) } } + +impl FromToParameter for Pos { + fn from_parameter(p: Parameter) -> Option<Self>{ + let (x, y) = <(i64, i64)>::from_parameter(p)?; + Some(Self{x, y}) + } + fn to_parameter(self) -> Parameter { + (self.x, self.y).to_parameter() + } +} diff --git a/src/item.rs b/src/item.rs index 37ee4f2..c8337f9 100644 --- a/src/item.rs +++ b/src/item.rs @@ -1,7 +1,6 @@ use std::collections::HashSet; -use std::str::FromStr; use serde; use serde::{Deserialize, Serialize}; use crate::{ @@ -9,8 +8,7 @@ use crate::{ components::{ Flag, equipment::Equippable - }, - errors::{ParseError} + } }; @@ -18,13 +16,6 @@ use crate::{ #[derive(Debug, Default, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)] pub struct ItemId(pub String); -impl FromStr for ItemId { - type Err = ParseError; - fn from_str(s: &str) -> Result<Self, Self::Err> { - Ok(Self(s.to_string())) - } -} - #[derive(Debug, Clone)] pub struct Item { pub ent: Template, diff --git a/src/main.rs b/src/main.rs index 6cd0f24..2176801 100644 --- a/src/main.rs +++ b/src/main.rs @@ -45,7 +45,7 @@ use self::{ playerid::PlayerId, roomid::RoomId, item::ItemId, - errors::{Result, PResult}, + errors::{Result}, sprite::Sprite, template::Template, encyclopedia::Encyclopedia, diff --git a/src/parameter.rs b/src/parameter.rs index 29d1990..be846a1 100644 --- a/src/parameter.rs +++ b/src/parameter.rs @@ -1,35 +1,22 @@ -use serde_json::{Value, json}; -use serde::{de, Serialize, Deserialize, Serializer, Deserializer}; +use serde::{Serialize, Deserialize}; use strum_macros::{EnumString, Display}; use crate::{ Template, - Pos, - PResult, - perr }; macro_rules! parameters { - ($($name: ident ($typ: ty) $stringname: ident, $v: ident ($fromjson: expr) ($tojson: expr));*;) => { - #[derive(Debug, PartialEq, Clone)] + {$($name: ident $typ: ty);*;} => { + #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] + #[serde(untagged)] pub enum Parameter { $( $name($typ), )* } impl Parameter { - pub fn from_typed_json(typ: ParameterType, val: &Value) -> PResult<Parameter>{ - match typ { - $( - ParameterType::$name => Ok(Self::$name({ - let $v = val; - $fromjson - })), - )* - } - } pub fn paramtype(&self) -> ParameterType { match self { $( @@ -37,13 +24,6 @@ macro_rules! parameters { )* } } - pub fn to_json(&self) -> Value { - match self { - $( - Self::$name($v) => $tojson, - )* - } - } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, EnumString, Display)] @@ -54,36 +34,17 @@ macro_rules! parameters { $name, )* } - impl ParameterType { - pub fn from_str(typename: &str) -> Option<Self>{ - match typename { - $( - stringify!($stringname) => Some(Self::$name), - )* - _ => None - } - } - } } } -parameters!( - String (String) string, v (v.as_str().ok_or(perr!("{:?} not a string", v))?.to_string()) (json!(v)); - Int (i64) int, v (v.as_i64().ok_or(perr!("{:?} not an int", v))?) (json!(v)); - Pos (Pos) pos, v (Pos::deserialize(v).map_err(|e| perr!("{:?} not a pos {}", v, e))?) (json!(v)); - Float (f64) float, v (v.as_f64().ok_or(perr!("{:?} not an float", v))?) (json!(v)); - Template (Template) template, v (Template::deserialize(v).map_err(|e| perr!("template json error {:?}", e))?) (json!(["template", v])); - Bool (bool) bool, v (v.as_bool().ok_or(perr!("{:?} not a bool", v))?) (json!(v)); - List (Vec<Parameter>) list, v - ({ - v - .as_array().ok_or(perr!("{:?} not an array", v))? - .iter() - .map(|item| Parameter::guess_from_json(item)) - .collect::<PResult<Vec<Parameter>>>()? - }) - (json!(["list", v.iter().map(Parameter::to_json).collect::<Vec<Value>>()])); -); +parameters!{ + String String; + Int i64; + Float f64; + Template Template; + Bool bool; + List Vec<Parameter>; +} impl Parameter { @@ -92,58 +53,21 @@ impl Parameter { Self::String(string.to_string()) } - pub fn guess_from_json(val: &Value) -> PResult<Parameter> { - if let Some(arr) = val.as_array() { - if arr.len() == 2 && arr[0].is_string() { - let typestr = arr[0].as_str().unwrap(); - let typ = ParameterType::from_str(typestr).ok_or(perr!("invalid parameter type {}", typestr))?; - return Self::from_typed_json(typ, &arr[1]); - } - } - let typ = - if val.is_string() { - ParameterType::String - } else if val.is_u64() || val.is_i64() { - ParameterType::Int - } else if val.is_f64() { - ParameterType::Float - } else if val.is_boolean(){ - ParameterType::Bool - } else if val.is_object(){ - ParameterType::Template - } else { - return Err(perr!("can't guess the type of parameter {:?}", val)); - }; - Self::from_typed_json(typ, val) - } } -impl Serialize for Parameter { - fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> - where S: Serializer { - self.to_json().serialize(serializer) - } -} -impl<'de> Deserialize<'de> for Parameter { - fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> - where D: Deserializer<'de> { - Self::guess_from_json(&Value::deserialize(deserializer)?).map_err(|e| de::Error::custom(e.text)) - } -} - #[cfg(test)] mod tests { use super::*; use serde_json::json; macro_rules! gfj { // guess from json - ($($j:tt)*) => {Parameter::guess_from_json(&json!($($j)*)).unwrap()} + ($($j:tt)*) => {Parameter::deserialize(&json!($($j)*)).unwrap()} } #[test] fn can_guess_json() { - Parameter::guess_from_json(&json!(3)).unwrap(); + Parameter::deserialize(&json!(3)).unwrap(); } #[test] @@ -162,19 +86,19 @@ mod tests { assert_eq!(gfj!(-0.0), Parameter::Float(0.0)); assert_eq!(gfj!(true), Parameter::Bool(true)); - assert_eq!(gfj!(["int", 3]), Parameter::Int(3)); + assert_eq!(gfj!(["int", 3]), Parameter::List(vec![Parameter::string("int"), Parameter::Int(3)])); + assert_eq!(gfj!([2, 5]), Parameter::List(vec![Parameter::Int(2), Parameter::Int(5)])); } #[test] fn guess_json_none() { - assert!(Parameter::guess_from_json(&json!([2, 5])).is_err()); - assert!(Parameter::guess_from_json(&json!({"hello": "world"})).is_err()); + assert!(Parameter::deserialize(&json!({"hello": "world"})).is_err()); } #[test] fn parse_list() { assert_eq!( - gfj!(["list", [5, 3, 1, 2]]), + gfj!([5, 3, 1, 2]), Parameter::List(vec![ Parameter::Int(5), Parameter::Int(3), @@ -183,7 +107,7 @@ mod tests { ]) ); assert_eq!( - gfj!(["list", [5, 3.0, "Hello", true]]), + gfj!([5, 3.0, "Hello", true]), Parameter::List(vec![ Parameter::Int(5), Parameter::Float(3.0), diff --git a/src/parameterexpression.rs b/src/parameterexpression.rs index b92613a..2db52ef 100644 --- a/src/parameterexpression.rs +++ b/src/parameterexpression.rs @@ -1,16 +1,13 @@ use std::collections::HashMap; use rand::Rng; -use serde_json::{Value, json}; -use serde::{Deserialize, Deserializer, de}; +use serde::{Deserialize, Deserializer}; use crate::{ parameter::{Parameter, ParameterType}, Template, template::{EntityType}, Result as AnyResult, aerr, - PResult, - perr }; const MAX_NESTING: usize = 5; @@ -21,7 +18,7 @@ pub enum ParameterExpression { Constant(Parameter), List(Vec<ParameterExpression>), #[allow(dead_code)] // rustc bug does not know that this variant is used: https://github.com/rust-lang/rust/issues/68408 - Template{name: EntityType, kwargs: HashMap<String, ParameterExpression>, save: Option<bool>}, + Template{name: EntityType, kwargs: HashMap<String, ParameterExpression>, save: Option<bool>, clan: Option<String>}, Argument(String), Random(Vec<ParameterExpression>), Concat(Vec<ParameterExpression>), @@ -47,7 +44,7 @@ impl ParameterExpression { Self::List(values) => { Some(Parameter::List(values.iter().map(|v| v.evaluate_(arguments, template, nesting+1)).collect::<Option<Vec<Parameter>>>()?)) } - Self::Template{name, kwargs, save} => { + Self::Template{name, kwargs, save, clan} => { Some(Parameter::Template(Template{ name: name.clone(), save: *save, @@ -57,7 +54,7 @@ impl ParameterExpression { |(k, v)| Some((k.clone(), v.evaluate_(arguments, template, nesting+1)?))) .collect::<Option<HashMap<String, Parameter>>>()?, - clan: None + clan: clan.clone() })) } Self::Argument(argname) => { @@ -95,88 +92,12 @@ impl ParameterExpression { } } - pub fn from_json(value: &Value) -> PResult<Self> { - if !value.is_array() { - return Ok(Self::Constant(Parameter::guess_from_json(value)?)); - } - let paramvalue = value.get(1).ok_or(perr!("index 1 not in component parameter"))?; - let typename = value.get(0).ok_or(perr!("index 0 not in component parameter"))?.as_str().ok_or(perr!("compparam type not a string"))?; - match typename { - "string" | "int" | "float" | "bool" | "pos" => { - let paramtype = ParameterType::from_str(typename).expect(&format!("unknown parameter type {:?}", typename)); - Ok(Self::Constant(Parameter::from_typed_json(paramtype, paramvalue)?)) - } - "list" => { - let values = paramvalue.as_array().ok_or(perr!("random argument not an array"))?; - let mut entries = Vec::new(); - for entry in values { - entries.push(Self::from_json(entry)?) - } - Ok(Self::List(entries)) - } - "template" => { - match paramvalue { - Value::String(s) => Ok(Self::Template{ - name: EntityType(s.clone()), - kwargs: HashMap::new(), - save: None - }), - Value::Object(o) => { - let name = EntityType(o.get("type").ok_or(perr!("template doesn't have 'type'"))?.as_str().ok_or(perr!("template type not a string"))?.to_string()); - let mut kwargs = HashMap::new(); - for (key, arg) in o.get("kwargs").unwrap_or(&json!({})).as_object().ok_or(perr!("template kwargs not a json object"))? { - kwargs.insert(key.to_string(), Self::from_json(arg)?); - } - let save = match o.get("save") { - Some(Value::Bool(b)) if *b => Some(true), - Some(Value::Bool(_b)) => Some(false), - None => None, - _ => {return Err(perr!("save not a bool"))} - }; - Ok(Self::Template{name, kwargs, save}) - } - _ => return Err(perr!("invalid template {:?}", paramvalue)) - } - } - "A" | "arg" => { - let argname = paramvalue.as_str().ok_or(perr!("argument parameter not a string"))?.to_string(); - Ok(Self::Argument(argname)) - } - "random" => { - let optionvalues = paramvalue.as_array().ok_or(perr!("random argument not an array"))?; - let mut options = Vec::new(); - for option in optionvalues { - options.push(Self::from_json(option)?) - } - Ok(Self::Random(options)) - } - "concat" => { - let values = paramvalue.as_array().ok_or(perr!("concat argument not an array"))?; - let mut options = Vec::new(); - for option in values { - options.push(Self::from_json(option)?) - } - Ok(Self::Concat(options)) - } - "if" => { - Ok(Self::If( - Box::new(Self::from_json(paramvalue.get(0).ok_or(perr!("if does not have condition"))?)?), - Box::new(Self::from_json(paramvalue.get(1).ok_or(perr!("if does not have then value"))?)?), - Box::new(Self::from_json(paramvalue.get(2).ok_or(perr!("if does not have else value"))?)?) - )) - } - "self" => Ok(Self::TemplateSelf), - "name" => Ok(Self::TemplateName), - _ => Err(perr!("unknown compparam type '{}'", typename)) - } - } - #[allow(dead_code)] pub fn get_type(&self, arguments: &[(String, ParameterType, Option<Parameter>)]) -> AnyResult<ParameterType>{ Ok(match self { Self::Constant(param) => param.paramtype(), Self::List(_) => ParameterType::List, - Self::Template{name: _, kwargs: _, save: _} => ParameterType::Template, + Self::Template{name: _, kwargs: _, save: _, clan: _} => ParameterType::Template, Self::Argument(argname) => arguments.iter().find(|(n, _t, _d)| n == argname).ok_or(aerr!("unknown argument name {} in {:?}", argname, arguments))?.1, Self::Random(options) => { let typ: ParameterType = options.get(0).ok_or(aerr!("random has no options"))?.get_type(arguments)?; @@ -204,16 +125,57 @@ impl ParameterExpression { } } -// impl Serialize for ParameterExpression { -// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> -// where S: Serializer { -// self.to_json().serialize(serializer) -// } -// } + +#[derive(Debug, PartialEq, Clone, Deserialize)] +enum DynamicParameterExpressionSave { + #[serde(rename = "$arg")] + Argument(String), + #[serde(rename = "$random")] + Random(Vec<ParameterExpression>), + #[serde(rename = "$concat")] + Concat(Vec<ParameterExpression>), + #[serde(rename = "$if")] + If(Box<ParameterExpression>, Box<ParameterExpression>, Box<ParameterExpression>), + #[serde(rename = "$self")] + TemplateSelf, + #[serde(rename = "$name")] + TemplateName +} +#[derive(Debug, PartialEq, Clone, Deserialize)] +#[serde(untagged)] +enum ParameterExpressionSave { + List(Vec<ParameterExpression>), + Template { + #[serde(rename = "$template")] + name: EntityType, + #[serde(rename="__save__", default, skip_serializing_if = "Option::is_none")] + save: Option<bool>, + #[serde(rename="__clan__", default, skip_serializing_if = "Option::is_none")] + clan: Option<String>, + #[serde(flatten)] + kwargs: HashMap<String, ParameterExpression> + }, + Dynamic(DynamicParameterExpressionSave), + Constant(Parameter), +} +use ParameterExpressionSave as PES; +use DynamicParameterExpressionSave as DPES; + impl<'de> Deserialize<'de> for ParameterExpression { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> { - Self::from_json(&Value::deserialize(deserializer)?).map_err(|e| de::Error::custom(e.text)) + let save = ParameterExpressionSave::deserialize(deserializer)?; + Ok(match save { + PES::List(params) => Self::List(params), + PES::Template{name, save, clan, kwargs} => Self::Template{name, save, kwargs, clan}, + PES::Dynamic(DPES::Argument(name)) => Self::Argument(name), + PES::Dynamic(DPES::Random(items)) => Self::Random(items), + PES::Dynamic(DPES::Concat(items)) => Self::Concat(items), + PES::Dynamic(DPES::If(condition, ifpart, elsepart)) => Self::If(condition, ifpart, elsepart), + PES::Dynamic(DPES::TemplateSelf) => Self::TemplateSelf, + PES::Dynamic(DPES::TemplateName) => Self::TemplateName, + PES::Constant(param) => Self::Constant(param) + }) } } @@ -222,6 +184,7 @@ mod tests { use super::*; use super::ParameterExpression as PE; use crate::hashmap; + use serde_json::json; #[test] fn test_desrialize(){ @@ -230,22 +193,48 @@ mod tests { PE::Constant(Parameter::String("hello".to_string())) ); assert_eq!( - PE::deserialize(json!(["arg", "hello"])).unwrap(), + PE::deserialize(json!({"$arg": "hello"})).unwrap(), PE::Argument("hello".to_string()) ); assert_eq!( - PE::deserialize(json!(["list", ["hello", 3]])).unwrap(), + PE::deserialize(json!(["hello", 3])).unwrap(), PE::List(vec![ PE::Constant(Parameter::String("hello".to_string())), PE::Constant(Parameter::Int(3)) ]) ); + } + #[test] + fn test_templates(){ assert_eq!( - PE::deserialize(json!(["template", {"type": "radish", "kwargs": {"health": 10}}])).unwrap(), + PE::deserialize(json!({"$template": "radish", "health": 10})).unwrap(), PE::Template{ name: EntityType("radish".to_string()), kwargs: hashmap!{"health".to_string() => PE::Constant(Parameter::Int(10))}, - save: None + save: None, + clan: None + } + ); + assert_eq!( + PE::deserialize(json!({":template": "radish", "health": 10})).unwrap(), + PE::Constant(Parameter::Template(Template{ + name: EntityType("radish".to_string()), + kwargs: hashmap!{"health".to_string() => Parameter::Int(10)}, + save: None, + clan: None + })) + ); + assert_eq!( + PE::deserialize(json!({"$template": "radish", "health": {"$if": [{"$arg": "is_eldritch"}, 20, 3]}})).unwrap(), + PE::Template{ + name: EntityType("radish".to_string()), + kwargs: hashmap!{"health".to_string() => PE::If( + Box::new(PE::Argument("is_eldritch".to_string())), + Box::new(PE::Constant(Parameter::Int(20))), + Box::new(PE::Constant(Parameter::Int(3))) + )}, + save: None, + clan: None } ); } diff --git a/src/template.rs b/src/template.rs index 1ef6fc1..6eb27e1 100644 --- a/src/template.rs +++ b/src/template.rs @@ -23,6 +23,16 @@ enum TemplateSave { save: Option<bool>, #[serde(default, skip_serializing_if = "Option::is_none")] clan: Option<String> + }, + New{ + #[serde(rename = ":template")] + name: EntityType, + #[serde(rename="__save__", default, skip_serializing_if = "Option::is_none")] + save: Option<bool>, + #[serde(rename="__clan__", default, skip_serializing_if = "Option::is_none")] + clan: Option<String>, + #[serde(default, flatten, skip_serializing_if = "HashMap::is_empty")] + kwargs: HashMap<String, Parameter> } } @@ -40,7 +50,8 @@ impl From<TemplateSave> for Template { fn from(ts: TemplateSave) -> Self { match ts { TemplateSave::Name(name) => Self{name, kwargs: HashMap::new(), save: None, clan: None}, - TemplateSave::Full{name, kwargs, save, clan} => Self{name, kwargs, save, clan} + TemplateSave::Full{name, kwargs, save, clan} => Self{name, kwargs, save, clan}, + TemplateSave::New{name, kwargs, save, clan} => Self{name, kwargs, save, clan} } } } @@ -49,7 +60,7 @@ impl Into<TemplateSave> for Template { if self.kwargs.is_empty() && self.save == None && self.clan == None { return TemplateSave::Name(self.name); } - TemplateSave::Full { + TemplateSave::New { name: self.name, kwargs: self.kwargs, save: self.save, |
