diff options
| author | troido <troido@protonmail.com> | 2020-04-16 10:54:23 +0200 |
|---|---|---|
| committer | troido <troido@protonmail.com> | 2020-04-16 10:54:23 +0200 |
| commit | 905c6b649521296bba609db5b5c9a39008d34325 (patch) | |
| tree | 8d253de507b3663399e23819bf8b4a222e7b64a5 /src | |
| parent | 43bde225ebbadd0b917ca87f3164a50455a2b588 (diff) | |
add visit whitelist to homeportal, save and dedup its data even though it is loaded from template
Diffstat (limited to 'src')
| -rw-r--r-- | src/assemblage.rs | 2 | ||||
| -rw-r--r-- | src/components/interactable.rs | 2 | ||||
| -rw-r--r-- | src/components/mod.rs | 10 | ||||
| -rw-r--r-- | src/componentwrapper.rs | 50 | ||||
| -rw-r--r-- | src/room.rs | 6 | ||||
| -rw-r--r-- | src/systems/deduplicate.rs | 57 | ||||
| -rw-r--r-- | src/systems/interact.rs | 39 | ||||
| -rw-r--r-- | src/systems/mod.rs | 4 | ||||
| -rw-r--r-- | src/template.rs | 35 |
9 files changed, 183 insertions, 22 deletions
diff --git a/src/assemblage.rs b/src/assemblage.rs index e3238c9..d572c7f 100644 --- a/src/assemblage.rs +++ b/src/assemblage.rs @@ -192,7 +192,7 @@ impl Assemblage { } components.push(ComponentWrapper::load_component(*comptype, compargs)?); } - if template.save && self.save { + if template.should_save() && self.save { components.push(ComponentWrapper::Serialise(Serialise{template: template.clone(), extract: self.extract.clone() })); } Ok(components) diff --git a/src/components/interactable.rs b/src/components/interactable.rs index 3432f33..f1f0508 100644 --- a/src/components/interactable.rs +++ b/src/components/interactable.rs @@ -65,7 +65,7 @@ impl Interactable { } Visit(_) => { if let Some(txt) = arg { - txt.starts_with("visit") + txt.starts_with("visit ") || txt.starts_with("disallow ") || txt.starts_with("allow ") || txt.starts_with("whitelist") } else { false } diff --git a/src/components/mod.rs b/src/components/mod.rs index ae50edc..176f97a 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -29,7 +29,7 @@ pub use ear::{ Ear }; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use specs::{ DenseVecStorage, @@ -229,9 +229,13 @@ pub struct Build { #[derive(Component, Debug, Clone)] pub struct Whitelist{ - pub allowed: HashMap<String, PlayerId> + pub allowed: HashMap<String, HashSet<PlayerId>> } - +#[derive(Component, Debug, Clone)] +pub struct Dedup { + pub id: String, + pub priority: i64 +} diff --git a/src/componentwrapper.rs b/src/componentwrapper.rs index 5fe8f1d..d677cb2 100644 --- a/src/componentwrapper.rs +++ b/src/componentwrapper.rs @@ -132,10 +132,10 @@ macro_rules! components { (pre: ($($done: tt)*)) => { components!(post: $($done)*); }; - ($($all: tt)*) => {components!(pre: () $($all)*);}; + (all: $($all: tt)*) => {components!(pre: () $($all)*);}; } -components!( +components!(all: Visible (name: String, sprite: String, height: Float) { Visible { sprite: Sprite{name: sprite}, @@ -238,6 +238,52 @@ components!( }; Ear () {Ear::default()}; Build (obj: Template); + Whitelist ( + allowed: List ({ + Whitelist.allowed.iter().map(|(item, players)|{ + Parameter::List(vec![ + Parameter::String(item.clone()), + Parameter::List( + players + .iter() + .map(|playerid| Parameter::String(playerid.name.clone())) + .collect() + ) + ]) + }).collect() + }) + ) { + Whitelist { + allowed: allowed + .iter() + .map(|p| { + if let Parameter::List(e) = p { + if e.len() != 2 { + Err(aerr!("whitelist must be a list of pairs"))? + } + if let (Parameter::String(s), Parameter::List(l)) = (e[0].clone(), e[1].clone()) { + let names = l + .iter() + .map(|n| { + if let Parameter::String(name) = n { + Ok(PlayerId{name: name.clone()}) + } else { + Err(aerr!("whitelisted players must be strings"))? + } + }) + .collect::<Result<HashSet<PlayerId>>>()?; + Ok((s, names)) + } else { + Err(aerr!("whitelist entries must be a string and a list"))? + } + } else { + Err(aerr!("whitelist must be a list of pairs"))? + } + }) + .collect::<Result<HashMap<String, HashSet<PlayerId>>>>()? + } + }; + Dedup (id: String, priority: Int); ); diff --git a/src/room.rs b/src/room.rs index c9fb525..01a299a 100644 --- a/src/room.rs +++ b/src/room.rs @@ -66,12 +66,14 @@ use crate::{ DropLoot, Timeout, Clear, - Building + Building, + Deduplicate } }; pub fn default_dispatcher<'a, 'b>() -> Dispatcher<'a, 'b> { DispatcherBuilder::new() + .with(Deduplicate, "deduplicate", &[]) .with(Timeout, "timeout", &[]) .with(UpdateCooldowns, "cool_down", &[]) .with(Spawn, "spawn", &[]) @@ -118,7 +120,7 @@ impl <'a, 'b>Room<'a, 'b> { world.insert(NewEntities::new(encyclopedia)); register_insert!( world, - (Position, Visible, Controller, Movable, New, Removed, Moved, Player, Inventory, Health, Serialise, RoomExit, Entered, TriggerBox, Trap, Fighter, Healing, ControlCooldown, Autofight, MonsterAI, Home, AttackInbox, Item, Spawner, Clan, Faction, Interactable, Loot, Timer, Equipment, TimeOffset, Flags, Ear, Build, Whitelist), + (Position, Visible, Controller, Movable, New, Removed, Moved, Player, Inventory, Health, Serialise, RoomExit, Entered, TriggerBox, Trap, Fighter, Healing, ControlCooldown, Autofight, MonsterAI, Home, AttackInbox, Item, Spawner, Clan, Faction, Interactable, Loot, Timer, Equipment, TimeOffset, Flags, Ear, Build, Whitelist, Dedup), (Ground, Input, Output, Size, Spawn, Players, Emigration, Time) ); diff --git a/src/systems/deduplicate.rs b/src/systems/deduplicate.rs new file mode 100644 index 0000000..e9fb88a --- /dev/null +++ b/src/systems/deduplicate.rs @@ -0,0 +1,57 @@ + +use std::collections::HashSet; + +use specs::{ + Read, + WriteStorage, + ReadStorage, + Entities, + Entity, + System, + Join +}; + +use crate::{ + components::{Dedup, Removed, New, Position}, + resources::Ground +}; + + +pub struct Deduplicate; +impl <'a> System<'a> for Deduplicate { + type SystemData = ( + Entities<'a>, + WriteStorage<'a, Dedup>, + WriteStorage<'a, Removed>, + ReadStorage<'a, New>, + ReadStorage<'a, Position>, + Read<'a, Ground> + ); + fn run(&mut self, (entities, mut dedups, mut removeds, news, positions, ground): Self::SystemData) { + for (entity, dedup, position, _) in (&entities, &dedups, &positions, &news).join() { + let others: Vec<(Entity, &Dedup)> = ground.cells + .get(&position.pos) + .unwrap_or(&HashSet::new()) + .iter() + .filter_map(|e| Some((*e, dedups.get(*e)?))) + .collect(); + for (e, d) in others { + if dedup.id == d.id { + if dedup.priority > d.priority { + removeds.insert(e, Removed).unwrap(); + } else if dedup.priority < d.priority { + removeds.insert(entity, Removed).unwrap(); + } else if entity > e { + removeds.insert(e, Removed).unwrap(); + } else if entity < e { + removeds.insert(entity, Removed).unwrap(); + } + } + } + } + for (dedup, _) in (&mut dedups, &news).join() { + dedup.priority += 1; + } + } +} + diff --git a/src/systems/interact.rs b/src/systems/interact.rs index c3cd0d2..d00f3d7 100644 --- a/src/systems/interact.rs +++ b/src/systems/interact.rs @@ -21,12 +21,14 @@ use crate::{ Ear, Inventory, Visible, - Player + Player, + Whitelist }, controls::{Control}, resources::{Ground, NewEntities, Emigration}, hashmap, - playerstate::RoomPos + playerstate::RoomPos, + PlayerId }; pub struct Interact; @@ -44,10 +46,11 @@ impl <'a> System<'a> for Interact { WriteStorage<'a, Inventory>, ReadStorage<'a, Visible>, ReadStorage<'a, Player>, - Write<'a, Emigration> + Write<'a, Emigration>, + WriteStorage<'a, Whitelist> ); - fn run(&mut self, (entities, controllers, positions, ground, mut cooldowns, interactables, mut triggerbox, new, mut ears, mut inventories, visibles, players, mut emigration): Self::SystemData) { + fn run(&mut self, (entities, controllers, positions, ground, mut cooldowns, interactables, mut triggerbox, new, mut ears, mut inventories, visibles, players, mut emigration, mut whitelists): Self::SystemData) { for (entity, controller, position) in (&entities, &controllers, &positions).join(){ let mut target = None; let ear = ears.get_mut(entity); @@ -107,12 +110,34 @@ impl <'a> System<'a> for Interact { } } Interactable::Visit(dest) => { - if let Some(player) = players.get(entity){ + if let (Some(player), Some(whitelist)) = (players.get(entity), whitelists.get_mut(ent)){ let argument = arg.unwrap(); - if argument.starts_with("visit") { + if argument.starts_with("visit ") { let playername = argument.split_at("visit ".len()).1; let destination = dest.format(hashmap!("{player}" => playername)); - emigration.emigrants.push((player.id.clone(), destination, RoomPos::Unknown)); + if let Some(set) = whitelist.allowed.get(&destination.name) { + if set.contains(&player.id){ + emigration.emigrants.push((player.id.clone(), destination, RoomPos::Unknown)); + } else { + say(ear, format!("not allowed to visit {}", playername), name); + } + } else { + say(ear, format!("unknown destination {}", playername), name); + } + } else if argument.starts_with("allow ") { + let playername = argument.split_at("allow ".len()).1; + let destination = dest.format(hashmap!("{player}" => player.id.name.as_str())); + whitelist.allowed.entry(destination.name).or_insert_with(HashSet::new).insert(PlayerId{name: playername.to_string()}); + say(ear, format!("allowed {} to enter your home", playername), name); + } else if argument.starts_with("disallow ") { + let playername = argument.split_at("disallow ".len()).1; + let destination = dest.format(hashmap!("{player}" => player.id.name.as_str())); + whitelist.allowed.entry(destination.name).or_insert_with(HashSet::new).remove(&PlayerId{name: playername.to_string()}); + say(ear, format!("disallowed {} to enter your home", playername), name); + } else if argument.starts_with("whitelist") { + let destination = dest.format(hashmap!("{player}" => player.id.name.as_str())); + let allowed = whitelist.allowed.entry(destination.name).or_insert_with(HashSet::new).iter().map(|id| id.name.as_str()).collect::<Vec<&str>>(); + say(ear, format!("allowed players: {}", allowed.join(", ")), name); } } } diff --git a/src/systems/mod.rs b/src/systems/mod.rs index d45fc38..024f54f 100644 --- a/src/systems/mod.rs +++ b/src/systems/mod.rs @@ -21,6 +21,7 @@ mod droploot; mod timeout; mod clear; mod building; +mod deduplicate; pub use self::{ controlinput::ControlInput, @@ -44,5 +45,6 @@ pub use self::{ droploot::DropLoot, timeout::Timeout, clear::Clear, - building::Building + building::Building, + deduplicate::Deduplicate }; diff --git a/src/template.rs b/src/template.rs index 0ad1bc1..6b2dec3 100644 --- a/src/template.rs +++ b/src/template.rs @@ -11,12 +11,19 @@ use crate::{ #[derive(Debug, PartialEq, Eq, Clone, Hash)] pub struct EntityType(pub String); +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] +enum SaveOption { + Default, + False, + Always +} + #[derive(Debug, Clone, PartialEq)] pub struct Template { pub name: EntityType, pub args: Vec<Parameter>, pub kwargs: HashMap<String, Parameter>, - pub save: bool + save: SaveOption, } @@ -27,7 +34,7 @@ impl Template { name: EntityType(name.to_string()), args: Vec::new(), kwargs, - save: true + save: SaveOption::Default } } @@ -35,17 +42,26 @@ impl Template { Self::new(name, HashMap::new()) } + pub fn should_save(&self) -> bool { + match self.save { + SaveOption::Default | SaveOption::Always => true, + SaveOption::False => false + } + } + pub fn from_entity_type(typ: EntityType) -> Self { Self { name: typ, args: Vec::new(), kwargs: HashMap::new(), - save: true + save: SaveOption::Default } } pub fn unsaved(mut self) -> Self { - self.save = false; + if self.save == SaveOption::Default { + self.save = SaveOption::False + } self } @@ -69,7 +85,16 @@ impl Template { for (key, arg) in val.get("kwargs").unwrap_or(&json!({})).as_object().ok_or(perr!("template kwargs not a json object"))? { kwargs.insert(key.to_string(), Parameter::guess_from_json(arg).ok_or(perr!("template kwarg {}: {:?} not a parameter", key, arg))?); } - let save = val.get("save").unwrap_or(&json!(true)).as_bool().ok_or(perr!("save not a bool"))?; + let save = + if let Some(saveval) = val.get("save") { + if saveval.as_bool().ok_or(perr!("save not a bool"))? { + SaveOption::Always + } else { + SaveOption::False + } + } else { + SaveOption::Default + }; Ok(Template {name, args, kwargs, save}) } |
