diff options
Diffstat (limited to 'server/src/entity')
-rw-r--r-- | server/src/entity/conveyor.rs | 29 | ||||
-rw-r--r-- | server/src/entity/customers/mod.rs | 368 | ||||
-rw-r--r-- | server/src/entity/environment_effect.rs | 38 | ||||
-rw-r--r-- | server/src/entity/item_portal.rs | 25 | ||||
-rw-r--r-- | server/src/entity/mod.rs | 16 | ||||
-rw-r--r-- | server/src/entity/player_portal.rs | 24 |
6 files changed, 245 insertions, 255 deletions
diff --git a/server/src/entity/conveyor.rs b/server/src/entity/conveyor.rs index b370356c..f7f091c7 100644 --- a/server/src/entity/conveyor.rs +++ b/server/src/entity/conveyor.rs @@ -1,5 +1,3 @@ -use std::collections::VecDeque; - /* Hurry Curry! - a game about cooking Copyright 2024 metamuffin @@ -17,10 +15,10 @@ use std::collections::VecDeque; along with this program. If not, see <https://www.gnu.org/licenses/>. */ -use super::EntityT; -use crate::game::{interact_effect, Game}; +use super::{EntityContext, EntityT}; +use crate::server::interact_effect; use anyhow::{anyhow, Result}; -use hurrycurry_protocol::{glam::IVec2, ItemIndex, ItemLocation, PacketC}; +use hurrycurry_protocol::{glam::IVec2, ItemIndex, ItemLocation}; #[derive(Debug, Clone)] pub struct Conveyor { @@ -33,15 +31,17 @@ pub struct Conveyor { } impl EntityT for Conveyor { - fn tick(&mut self, game: &mut Game, packet_out: &mut VecDeque<PacketC>, dt: f32) -> Result<()> { - let from = game + fn tick(&mut self, c: EntityContext) -> Result<()> { + let from = c + .game .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 = game + let filter_tile = c + .game .tiles .get(t) .ok_or(anyhow!("conveyor filter missing"))?; @@ -56,28 +56,29 @@ impl EntityT for Conveyor { } } - self.cooldown += dt; + self.cooldown += c.dt; if self.cooldown < self.max_cooldown { return Ok(()); } self.cooldown = 0.; - let [from, to] = game + let [from, to] = c + .game .tiles .get_many_mut([&self.from, &self.to]) .ok_or(anyhow!("conveyor does ends in itself"))?; interact_effect( - &game.data, + &c.game.data, true, &mut to.item, ItemLocation::Tile(self.to), &mut from.item, ItemLocation::Tile(self.from), Some(to.kind), - packet_out, - &mut game.score, - &mut game.score_changed, + c.packet_out, + &mut c.game.score, + c.score_changed, true, ); } diff --git a/server/src/entity/customers/mod.rs b/server/src/entity/customers/mod.rs index 221351a5..85da2c07 100644 --- a/server/src/entity/customers/mod.rs +++ b/server/src/entity/customers/mod.rs @@ -18,8 +18,8 @@ pub mod demands; mod pathfinding; -use super::EntityT; -use crate::{data::Demand, game::Game}; +use super::{EntityContext, EntityT}; +use crate::{data::Demand, server::Server}; use anyhow::{anyhow, bail, Result}; use fake::{faker, Fake}; use hurrycurry_protocol::{glam::IVec2, DemandIndex, Message, PacketC, PacketS, PlayerID}; @@ -75,190 +75,190 @@ impl Customers { } impl EntityT for Customers { - fn tick(&mut self, game: &mut Game, packet_out: &mut VecDeque<PacketC>, dt: f32) -> Result<()> { - self.spawn_cooldown -= dt; - self.spawn_cooldown = self.spawn_cooldown.max(0.); - if self.customers.len() < 5 && self.spawn_cooldown <= 0. { - self.spawn_cooldown = 10. + random::<f32>() * 10.; - let id = game.join_player( - faker::name::fr_fr::Name().fake(), - -1 - (random::<u16>() as i32), - packet_out, - ); + fn tick(&mut self, c: EntityContext) -> Result<()> { + // self.spawn_cooldown -= dt; + // self.spawn_cooldown = self.spawn_cooldown.max(0.); + // if self.customers.len() < 5 && self.spawn_cooldown <= 0. { + // self.spawn_cooldown = 10. + random::<f32>() * 10.; + // let id = game.join_player( + // faker::name::fr_fr::Name().fake(), + // -1 - (random::<u16>() as i32), + // packet_out, + // ); - let chair = self.select_chair().ok_or(anyhow!("no free chair found"))?; - let from = game.data.customer_spawn.as_ivec2(); - let path = find_path(&game.walkable, from, chair) - .ok_or(anyhow!("no path from {from} to {chair}"))?; - info!("{id:?} -> entering"); - self.customers - .insert(id, CustomerState::Entering { path, chair }); - } - let mut customers_to_remove = Vec::new(); - for (&player, state) in &mut self.customers { - let Some(playerdata) = game.players.get_mut(&player) else { - continue; - }; + // let chair = self.select_chair().ok_or(anyhow!("no free chair found"))?; + // let from = game.data.customer_spawn.as_ivec2(); + // let path = find_path(&game.walkable, from, chair) + // .ok_or(anyhow!("no path from {from} to {chair}"))?; + // info!("{id:?} -> entering"); + // self.customers + // .insert(id, CustomerState::Entering { path, chair }); + // } + // let mut customers_to_remove = Vec::new(); + // for (&player, state) in &mut self.customers { + // let Some(playerdata) = game.players.get_mut(&player) else { + // continue; + // }; - match state { - CustomerState::Entering { path, chair } => { - playerdata - .movement - .input(path.next_direction(playerdata.position()), false); - if path.is_done() { - let demand = DemandIndex(random::<u32>() as usize % self.demands.len()); - self.cpackets.push_back(PacketS::Communicate { - message: Some(Message::Item(self.demands[demand.0].from)), - persist: true, - player, - }); - info!("{player:?} -> waiting"); - *state = CustomerState::Waiting { - chair: *chair, - timeout: 90. + random::<f32>() * 60., - demand, - }; - } - } - CustomerState::Waiting { - chair, - demand, - timeout, - } => { - playerdata - .movement - .input((chair.as_vec2() + 0.5) - playerdata.position(), false); - *timeout -= dt; - if *timeout <= 0. { - self.cpackets.push_back(PacketS::Communicate { - message: None, - persist: true, - player, - }); - self.cpackets.push_back(PacketS::Communicate { - message: Some(Message::Effect("angry".to_string())), - persist: false, - player, - }); - let path = find_path( - &game.walkable, - playerdata.position().as_ivec2(), - game.data.customer_spawn.as_ivec2(), - ) - .expect("no path to exit"); - *self.chairs.get_mut(chair).unwrap() = true; - game.score.demands_failed += 1; - game.score.points -= 1; - game.score_changed = true; - info!("{player:?} -> exiting"); - *state = CustomerState::Exiting { path } - } else { - let demand_data = &self.demands[demand.0]; - let demand_pos = [IVec2::NEG_X, IVec2::NEG_Y, IVec2::X, IVec2::Y] - .into_iter() - .find_map(|off| { - let pos = *chair + off; - if game - .tiles - .get(&pos) - .map(|t| { - t.item - .as_ref() - .map(|i| i.kind == demand_data.from) - .unwrap_or_default() - }) - .unwrap_or_default() - { - Some(pos) - } else { - None - } - }); - if let Some(pos) = demand_pos { - self.cpackets.push_back(PacketS::Communicate { - persist: true, - message: None, - player, - }); - self.cpackets.push_back(PacketS::Communicate { - message: Some(Message::Effect("satisfied".to_string())), - persist: false, - player, - }); - self.cpackets.push_back(PacketS::Interact { - pos: Some(pos), - player, - }); - self.cpackets - .push_back(PacketS::Interact { pos: None, player }); - info!("{player:?} -> eating"); - *state = CustomerState::Eating { - demand: *demand, - target: pos, - progress: 0., - chair: *chair, - } - } - } - } - CustomerState::Eating { - demand, - target, - progress, - chair, - } => { - playerdata - .movement - .input((chair.as_vec2() + 0.5) - playerdata.position(), false); - let demand = &self.demands[demand.0]; - *progress += dt / demand.duration; - if *progress >= 1. { - self.cpackets.push_back(PacketS::ReplaceHand { - player, - item: demand.to, - }); - if demand.to.is_some() { - self.cpackets.push_back(PacketS::Interact { - player, - pos: Some(*target), - }); - self.cpackets - .push_back(PacketS::Interact { player, pos: None }); - } - let path = find_path( - &game.walkable, - playerdata.position().as_ivec2(), - game.data.customer_spawn.as_ivec2(), - ) - .ok_or(anyhow!("no path to exit"))?; - *self.chairs.get_mut(chair).unwrap() = true; - game.score.demands_completed += 1; - game.score.points += demand.points; - game.score_changed = true; - info!("{player:?} -> exiting"); - *state = CustomerState::Exiting { path } - } - } - CustomerState::Exiting { path } => { - playerdata - .movement - .input(path.next_direction(playerdata.position()), false); - if path.is_done() { - info!("{player:?} -> leave"); - self.cpackets.push_back(PacketS::Leave { player }); - customers_to_remove.push(player); - } - } - } - } - for c in customers_to_remove { - self.customers.remove(&c).unwrap(); - } - for packet in self.cpackets.drain(..) { - if let Err(err) = game.packet_in(packet, &mut vec![], packet_out) { - warn!("demand packet {err}"); - } - } + // match state { + // CustomerState::Entering { path, chair } => { + // playerdata + // .movement + // .input(path.next_direction(playerdata.position()), false); + // if path.is_done() { + // let demand = DemandIndex(random::<u32>() as usize % self.demands.len()); + // self.cpackets.push_back(PacketS::Communicate { + // message: Some(Message::Item(self.demands[demand.0].from)), + // persist: true, + // player, + // }); + // info!("{player:?} -> waiting"); + // *state = CustomerState::Waiting { + // chair: *chair, + // timeout: 90. + random::<f32>() * 60., + // demand, + // }; + // } + // } + // CustomerState::Waiting { + // chair, + // demand, + // timeout, + // } => { + // playerdata + // .movement + // .input((chair.as_vec2() + 0.5) - playerdata.position(), false); + // *timeout -= dt; + // if *timeout <= 0. { + // self.cpackets.push_back(PacketS::Communicate { + // message: None, + // persist: true, + // player, + // }); + // self.cpackets.push_back(PacketS::Communicate { + // message: Some(Message::Effect("angry".to_string())), + // persist: false, + // player, + // }); + // let path = find_path( + // &game.walkable, + // playerdata.position().as_ivec2(), + // game.data.customer_spawn.as_ivec2(), + // ) + // .expect("no path to exit"); + // *self.chairs.get_mut(chair).unwrap() = true; + // game.score.demands_failed += 1; + // game.score.points -= 1; + // game.score_changed = true; + // info!("{player:?} -> exiting"); + // *state = CustomerState::Exiting { path } + // } else { + // let demand_data = &self.demands[demand.0]; + // let demand_pos = [IVec2::NEG_X, IVec2::NEG_Y, IVec2::X, IVec2::Y] + // .into_iter() + // .find_map(|off| { + // let pos = *chair + off; + // if game + // .tiles + // .get(&pos) + // .map(|t| { + // t.item + // .as_ref() + // .map(|i| i.kind == demand_data.from) + // .unwrap_or_default() + // }) + // .unwrap_or_default() + // { + // Some(pos) + // } else { + // None + // } + // }); + // if let Some(pos) = demand_pos { + // self.cpackets.push_back(PacketS::Communicate { + // persist: true, + // message: None, + // player, + // }); + // self.cpackets.push_back(PacketS::Communicate { + // message: Some(Message::Effect("satisfied".to_string())), + // persist: false, + // player, + // }); + // self.cpackets.push_back(PacketS::Interact { + // pos: Some(pos), + // player, + // }); + // self.cpackets + // .push_back(PacketS::Interact { pos: None, player }); + // info!("{player:?} -> eating"); + // *state = CustomerState::Eating { + // demand: *demand, + // target: pos, + // progress: 0., + // chair: *chair, + // } + // } + // } + // } + // CustomerState::Eating { + // demand, + // target, + // progress, + // chair, + // } => { + // playerdata + // .movement + // .input((chair.as_vec2() + 0.5) - playerdata.position(), false); + // let demand = &self.demands[demand.0]; + // *progress += dt / demand.duration; + // if *progress >= 1. { + // self.cpackets.push_back(PacketS::ReplaceHand { + // player, + // item: demand.to, + // }); + // if demand.to.is_some() { + // self.cpackets.push_back(PacketS::Interact { + // player, + // pos: Some(*target), + // }); + // self.cpackets + // .push_back(PacketS::Interact { player, pos: None }); + // } + // let path = find_path( + // &game.walkable, + // playerdata.position().as_ivec2(), + // game.data.customer_spawn.as_ivec2(), + // ) + // .ok_or(anyhow!("no path to exit"))?; + // *self.chairs.get_mut(chair).unwrap() = true; + // game.score.demands_completed += 1; + // game.score.points += demand.points; + // game.score_changed = true; + // info!("{player:?} -> exiting"); + // *state = CustomerState::Exiting { path } + // } + // } + // CustomerState::Exiting { path } => { + // playerdata + // .movement + // .input(path.next_direction(playerdata.position()), false); + // if path.is_done() { + // info!("{player:?} -> leave"); + // self.cpackets.push_back(PacketS::Leave { player }); + // customers_to_remove.push(player); + // } + // } + // } + // } + // for c in customers_to_remove { + // self.customers.remove(&c).unwrap(); + // } + // for packet in self.cpackets.drain(..) { + // if let Err(err) = game.packet_in(packet, &mut vec![], packet_out) { + // warn!("demand packet {err}"); + // } + // } Ok(()) } } diff --git a/server/src/entity/environment_effect.rs b/server/src/entity/environment_effect.rs index f369bce4..8f54d29c 100644 --- a/server/src/entity/environment_effect.rs +++ b/server/src/entity/environment_effect.rs @@ -15,15 +15,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ -use super::EntityT; -use crate::game::Game; +use super::{EntityContext, EntityT}; use hurrycurry_protocol::PacketC; use rand::random; use serde::{Deserialize, Serialize}; -use std::{ - collections::VecDeque, - time::{Duration, Instant}, -}; +use std::time::{Duration, Instant}; #[derive(Clone, Debug, Deserialize, Serialize, Default)] pub struct EnvironmentEffect { @@ -54,26 +50,21 @@ impl EnvironmentEffectController { } } impl EntityT for EnvironmentEffectController { - fn tick( - &mut self, - game: &mut Game, - packet_out: &mut VecDeque<PacketC>, - _dt: f32, - ) -> anyhow::Result<()> { + fn tick(&mut self, c: EntityContext) -> anyhow::Result<()> { if self.next_transition < Instant::now() { if self.active { self.next_transition += Duration::from_secs_f32(self.config.on + (0.5 + random::<f32>())); self.active = false; - game.environment_effects.remove(&self.config.name); + c.game.environment_effects.remove(&self.config.name); } else { self.next_transition += Duration::from_secs_f32(self.config.off * (0.5 + random::<f32>())); self.active = true; - game.environment_effects.insert(self.config.name.clone()); + c.game.environment_effects.insert(self.config.name.clone()); } - packet_out.push_back(PacketC::Environment { - effects: game.environment_effects.clone(), + c.packet_out.push_back(PacketC::Environment { + effects: c.game.environment_effects.clone(), }) } Ok(()) @@ -83,16 +74,11 @@ impl EntityT for EnvironmentEffectController { #[derive(Debug, Clone)] pub struct EnvironmentController(pub Vec<String>); impl EntityT for EnvironmentController { - fn tick( - &mut self, - game: &mut Game, - packet_out: &mut VecDeque<PacketC>, - _dt: f32, - ) -> anyhow::Result<()> { - if game.environment_effects.is_empty() { - game.environment_effects.extend(self.0.clone()); - packet_out.push_back(PacketC::Environment { - effects: game.environment_effects.clone(), + fn tick(&mut self, c: EntityContext) -> anyhow::Result<()> { + if c.game.environment_effects.is_empty() { + c.game.environment_effects.extend(self.0.clone()); + c.packet_out.push_back(PacketC::Environment { + effects: c.game.environment_effects.clone(), }) } Ok(()) diff --git a/server/src/entity/item_portal.rs b/server/src/entity/item_portal.rs index f63ff274..be6acd06 100644 --- a/server/src/entity/item_portal.rs +++ b/server/src/entity/item_portal.rs @@ -15,11 +15,10 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ -use super::EntityT; -use crate::game::{interact_effect, Game}; +use super::{EntityContext, EntityT}; +use crate::server::interact_effect; use anyhow::{anyhow, Result}; -use hurrycurry_protocol::{glam::IVec2, ItemLocation, PacketC}; -use std::collections::VecDeque; +use hurrycurry_protocol::{glam::IVec2, ItemLocation}; #[derive(Debug, Default, Clone)] pub struct ItemPortal { @@ -28,29 +27,25 @@ pub struct ItemPortal { } impl EntityT for ItemPortal { - fn tick( - &mut self, - game: &mut Game, - packet_out: &mut VecDeque<PacketC>, - _dt: f32, - ) -> Result<()> { - let [from, to] = game + fn tick(&mut self, c: EntityContext) -> Result<()> { + let [from, to] = c + .game .tiles .get_many_mut([&self.from, &self.to]) .ok_or(anyhow!("conveyor does ends in itself"))?; if from.item.is_some() { interact_effect( - &game.data, + &c.game.data, true, &mut to.item, ItemLocation::Tile(self.to), &mut from.item, ItemLocation::Tile(self.from), Some(to.kind), - packet_out, - &mut game.score, - &mut game.score_changed, + c.packet_out, + &mut c.game.score, + c.score_changed, true, ); } diff --git a/server/src/entity/mod.rs b/server/src/entity/mod.rs index 94718dd1..10d0c155 100644 --- a/server/src/entity/mod.rs +++ b/server/src/entity/mod.rs @@ -21,11 +21,12 @@ pub mod environment_effect; pub mod item_portal; pub mod player_portal; -use crate::{data::ItemTileRegistry, game::Game}; +use crate::data::ItemTileRegistry; use anyhow::{anyhow, Result}; use conveyor::Conveyor; use customers::{demands::generate_demands, Customers}; use environment_effect::{EnvironmentController, EnvironmentEffect, EnvironmentEffectController}; +use hurrycurry_client_lib::Game; use hurrycurry_protocol::{ glam::{IVec2, Vec2}, ItemIndex, PacketC, Recipe, TileIndex, @@ -35,8 +36,15 @@ use player_portal::PlayerPortal; use serde::{Deserialize, Serialize}; use std::collections::{HashMap, HashSet, VecDeque}; +pub struct EntityContext<'a> { + pub game: &'a mut Game, + pub packet_out: &'a mut VecDeque<PacketC>, + pub score_changed: &'a mut bool, + pub dt: f32, +} + pub trait EntityT: Clone { - fn tick(&mut self, game: &mut Game, packet_out: &mut VecDeque<PacketC>, dt: f32) -> Result<()>; + fn tick(&mut self, c: EntityContext<'_>) -> Result<()>; } macro_rules! entities { @@ -44,8 +52,8 @@ macro_rules! entities { #[derive(Debug, Clone)] pub enum Entity { $($e($e)),* } impl EntityT for Entity { - fn tick(&mut self, game: &mut Game, packet_out: &mut VecDeque<PacketC>, dt: f32) -> Result<()> { - match self { $(Entity::$e(x) => x.tick(game, packet_out, dt)),*, } + fn tick(&mut self, c: EntityContext<'_>) -> Result<()> { + match self { $(Entity::$e(x) => x.tick(c)),*, } } } }; diff --git a/server/src/entity/player_portal.rs b/server/src/entity/player_portal.rs index 6ee04f15..11442677 100644 --- a/server/src/entity/player_portal.rs +++ b/server/src/entity/player_portal.rs @@ -15,11 +15,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ -use super::EntityT; -use crate::game::Game; +use super::{EntityContext, EntityT}; use anyhow::{anyhow, Result}; use hurrycurry_protocol::{glam::Vec2, PacketC}; -use std::collections::VecDeque; #[derive(Debug, Default, Clone)] pub struct PlayerPortal { @@ -28,19 +26,21 @@ pub struct PlayerPortal { } impl EntityT for PlayerPortal { - fn tick( - &mut self, - game: &mut Game, - _packet_out: &mut VecDeque<PacketC>, - _dt: f32, - ) -> Result<()> { + fn tick(&mut self, c: EntityContext) -> Result<()> { let mut players = Vec::new(); - game.players_spatial_index + c.game + .players_spatial_index .query(self.from, 0.5, |pid, _| players.push(pid)); - for p in players { - let p = game.players.get_mut(&p).ok_or(anyhow!("player missing"))?; + for pid in players { + let p = c + .game + .players + .get_mut(&pid) + .ok_or(anyhow!("player missing"))?; p.movement.position = self.to; + c.packet_out + .push_back(PacketC::MovementSync { player: pid }); } Ok(()) |