diff options
-rw-r--r-- | data/index.yaml | 1 | ||||
-rw-r--r-- | data/maps/bus.yaml | 84 | ||||
-rw-r--r-- | data/maps/test.yaml | 6 | ||||
-rw-r--r-- | server/src/data.rs | 20 | ||||
-rw-r--r-- | server/src/entity/conveyor.rs | 7 | ||||
-rw-r--r-- | server/src/entity/mod.rs | 56 | ||||
-rw-r--r-- | server/src/game.rs | 16 | ||||
-rw-r--r-- | server/src/interaction.rs | 8 | ||||
-rw-r--r-- | server/src/lib.rs | 4 | ||||
-rw-r--r-- | test-client/main.ts | 5 | ||||
-rw-r--r-- | test-client/tiles.ts | 1 |
11 files changed, 169 insertions, 39 deletions
diff --git a/data/index.yaml b/data/index.yaml index 05e2de9d..f7abdb3b 100644 --- a/data/index.yaml +++ b/data/index.yaml @@ -14,6 +14,7 @@ maps: - depot - line - teeny + - bus recipes: - none diff --git a/data/maps/bus.yaml b/data/maps/bus.yaml new file mode 100644 index 00000000..cfac1380 --- /dev/null +++ b/data/maps/bus.yaml @@ -0,0 +1,84 @@ +map: + - "''''''''''''''''''''" + - "'███████c__c███████'" + - "'█#SSSS█t__t█RTFL.█'" + - "'█#....█c__c█.....█'" + - "'d.....█'__'█.....d'" + - "'█...>>>>»»>>>v...█'" + - "'█oo.A██▒dd▒██v...█'" + - "'████A█.c..c.█v████'" + - "'''''A▒ct..tc▒v'''''" + - "'''''A<......v<'''''" + - "'''''>A......>v'''''" + - "'''''A▒ct..tc▒v'''''" + - "'████A█.c..c.█v████'" + - "'█#..A██▒dd▒██v.pp█'" + - "'█#..A<<<««<<<<..p█'" + - "'d.....█'__'█.....d'" + - "'█.....█'__'█....p█'" + - "'█ff#CC█'__'█Xsspp█'" + - "'███████'__'███████'" + - "'''''''''__'''''''''" + - "'''''''''__'''''''''" + - "'''''''''!~'''''''''" + +tiles: + "#": counter + "f": counter + "p": counter + ">": conveyor + "<": conveyor + "A": conveyor + "v": conveyor + "t": table + "w": counter-window + "s": sink + "o": oven + "S": stove + "C": cuttingboard + "R": raw-steak-crate + "T": tomato-crate + "F": flour-crate + "L": leek-crate + "X": trash + + "c": chair + ".": floor + "'": grass + "*": tree + "~": path + "!": path + "_": path + "«": path + "»": path + "d": door + "█": wall + "▒": wall-window + +tile_entities: + ">": !conveyor { dir: [1, 0] } + "<": !conveyor { dir: [-1, 0] } + "»": !conveyor { dir: [1, 0] } + "«": !conveyor { dir: [-1, 0] } + "v": !conveyor { dir: [0, 1] } + "A": !conveyor { dir: [0, -1] } + +items: + "S": pot + "w": plate + "p": plate + "f": foodprocessor + +chef_spawn: "~" +customer_spawn: "!" + +walkable: + - door + - floor + - chair + - grass + - path + +collider: + - wall + - tree diff --git a/data/maps/test.yaml b/data/maps/test.yaml index 09f0b8a7..bb6137e5 100644 --- a/data/maps/test.yaml +++ b/data/maps/test.yaml @@ -34,9 +34,9 @@ map: tiles: "⌷": counter "f": counter - "<": counter - "#": counter - ">": counter + "<": conveyor + "#": conveyor + ">": conveyor "t": table "w": counter-window "s": sink diff --git a/server/src/data.rs b/server/src/data.rs index a1c7e894..c667e760 100644 --- a/server/src/data.rs +++ b/server/src/data.rs @@ -16,7 +16,7 @@ */ use crate::{ - entity::EntityDecl, + entity::{construct_entity, Entity, EntityDecl}, interaction::Recipe, protocol::{DemandIndex, ItemIndex, RecipeIndex, TileIndex}, }; @@ -73,6 +73,8 @@ pub struct InitialMap { customer_spawn: char, #[serde(default)] entities: Vec<EntityDecl>, + #[serde(default)] + tile_entities: HashMap<char, EntityDecl>, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -104,7 +106,7 @@ pub struct Gamedata { #[serde(skip)] pub initial_map: HashMap<IVec2, (TileIndex, Option<ItemIndex>)>, #[serde(skip)] pub chef_spawn: Vec2, #[serde(skip)] pub customer_spawn: Vec2, - #[serde(skip)] pub entities: Vec<EntityDecl>, + #[serde(skip)] pub entities: Vec<Entity>, } #[derive(Debug, Deserialize, Default)] @@ -170,6 +172,7 @@ impl Gamedata { let tile_names = RwLock::new(Vec::new()); 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(); @@ -238,6 +241,9 @@ impl Gamedata { .get(&tile) .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)?); + } 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))); @@ -257,6 +263,14 @@ 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 { demands, tile_collide, @@ -265,7 +279,7 @@ impl Gamedata { map_names: HashSet::new(), initial_map, item_names, - entities: map_in.entities, + entities, tile_names, chef_spawn, customer_spawn, diff --git a/server/src/entity/conveyor.rs b/server/src/entity/conveyor.rs index b74c03ef..48d0d154 100644 --- a/server/src/entity/conveyor.rs +++ b/server/src/entity/conveyor.rs @@ -1,4 +1,4 @@ -use super::Entity; +use super::EntityT; use crate::{ data::Gamedata, game::{interact_effect, Tile}, @@ -8,7 +8,7 @@ use anyhow::{anyhow, Result}; use glam::IVec2; use std::collections::{HashMap, VecDeque}; -#[derive(Debug, Default)] +#[derive(Debug, Default, Clone)] pub struct Conveyor { pub(super) from: IVec2, pub(super) to: IVec2, @@ -16,7 +16,7 @@ pub struct Conveyor { pub(super) max_cooldown: f32, } -impl Entity for Conveyor { +impl EntityT for Conveyor { fn tick( &mut self, data: &Gamedata, @@ -46,6 +46,7 @@ impl Entity for Conveyor { Some(to.kind), packet_out, points, + true, ); } diff --git a/server/src/entity/mod.rs b/server/src/entity/mod.rs index 089c60a5..d286d3bb 100644 --- a/server/src/entity/mod.rs +++ b/server/src/entity/mod.rs @@ -1,15 +1,12 @@ pub mod conveyor; - use crate::{data::Gamedata, game::Tile, protocol::PacketC}; -use anyhow::Result; +use anyhow::{anyhow, Result}; use conveyor::Conveyor; use glam::IVec2; use serde::{Deserialize, Serialize}; use std::collections::{HashMap, VecDeque}; -pub type DynEntity = Box<dyn Entity + Send + Sync + 'static>; - -pub trait Entity { +pub trait EntityT: Clone { fn tick( &mut self, data: &Gamedata, @@ -20,23 +17,54 @@ pub trait Entity { ) -> 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), + } + } +} + #[derive(Debug, Clone, Deserialize, Serialize)] #[serde(rename_all = "snake_case")] pub enum EntityDecl { Conveyor { - from: IVec2, - to: IVec2, + from: Option<IVec2>, + to: Option<IVec2>, + dir: Option<IVec2>, speed: Option<f32>, }, } -pub fn construct_entity(decl: &EntityDecl) -> DynEntity { - match decl.to_owned() { - EntityDecl::Conveyor { from, to, speed } => Box::new(Conveyor { +pub fn construct_entity(pos: Option<IVec2>, decl: &EntityDecl) -> Result<Entity> { + Ok(match decl.to_owned() { + EntityDecl::Conveyor { from, to, - max_cooldown: 1. / speed.unwrap_or(2.), - ..Default::default() - }), - } + speed, + dir, + } => { + let from = from.or(pos).ok_or(anyhow!("conveyor has no start"))?; + let to = to + .or(dir.map(|s| s + from)) + .ok_or(anyhow!("conveyor has no destination"))?; + Entity::Conveyor(Conveyor { + from, + to, + max_cooldown: 1. / speed.unwrap_or(2.), + ..Default::default() + }) + } + }) } diff --git a/server/src/game.rs b/server/src/game.rs index 7609b965..e8d307db 100644 --- a/server/src/game.rs +++ b/server/src/game.rs @@ -18,7 +18,7 @@ use crate::{ customer::DemandState, data::Gamedata, - entity::{construct_entity, DynEntity}, + entity::{Entity, EntityT}, interaction::{interact, tick_slot, InteractEffect, TickEffect}, protocol::{ ItemIndex, ItemLocation, Message, PacketC, PacketS, PlayerID, RecipeIndex, TileIndex, @@ -69,7 +69,7 @@ pub struct Game { packet_out: VecDeque<PacketC>, demand: Option<DemandState>, pub points: i64, - entities: Vec<DynEntity>, + entities: Vec<Entity>, end: Option<Instant>, } @@ -117,12 +117,7 @@ impl Game { self.data = gamedata.into(); self.points = 0; self.end = timer.map(|dur| Instant::now() + dur); - self.entities = self - .data - .entities - .iter() - .map(|decl| construct_entity(decl)) - .collect(); + self.entities = self.data.entities.clone(); for (&p, (tile, item)) in &self.data.initial_map { self.tiles.insert( @@ -364,6 +359,7 @@ impl Game { None, &mut self.packet_out, &mut self.points, + false, ) } else { let player = self @@ -381,6 +377,7 @@ impl Game { Some(tile.kind), &mut self.packet_out, &mut self.points, + false, ) } } @@ -523,11 +520,12 @@ pub fn interact_effect( this_tile_kind: Option<TileIndex>, packet_out: &mut VecDeque<PacketC>, points: &mut i64, + automated: bool, ) { let this_had_item = this.is_some(); let other_had_item = other.is_some(); - if let Some(effect) = interact(&data, edge, this_tile_kind, this, other, points) { + if let Some(effect) = interact(&data, edge, this_tile_kind, this, other, points, automated) { match effect { InteractEffect::Put => packet_out.push_back(PacketC::MoveItem { from: other_loc, diff --git a/server/src/interaction.rs b/server/src/interaction.rs index 85df9925..bca480f5 100644 --- a/server/src/interaction.rs +++ b/server/src/interaction.rs @@ -122,10 +122,12 @@ pub fn interact( this: &mut Option<Item>, other: &mut Option<Item>, points: &mut i64, + automated: bool, ) -> Option<InteractEffect> { - let interactable = tile - .map(|tile| data.is_tile_interactable(tile)) - .unwrap_or(true); + let interactable = automated + || tile + .map(|tile| data.is_tile_interactable(tile)) + .unwrap_or(true); if interactable && other.is_none() { if let Some(item) = this { if let Some(active) = &mut item.active { diff --git a/server/src/lib.rs b/server/src/lib.rs index 890e5148..96fb954a 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -15,11 +15,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ -#![feature(if_let_guard, map_many_mut, let_chains)] +#![feature(if_let_guard, map_many_mut, let_chains, iterator_try_collect)] pub mod customer; pub mod data; +pub mod entity; pub mod game; pub mod interaction; pub mod protocol; pub mod state; -pub mod entity; diff --git a/test-client/main.ts b/test-client/main.ts index c4db6935..04d1a5b4 100644 --- a/test-client/main.ts +++ b/test-client/main.ts @@ -98,7 +98,7 @@ export const players = new Map<PlayerID, PlayerData>() export const tiles = new Map<string, TileData>() export const items_removed = new Set<ItemData>() -export let data: Gamedata = { item_names: [], tile_names: [], spawn: [0, 0], tile_collide: [], tile_interact: [] } +export let data: Gamedata = { item_names: [], tile_names: [], spawn: [0, 0], tile_collide: [], tile_interact: [], map_names: [] } export let time_remaining: number | null = null export let global_message: MessageData | undefined = undefined @@ -245,6 +245,7 @@ function keyboard(ev: KeyboardEvent, down: boolean) { if (down && ev.code == "Numpad2") send({ type: "communicate", message: { text: "/start small" }, persist: false }) if (down && ev.code == "Numpad3") send({ type: "communicate", message: { text: "/start big" }, persist: false }) if (down && ev.code == "Numpad4") send({ type: "communicate", message: { text: "/start test" }, persist: false }) + if (down && ev.code == "Numpad5") send({ type: "communicate", message: { text: "/start bus" }, persist: false }) if (down && ev.code == "Numpad0") send({ type: "communicate", message: { text: "/end" }, persist: false }) if (down) keys_down.add(ev.code) else keys_down.delete(ev.code) @@ -319,7 +320,7 @@ function frame_update(dt: number) { if (tile.item !== undefined && tile.item !== null) update_item(tile.item) } - const remove = [] + const remove: ItemData[] = [] for (const item of items_removed) { update_item(item) if (item.remove_anim === undefined) item.remove_anim = 0 diff --git a/test-client/tiles.ts b/test-client/tiles.ts index da5b0761..5ecc1fad 100644 --- a/test-client/tiles.ts +++ b/test-client/tiles.ts @@ -170,6 +170,7 @@ export const TILES: { [key: string]: Component[] } = { "counter-window": [base("rgb(233, 233, 233)")], "grass": [base("rgb(0, 107, 4)")], "path": [base("rgb(100, 80, 55)")], + "conveyor": [base("rgb(107, 62, 128)")], "tree": [base("rgb(1, 82, 4)")], "cuttingboard": [...counter, rect(0.3, "rgb(158, 236, 68)", "rgb(158, 236, 68)", 0.2)], "trash": [...floor, circle(0.4, "rgb(20, 20, 20)"), cross(0.3, "rgb(90, 36, 36)")], |