diff options
author | metamuffin <metamuffin@disroot.org> | 2024-06-20 01:38:00 +0200 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2024-06-23 19:21:49 +0200 |
commit | 720bb2e4f53d4467832ba59f97c9b6b6786181e7 (patch) | |
tree | 10ea600436adf2c101d9a1ccbf64808414bbc354 | |
parent | 6f7b995dd9fa3bea95be8c24e2452f015b410839 (diff) | |
download | hurrycurry-720bb2e4f53d4467832ba59f97c9b6b6786181e7.tar hurrycurry-720bb2e4f53d4467832ba59f97c9b6b6786181e7.tar.bz2 hurrycurry-720bb2e4f53d4467832ba59f97c9b6b6786181e7.tar.zst |
type safe indecies
-rw-r--r-- | data/demands.yaml | 10 | ||||
-rw-r--r-- | server/src/customer/mod.rs | 58 | ||||
-rw-r--r-- | server/src/data.rs | 65 | ||||
-rw-r--r-- | server/src/game.rs | 4 | ||||
-rw-r--r-- | server/src/interaction.rs | 16 | ||||
-rw-r--r-- | server/src/main.rs | 8 | ||||
-rw-r--r-- | server/src/protocol.rs | 21 | ||||
-rw-r--r-- | test-client/main.ts | 1 |
8 files changed, 112 insertions, 71 deletions
diff --git a/data/demands.yaml b/data/demands.yaml index 6862395e..d819f517 100644 --- a/data/demands.yaml +++ b/data/demands.yaml @@ -1,5 +1,5 @@ -- { from: burger-meal, to: dirty-dish } -- { from: tomatoburger-meal, to: dirty-dish } -- { from: tomatosteak-meal, to: dirty-dish } -- { from: steak-meal, to: dirty-dish } -- { from: sliced-tomato-mea, to: dirty-dish } +- { from: burger-meal, to: dirty-plate } +- { from: tomatoburger-meal, to: dirty-plate } +- { from: tomatosteak-meal, to: dirty-plate } +- { from: steak-meal, to: dirty-plate } +- { from: sliced-tomato-mea, to: dirty-plate } diff --git a/server/src/customer/mod.rs b/server/src/customer/mod.rs index ecd99250..4c557d41 100644 --- a/server/src/customer/mod.rs +++ b/server/src/customer/mod.rs @@ -47,7 +47,7 @@ struct Customer { pub async fn customer(game: Arc<RwLock<Game>>, mut grx: broadcast::Receiver<PacketC>) { let mut state = CustomerManager { - customer_id_counter: 0, + customer_id_counter: PlayerID(0), walkable: Default::default(), chairs: Default::default(), items: Default::default(), @@ -56,14 +56,14 @@ pub async fn customer(game: Arc<RwLock<Game>>, mut grx: broadcast::Receiver<Pack data: Gamedata::default(), }, }; - let initial = game.write().await.prime_client(-1); + let initial = game.write().await.prime_client(PlayerID(-1)); for p in initial { match p { PacketC::Init { data, .. } => { state.demand.data = data; } PacketC::UpdateMap { pos, tile, .. } => { - let tilename = &state.demand.data.tile_names[tile]; + let tilename = state.demand.data.tile_name(tile); if tilename == "floor" || tilename == "door" || tilename == "chair" { state.walkable.insert(pos); } @@ -119,14 +119,14 @@ impl DemandState { pub fn generate_demand(&self) -> DemandIndex { // TODO insert sofa magic formula - random::<usize>() % self.data.demands.len() + DemandIndex(random::<usize>() % self.data.demands.len()) } } impl CustomerManager { pub fn tick(&mut self, packets_out: &mut Vec<(PlayerID, PacketS)>, dt: f32) { if self.customers.len() < self.demand.target_customer_count() { - self.customer_id_counter -= 1; + self.customer_id_counter.0 -= 1; let id = self.customer_id_counter; packets_out.push(( id, @@ -164,7 +164,7 @@ impl CustomerManager { packets_out.push(( id, PacketS::Communicate { - message: Some(Message::Item(self.demand.data.demands[demand].from)), + message: Some(Message::Item(self.demand.data.demand(demand).from)), }, )); p.state = CustomerState::Waiting { @@ -174,41 +174,39 @@ impl CustomerManager { } } CustomerState::Waiting { chair, demand } => { + let demand = &self.demand.data.demand(*demand); let demand_pos = [IVec2::NEG_X, IVec2::NEG_Y, IVec2::X, IVec2::Y] .into_iter() .find_map(|off| { let pos = *chair + off; - if self.items.get(&pos) == Some(demand) { + if self.items.get(&pos) == Some(&demand.from) { Some(pos) } else { None } }); if let Some(pos) = demand_pos { - let demand = &self.demand.data.demands[*demand]; - if self.items.get(&pos) == Some(&demand.from) { - packets_out.push((id, PacketS::Communicate { message: None })); - for edge in [true, false] { - packets_out.push((id, PacketS::Interact { pos, edge })) - } - packets_out.push(( - id, - PacketS::ReplaceHand { - item: Some(demand.to), - }, - )); - for edge in [true, false] { - packets_out.push((id, PacketS::Interact { pos, edge })) - } - let path = find_path( - &self.walkable, - p.movement.position.as_ivec2(), - self.demand.data.customer_spawn.as_ivec2(), - ) - .expect("no path to exit"); - *self.chairs.get_mut(&chair).unwrap() = true; - p.state = CustomerState::Exiting { path } + packets_out.push((id, PacketS::Communicate { message: None })); + for edge in [true, false] { + packets_out.push((id, PacketS::Interact { pos, edge })) + } + packets_out.push(( + id, + PacketS::ReplaceHand { + item: Some(demand.to), + }, + )); + for edge in [true, false] { + packets_out.push((id, PacketS::Interact { pos, edge })) } + let path = find_path( + &self.walkable, + p.movement.position.as_ivec2(), + self.demand.data.customer_spawn.as_ivec2(), + ) + .expect("no path to exit"); + *self.chairs.get_mut(&chair).unwrap() = true; + p.state = CustomerState::Exiting { path } } debug!("waiting") } diff --git a/server/src/data.rs b/server/src/data.rs index e467fefa..51347c7c 100644 --- a/server/src/data.rs +++ b/server/src/data.rs @@ -1,4 +1,7 @@ -use crate::{interaction::Recipe, protocol::TileIndex}; +use crate::{ + interaction::Recipe, + protocol::{DemandIndex, ItemIndex, RecipeIndex, TileIndex}, +}; use glam::{IVec2, Vec2}; use serde::{Deserialize, Serialize}; use std::{collections::HashMap, sync::RwLock}; @@ -39,16 +42,16 @@ pub struct DemandDecl { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Demand { - pub from: usize, - pub to: usize, + pub from: ItemIndex, + pub to: ItemIndex, } #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct Gamedata { - pub recipes: Vec<Recipe>, + recipes: Vec<Recipe>, pub demands: Vec<Demand>, - pub item_names: Vec<String>, - pub tile_names: Vec<String>, + item_names: Vec<String>, + tile_names: Vec<String>, #[serde(skip)] pub initial_map: HashMap<IVec2, TileIndex>, pub chef_spawn: Vec2, @@ -67,9 +70,15 @@ pub fn build_gamedata( for r in recipes_in { let r2 = r.clone(); - let mut inputs = r.inputs.into_iter().map(|i| register(&item_names, i)); - let mut outputs = r.outputs.into_iter().map(|o| register(&item_names, o)); - let tile = r.tile.map(|t| register(&tile_names, t)); + 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))); match r.action { Action::Never => {} Action::Passive(duration) => recipes.push(Recipe::Passive { @@ -98,8 +107,8 @@ pub fn build_gamedata( for d in demands_in { demands.push(Demand { - from: register(&item_names, d.from), - to: register(&item_names, d.to), + from: ItemIndex(register(&item_names, d.from)), + to: ItemIndex(register(&item_names, d.to)), }) } @@ -118,7 +127,7 @@ pub fn build_gamedata( customer_spawn = pos.as_vec2(); tilename = "floor".to_owned(); } - let tile = register(&tile_names, tilename); + let tile = TileIndex(register(&tile_names, tilename)); initial_map.insert(pos, tile); } } @@ -146,11 +155,35 @@ fn register(db: &RwLock<Vec<String>>, name: String) -> usize { } impl Gamedata { - pub fn get_tile(&self, name: &str) -> Option<TileIndex> { - self.tile_names.iter().position(|t| t == name) + pub fn tile_name(&self, index: TileIndex) -> &String { + &self.tile_names[index.0] } - pub fn get_item(&self, name: &str) -> Option<TileIndex> { - self.item_names.iter().position(|t| t == name) + pub fn item_name(&self, index: ItemIndex) -> &String { + &self.item_names[index.0] + } + pub fn recipe(&self, index: RecipeIndex) -> &Recipe { + &self.recipes[index.0] + } + pub fn demand(&self, index: DemandIndex) -> &Demand { + &self.demands[index.0] + } + pub fn get_tile_by_name(&self, name: &str) -> Option<TileIndex> { + self.tile_names + .iter() + .position(|t| t == name) + .map(TileIndex) + } + pub fn get_item_by_name(&self, name: &str) -> Option<ItemIndex> { + self.item_names + .iter() + .position(|t| t == name) + .map(ItemIndex) + } + pub fn recipes(&self) -> impl Iterator<Item = (RecipeIndex, &Recipe)> { + self.recipes + .iter() + .enumerate() + .map(|(i, e)| (RecipeIndex(i), e)) } } impl Action { diff --git a/server/src/game.rs b/server/src/game.rs index b48e1833..e4693e4a 100644 --- a/server/src/game.rs +++ b/server/src/game.rs @@ -123,7 +123,7 @@ impl Game { Player { item: None, character, - position: if player < 0 { + position: if player.0 < 0 { self.data.customer_spawn } else { self.data.chef_spawn @@ -246,7 +246,7 @@ impl Game { player.interacting = if edge { Some(pos) } else { None }; } PacketS::Communicate { message } => { - info!("{player} message {message:?}"); + info!("{player:?} message {message:?}"); if let Some(player) = self.players.get_mut(&player) { player.communicate = message.clone() } diff --git a/server/src/interaction.rs b/server/src/interaction.rs index d822340f..a4b79bd0 100644 --- a/server/src/interaction.rs +++ b/server/src/interaction.rs @@ -70,7 +70,7 @@ pub fn interact( if player.item.is_none() { if let Some(item) = &mut tile.item { if let Some(active) = &mut item.active { - let recipe = &data.recipes[active.recipe]; + let recipe = &data.recipe(active.recipe); if recipe.supports_tile(tile.kind) { if let Recipe::Active { outputs, .. } = recipe { if edge { @@ -92,7 +92,7 @@ pub fn interact( return None; } - for (ri, recipe) in data.recipes.iter().enumerate() { + for (ri, recipe) in data.recipes() { if !recipe.supports_tile(tile.kind) { continue; } @@ -102,7 +102,7 @@ pub fn interact( if let Some(item) = &mut tile.item { if item.kind == *input { if item.active.is_none() { - info!("start active recipe {ri}"); + info!("start active recipe {ri:?}"); item.active = Some(Involvement { recipe: ri, working: 1, @@ -119,7 +119,7 @@ pub fn interact( if let Some(active) = &mut item.active { active.working += 1; } else { - info!("start active recipe {ri}"); + info!("start active recipe {ri:?}"); item.active = Some(Involvement { recipe: ri, working: 1, @@ -140,7 +140,7 @@ pub fn interact( let ok = (inputs[0] == on_tile && inputs[1] == in_hand) || (inputs[1] == on_tile && inputs[0] == in_hand); if ok { - info!("instant recipe {ri}"); + info!("instant recipe {ri:?}"); player.item = outputs[0].map(|kind| Item { kind, active: None }); tile.item = outputs[1].map(|kind| Item { kind, active: None }); return Some(InteractEffect::Produce); @@ -173,11 +173,11 @@ pub enum TickEffect { pub fn tick_tile(dt: f32, data: &Gamedata, tile: &mut Tile) -> Option<TickEffect> { if let Some(item) = &mut tile.item { if let Some(a) = &mut item.active { - let r = &data.recipes[a.recipe]; + let r = &data.recipe(a.recipe); if r.supports_tile(tile.kind) { a.progress += a.working as f32 * dt / r.duration().unwrap(); if a.progress >= 1. { - if let Recipe::Passive { output, .. } = &data.recipes[a.recipe] { + if let Recipe::Passive { output, .. } = &data.recipe(a.recipe) { tile.item = output.map(|kind| Item { kind, active: None }); return Some(TickEffect::Produce); }; @@ -186,7 +186,7 @@ pub fn tick_tile(dt: f32, data: &Gamedata, tile: &mut Tile) -> Option<TickEffect return Some(TickEffect::Progress); } } else { - for (ri, recipe) in data.recipes.iter().enumerate() { + for (ri, recipe) in data.recipes() { if let Some(tile_constraint) = recipe.tile() { if tile.kind != tile_constraint { continue; diff --git a/server/src/main.rs b/server/src/main.rs index 4d761b0c..3af71e17 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -14,7 +14,7 @@ use undercooked::{ customer::customer, data::build_gamedata, game::Game, - protocol::{PacketC, PacketS}, + protocol::{PacketC, PacketS, PlayerID}, }; #[tokio::main] @@ -57,7 +57,7 @@ async fn main() -> Result<()> { spawn(customer(game.clone(), rx.resubscribe())); - for id in 1.. { + for id in (1..).map(PlayerID) { tokio::select! { r = raw_listener.accept() => { let (sock, addr) = r?; @@ -88,7 +88,7 @@ async fn main() -> Result<()> { warn!("invalid json over tcp"); break }; - debug!("<- {id} {packet:?}"); + debug!("<- {id:?} {packet:?}"); if let Err(e) = game.write().await.packet_in(id, packet) { warn!("client error: {e}"); } @@ -133,7 +133,7 @@ async fn main() -> Result<()> { warn!("invalid json over ws"); break }; - debug!("<- {id} {packet:?}"); + debug!("<- {id:?} {packet:?}"); if let Err(e) = game.write().await.packet_in(id, packet) { warn!("client error: {e}"); } diff --git a/server/src/protocol.rs b/server/src/protocol.rs index 24fe2468..a629ffbf 100644 --- a/server/src/protocol.rs +++ b/server/src/protocol.rs @@ -2,11 +2,22 @@ use crate::data::Gamedata; use glam::{IVec2, Vec2}; use serde::{Deserialize, Serialize}; -pub type PlayerID = i64; -pub type ItemIndex = usize; -pub type TileIndex = usize; -pub type RecipeIndex = usize; -pub type DemandIndex = usize; +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[serde(transparent)] +pub struct PlayerID(pub i64); + +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[serde(transparent)] +pub struct ItemIndex(pub usize); +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[serde(transparent)] +pub struct TileIndex(pub usize); +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[serde(transparent)] +pub struct RecipeIndex(pub usize); +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[serde(transparent)] +pub struct DemandIndex(pub usize); #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "snake_case", tag = "type")] diff --git a/test-client/main.ts b/test-client/main.ts index fd49fca2..9cafa1f6 100644 --- a/test-client/main.ts +++ b/test-client/main.ts @@ -227,7 +227,6 @@ function frame_update(dt: number) { } remove.forEach(i => items_removed.delete(i)) - lerp_exp_v2_mut(interact_target_anim, get_interact_target() ?? { x: 0, y: 0 }, dt * 15.) lerp_exp_v2_mut(camera, p, dt * 10.) } |