diff options
author | metamuffin <metamuffin@disroot.org> | 2024-07-11 16:55:39 +0200 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2024-07-11 16:55:39 +0200 |
commit | 2537e764a359328870c3eabb16ee5238becd3c73 (patch) | |
tree | 07b731da36fd795399dbb62446e8a36ae3318f0b /server/src | |
parent | 51f3c580fcfac8d37e5e345031cadda141f0340f (diff) | |
download | hurrycurry-2537e764a359328870c3eabb16ee5238becd3c73.tar hurrycurry-2537e764a359328870c3eabb16ee5238becd3c73.tar.bz2 hurrycurry-2537e764a359328870c3eabb16ee5238becd3c73.tar.zst |
add conveyor filters
Diffstat (limited to 'server/src')
-rw-r--r-- | server/src/data.rs | 74 | ||||
-rw-r--r-- | server/src/entity/conveyor.rs | 33 | ||||
-rw-r--r-- | server/src/entity/mod.rs | 56 | ||||
-rw-r--r-- | server/src/entity/portal.rs | 46 |
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, ®)?); } 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, ®)) + .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(()) + } +} |