aboutsummaryrefslogtreecommitdiff
path: root/server
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2024-07-11 16:55:39 +0200
committermetamuffin <metamuffin@disroot.org>2024-07-11 16:55:39 +0200
commit2537e764a359328870c3eabb16ee5238becd3c73 (patch)
tree07b731da36fd795399dbb62446e8a36ae3318f0b /server
parent51f3c580fcfac8d37e5e345031cadda141f0340f (diff)
downloadhurrycurry-2537e764a359328870c3eabb16ee5238becd3c73.tar
hurrycurry-2537e764a359328870c3eabb16ee5238becd3c73.tar.bz2
hurrycurry-2537e764a359328870c3eabb16ee5238becd3c73.tar.zst
add conveyor filters
Diffstat (limited to 'server')
-rw-r--r--server/src/data.rs74
-rw-r--r--server/src/entity/conveyor.rs33
-rw-r--r--server/src/entity/mod.rs56
-rw-r--r--server/src/entity/portal.rs46
4 files changed, 150 insertions, 59 deletions
diff --git a/server/src/data.rs b/server/src/data.rs
index c5ed25ad..966fd0d2 100644
--- a/server/src/data.rs
+++ b/server/src/data.rs
@@ -179,23 +179,16 @@ impl Gamedata {
demands_in: Vec<DemandDecl>,
recipes_in: Vec<RecipeDecl>,
) -> Result<Self> {
- let item_names = RwLock::new(Vec::new());
- let tile_names = RwLock::new(Vec::new());
+ let reg = ItemTileRegistry::default();
let mut recipes = Vec::new();
let mut demands = Vec::new();
let mut entities = Vec::new();
for mut r in recipes_in {
let r2 = r.clone();
- let mut inputs = r
- .inputs
- .into_iter()
- .map(|i| ItemIndex(register(&item_names, i)));
- let mut outputs = r
- .outputs
- .into_iter()
- .map(|o| ItemIndex(register(&item_names, o)));
- let tile = r.tile.map(|t| TileIndex(register(&tile_names, t)));
+ let mut inputs = r.inputs.into_iter().map(|i| reg.register_item(i));
+ let mut outputs = r.outputs.into_iter().map(|o| reg.register_item(o));
+ let tile = r.tile.map(|t| reg.register_tile(t));
match r.action {
Action::Never => {}
Action::Passive => recipes.push(Recipe::Passive {
@@ -228,8 +221,8 @@ impl Gamedata {
for d in demands_in {
demands.push(Demand {
- from: ItemIndex(register(&item_names, d.from)),
- to: d.to.map(|to| ItemIndex(register(&item_names, to))),
+ from: reg.register_item(d.from),
+ to: d.to.map(|to| reg.register_item(to)),
duration: d.duration,
points: d.points,
})
@@ -253,18 +246,25 @@ impl Gamedata {
.ok_or(anyhow!("tile {tile} is undefined"))?
.clone();
if let Some(ent) = map_in.tile_entities.get(&tile) {
- entities.push(construct_entity(Some(pos), ent)?);
+ entities.push(construct_entity(Some(pos), ent, &reg)?);
}
let itemname = map_in.items.get(&tile).cloned();
- let tile = TileIndex(register(&tile_names, tilename));
- let item = itemname.map(|i| ItemIndex(register(&item_names, i)));
+ let tile = reg.register_tile(tilename);
+ let item = itemname.map(|i| reg.register_item(i));
initial_map.insert(pos, (tile, item));
}
}
- let item_names = item_names.into_inner().unwrap();
- let tile_names = tile_names.into_inner().unwrap();
+ entities.extend(
+ map_in
+ .entities
+ .iter()
+ .map(|decl| construct_entity(None, decl, &reg))
+ .try_collect::<Vec<_>>()?,
+ );
+ let item_names = reg.items.into_inner().unwrap();
+ let tile_names = reg.tiles.into_inner().unwrap();
let tile_collide = tile_names
.iter()
.map(|i| !map_in.walkable.contains(i))
@@ -274,14 +274,6 @@ impl Gamedata {
.map(|i| !map_in.collider.contains(i) && !map_in.walkable.contains(i))
.collect();
- entities.extend(
- map_in
- .entities
- .iter()
- .map(|decl| construct_entity(None, decl))
- .try_collect::<Vec<_>>()?,
- );
-
Ok(Gamedata {
spec,
demands,
@@ -299,14 +291,28 @@ impl Gamedata {
}
}
-fn register(db: &RwLock<Vec<String>>, name: String) -> usize {
- let mut db = db.write().unwrap();
- if let Some(index) = db.iter().position(|e| e == &name) {
- index
- } else {
- let index = db.len();
- db.push(name);
- index
+#[derive(Default)]
+pub struct ItemTileRegistry {
+ tiles: RwLock<Vec<String>>,
+ items: RwLock<Vec<String>>,
+}
+
+impl ItemTileRegistry {
+ pub fn register_tile(&self, name: String) -> TileIndex {
+ TileIndex(Self::register(&self.tiles, name))
+ }
+ pub fn register_item(&self, name: String) -> ItemIndex {
+ ItemIndex(Self::register(&self.items, name))
+ }
+ fn register(db: &RwLock<Vec<String>>, name: String) -> usize {
+ let mut db = db.write().unwrap();
+ if let Some(index) = db.iter().position(|e| e == &name) {
+ index
+ } else {
+ let index = db.len();
+ db.push(name);
+ index
+ }
}
}
diff --git a/server/src/entity/conveyor.rs b/server/src/entity/conveyor.rs
index 4d11ffe1..2d56c144 100644
--- a/server/src/entity/conveyor.rs
+++ b/server/src/entity/conveyor.rs
@@ -21,13 +21,15 @@ use crate::{
game::{interact_effect, Tile},
};
use anyhow::{anyhow, Result};
-use hurrycurry_protocol::{glam::IVec2, ItemLocation, PacketC};
+use hurrycurry_protocol::{glam::IVec2, ItemIndex, ItemLocation, PacketC};
use std::collections::{HashMap, VecDeque};
-#[derive(Debug, Default, Clone)]
+#[derive(Debug, Clone)]
pub struct Conveyor {
pub(super) from: IVec2,
pub(super) to: IVec2,
+ pub(super) filter_tile: Option<IVec2>,
+ pub(super) filter_item: Option<ItemIndex>,
pub(super) cooldown: f32,
pub(super) max_cooldown: f32,
}
@@ -41,17 +43,36 @@ impl EntityT for Conveyor {
tiles: &mut HashMap<IVec2, Tile>,
dt: f32,
) -> Result<()> {
- let [from, to] = tiles
- .get_many_mut([&self.from, &self.to])
- .ok_or(anyhow!("conveyor does ends in itself"))?;
+ let from = tiles
+ .get(&self.from)
+ .ok_or(anyhow!("conveyor from missing"))?;
+
+ if let Some(from_item) = from.item.as_ref() {
+ let filter = if let Some(t) = &self.filter_tile {
+ let filter_tile = tiles.get(t).ok_or(anyhow!("conveyor filter missing"))?;
+ filter_tile.item.as_ref().map(|e| e.kind)
+ } else if let Some(i) = &self.filter_item {
+ Some(*i)
+ } else {
+ None
+ };
+
+ if let Some(filter) = filter {
+ if from_item.kind != filter {
+ return Ok(());
+ }
+ }
- if from.item.is_some() {
self.cooldown += dt;
if self.cooldown < self.max_cooldown {
return Ok(());
}
self.cooldown = 0.;
+ let [from, to] = tiles
+ .get_many_mut([&self.from, &self.to])
+ .ok_or(anyhow!("conveyor does ends in itself"))?;
+
interact_effect(
data,
true,
diff --git a/server/src/entity/mod.rs b/server/src/entity/mod.rs
index 925ed5f4..a1f690a3 100644
--- a/server/src/entity/mod.rs
+++ b/server/src/entity/mod.rs
@@ -16,10 +16,15 @@
*/
pub mod conveyor;
-use crate::{data::Gamedata, game::Tile};
+pub mod portal;
+use crate::{
+ data::{Gamedata, ItemTileRegistry},
+ game::Tile,
+};
use anyhow::{anyhow, Result};
use conveyor::Conveyor;
use hurrycurry_protocol::{glam::IVec2, PacketC};
+use portal::Portal;
use serde::{Deserialize, Serialize};
use std::collections::{HashMap, VecDeque};
@@ -34,43 +39,54 @@ pub trait EntityT: Clone {
) -> Result<()>;
}
-#[derive(Debug, Clone)]
-pub enum Entity {
- Conveyor(Conveyor),
-}
-impl EntityT for Entity {
- fn tick(
- &mut self,
- data: &Gamedata,
- points: &mut i64,
- packet_out: &mut VecDeque<PacketC>,
- tiles: &mut HashMap<IVec2, Tile>,
- dt: f32,
- ) -> Result<()> {
- match self {
- Entity::Conveyor(x) => x.tick(data, points, packet_out, tiles, dt),
+macro_rules! entities {
+ ($($e:ident),*) => {
+ #[derive(Debug, Clone)]
+ pub enum Entity { $($e($e)),* }
+ impl EntityT for Entity {
+ fn tick(&mut self, data: &Gamedata, points: &mut i64, packet_out: &mut VecDeque<PacketC>, tiles: &mut HashMap<IVec2, Tile>, dt: f32) -> Result<()> {
+ match self { $(Entity::$e(x) => x.tick(data, points, packet_out, tiles, dt)),*, }
+ }
}
- }
+ };
}
+entities!(Conveyor, Portal);
+
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum EntityDecl {
Conveyor {
from: Option<IVec2>,
to: Option<IVec2>,
+ filter_dir: Option<IVec2>,
+ filter: Option<String>,
dir: Option<IVec2>,
speed: Option<f32>,
},
+ Portal {
+ from: Option<IVec2>,
+ to: IVec2,
+ },
}
-pub fn construct_entity(pos: Option<IVec2>, decl: &EntityDecl) -> Result<Entity> {
+pub fn construct_entity(
+ pos: Option<IVec2>,
+ decl: &EntityDecl,
+ reg: &ItemTileRegistry,
+) -> Result<Entity> {
Ok(match decl.to_owned() {
+ EntityDecl::Portal { from, to } => Entity::Portal(Portal {
+ from: from.or(pos).ok_or(anyhow!("no portla start"))?,
+ to,
+ }),
EntityDecl::Conveyor {
from,
to,
speed,
dir,
+ filter,
+ filter_dir,
} => {
let from = from.or(pos).ok_or(anyhow!("conveyor has no start"))?;
let to = to
@@ -80,7 +96,9 @@ pub fn construct_entity(pos: Option<IVec2>, decl: &EntityDecl) -> Result<Entity>
from,
to,
max_cooldown: 1. / speed.unwrap_or(2.),
- ..Default::default()
+ filter_tile: filter_dir.map(|o| to + o),
+ filter_item: filter.map(|name| reg.register_item(name)),
+ cooldown: 0.,
})
}
})
diff --git a/server/src/entity/portal.rs b/server/src/entity/portal.rs
new file mode 100644
index 00000000..e0195b9f
--- /dev/null
+++ b/server/src/entity/portal.rs
@@ -0,0 +1,46 @@
+use super::EntityT;
+use crate::{
+ data::Gamedata,
+ game::{interact_effect, Tile},
+};
+use anyhow::{anyhow, Result};
+use hurrycurry_protocol::{glam::IVec2, ItemLocation, PacketC};
+use std::collections::{HashMap, VecDeque};
+
+#[derive(Debug, Default, Clone)]
+pub struct Portal {
+ pub(super) from: IVec2,
+ pub(super) to: IVec2,
+}
+
+impl EntityT for Portal {
+ fn tick(
+ &mut self,
+ data: &Gamedata,
+ points: &mut i64,
+ packet_out: &mut VecDeque<PacketC>,
+ tiles: &mut HashMap<IVec2, Tile>,
+ _dt: f32,
+ ) -> Result<()> {
+ let [from, to] = tiles
+ .get_many_mut([&self.from, &self.to])
+ .ok_or(anyhow!("conveyor does ends in itself"))?;
+
+ if from.item.is_some() {
+ interact_effect(
+ data,
+ true,
+ &mut to.item,
+ ItemLocation::Tile(self.to),
+ &mut from.item,
+ ItemLocation::Tile(self.from),
+ Some(to.kind),
+ packet_out,
+ points,
+ true,
+ );
+ }
+
+ Ok(())
+ }
+}