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 a2dc8842..37229844 100644 --- a/data/index.yaml +++ b/data/index.yaml @@ -14,6 +14,7 @@ maps:      - depot      - line      - teeny +    - bus      - rivalry      - village      - zigzag 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)")], | 
