summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authortroido <troido@protonmail.com>2020-04-16 10:54:23 +0200
committertroido <troido@protonmail.com>2020-04-16 10:54:23 +0200
commit905c6b649521296bba609db5b5c9a39008d34325 (patch)
tree8d253de507b3663399e23819bf8b4a222e7b64a5 /src
parent43bde225ebbadd0b917ca87f3164a50455a2b588 (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.rs2
-rw-r--r--src/components/interactable.rs2
-rw-r--r--src/components/mod.rs10
-rw-r--r--src/componentwrapper.rs50
-rw-r--r--src/room.rs6
-rw-r--r--src/systems/deduplicate.rs57
-rw-r--r--src/systems/interact.rs39
-rw-r--r--src/systems/mod.rs4
-rw-r--r--src/template.rs35
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})
}