diff options
-rw-r--r-- | server/src/bin/graph.rs | 2 | ||||
-rw-r--r-- | server/src/data.rs | 11 | ||||
-rw-r--r-- | server/src/entity/bot.rs | 13 | ||||
-rw-r--r-- | server/src/entity/conveyor.rs | 4 | ||||
-rw-r--r-- | server/src/entity/customers/mod.rs | 4 | ||||
-rw-r--r-- | server/src/entity/environment_effect.rs | 6 | ||||
-rw-r--r-- | server/src/entity/item_portal.rs | 4 | ||||
-rw-r--r-- | server/src/entity/mod.rs | 70 | ||||
-rw-r--r-- | server/src/entity/player_portal.rs | 4 | ||||
-rw-r--r-- | server/src/server.rs | 12 |
10 files changed, 76 insertions, 54 deletions
diff --git a/server/src/bin/graph.rs b/server/src/bin/graph.rs index 62dc47a2..c16bfe2d 100644 --- a/server/src/bin/graph.rs +++ b/server/src/bin/graph.rs @@ -30,7 +30,7 @@ async fn main() -> Result<()> { .nth(1) .ok_or(anyhow!("first arg should be recipe set name"))?; - let (data, _) = index.generate(format!("sushibar-{rn}")).await?; + let (data, _, _) = index.generate(format!("sushibar-{rn}")).await?; for i in 0..data.item_names.len() { println!("i{i} [label=\"{}\"]", data.item_name(ItemIndex(i))) diff --git a/server/src/data.rs b/server/src/data.rs index f0a85cca..021de525 100644 --- a/server/src/data.rs +++ b/server/src/data.rs @@ -16,7 +16,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ -use crate::entity::{construct_entity, Entity, EntityDecl}; +use crate::entity::{construct_entity, Entities, EntityDecl}; use anyhow::{anyhow, bail, Result}; use hurrycurry_protocol::{ glam::{IVec2, Vec2}, @@ -97,7 +97,7 @@ pub struct Demand { pub points: i64, } -#[derive(Debug, Clone, Default)] +#[derive(Debug,Clone, Default)] #[rustfmt::skip] pub struct Serverdata { pub spec: String, @@ -105,7 +105,6 @@ pub struct Serverdata { pub chef_spawn: Vec2, pub customer_spawn: Vec2, pub score_baseline: i64, - pub entities: Vec<Entity>, } #[derive(Debug, Deserialize, Default)] @@ -144,7 +143,7 @@ impl DataIndex { Ok(read_to_string(path).await?) } - pub async fn generate(&self, spec: String) -> Result<(Gamedata, Serverdata)> { + pub async fn generate(&self, spec: String) -> Result<(Gamedata, Serverdata, Entities)> { let (map, recipes) = spec.split_once("-").unwrap_or((spec.as_str(), "default")); let map_in = serde_yml::from_str(&self.read_map(map).await?)?; @@ -166,7 +165,7 @@ pub fn build_data( map_name: String, map_in: InitialMap, recipes_in: Vec<RecipeDecl>, -) -> Result<(Gamedata, Serverdata)> { +) -> Result<(Gamedata, Serverdata, Entities)> { let reg = ItemTileRegistry::default(); let mut recipes = Vec::new(); let mut entities = Vec::new(); @@ -324,8 +323,8 @@ pub fn build_data( chef_spawn, customer_spawn, score_baseline: map_in.score_baseline, - entities, }, + entities, )) } diff --git a/server/src/entity/bot.rs b/server/src/entity/bot.rs new file mode 100644 index 00000000..06477e8a --- /dev/null +++ b/server/src/entity/bot.rs @@ -0,0 +1,13 @@ +use super::{EntityContext, Entity}; +use anyhow::Result; +use hurrycurry_bot::BotAlgo; + +pub struct BotDriver { + algo: Box<dyn BotAlgo>, +} + +impl Entity for BotDriver { + fn tick(&mut self, c: EntityContext<'_>) -> Result<()> { + Ok(()) + } +} diff --git a/server/src/entity/conveyor.rs b/server/src/entity/conveyor.rs index f7f091c7..5602e082 100644 --- a/server/src/entity/conveyor.rs +++ b/server/src/entity/conveyor.rs @@ -15,7 +15,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ -use super::{EntityContext, EntityT}; +use super::{EntityContext, Entity}; use crate::server::interact_effect; use anyhow::{anyhow, Result}; use hurrycurry_protocol::{glam::IVec2, ItemIndex, ItemLocation}; @@ -30,7 +30,7 @@ pub struct Conveyor { pub(super) max_cooldown: f32, } -impl EntityT for Conveyor { +impl Entity for Conveyor { fn tick(&mut self, c: EntityContext) -> Result<()> { let from = c .game diff --git a/server/src/entity/customers/mod.rs b/server/src/entity/customers/mod.rs index 85da2c07..5038eaf2 100644 --- a/server/src/entity/customers/mod.rs +++ b/server/src/entity/customers/mod.rs @@ -18,7 +18,7 @@ pub mod demands; mod pathfinding; -use super::{EntityContext, EntityT}; +use super::{EntityContext, Entity}; use crate::{data::Demand, server::Server}; use anyhow::{anyhow, bail, Result}; use fake::{faker, Fake}; @@ -74,7 +74,7 @@ impl Customers { } } -impl EntityT for Customers { +impl Entity for Customers { fn tick(&mut self, c: EntityContext) -> Result<()> { // self.spawn_cooldown -= dt; // self.spawn_cooldown = self.spawn_cooldown.max(0.); diff --git a/server/src/entity/environment_effect.rs b/server/src/entity/environment_effect.rs index 8f54d29c..b0e811c3 100644 --- a/server/src/entity/environment_effect.rs +++ b/server/src/entity/environment_effect.rs @@ -15,7 +15,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ -use super::{EntityContext, EntityT}; +use super::{EntityContext, Entity}; use hurrycurry_protocol::PacketC; use rand::random; use serde::{Deserialize, Serialize}; @@ -49,7 +49,7 @@ impl EnvironmentEffectController { } } } -impl EntityT for EnvironmentEffectController { +impl Entity for EnvironmentEffectController { fn tick(&mut self, c: EntityContext) -> anyhow::Result<()> { if self.next_transition < Instant::now() { if self.active { @@ -73,7 +73,7 @@ impl EntityT for EnvironmentEffectController { #[derive(Debug, Clone)] pub struct EnvironmentController(pub Vec<String>); -impl EntityT for EnvironmentController { +impl Entity for EnvironmentController { fn tick(&mut self, c: EntityContext) -> anyhow::Result<()> { if c.game.environment_effects.is_empty() { c.game.environment_effects.extend(self.0.clone()); diff --git a/server/src/entity/item_portal.rs b/server/src/entity/item_portal.rs index be6acd06..faaa210b 100644 --- a/server/src/entity/item_portal.rs +++ b/server/src/entity/item_portal.rs @@ -15,7 +15,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ -use super::{EntityContext, EntityT}; +use super::{EntityContext, Entity}; use crate::server::interact_effect; use anyhow::{anyhow, Result}; use hurrycurry_protocol::{glam::IVec2, ItemLocation}; @@ -26,7 +26,7 @@ pub struct ItemPortal { pub(super) to: IVec2, } -impl EntityT for ItemPortal { +impl Entity for ItemPortal { fn tick(&mut self, c: EntityContext) -> Result<()> { let [from, to] = c .game diff --git a/server/src/entity/mod.rs b/server/src/entity/mod.rs index 10d0c155..efee6a6d 100644 --- a/server/src/entity/mod.rs +++ b/server/src/entity/mod.rs @@ -15,6 +15,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ +pub mod bot; pub mod conveyor; pub mod customers; pub mod environment_effect; @@ -29,44 +30,51 @@ use environment_effect::{EnvironmentController, EnvironmentEffect, EnvironmentEf use hurrycurry_client_lib::Game; use hurrycurry_protocol::{ glam::{IVec2, Vec2}, - ItemIndex, PacketC, Recipe, TileIndex, + ItemIndex, PacketC, PacketS, Recipe, TileIndex, }; use item_portal::ItemPortal; use player_portal::PlayerPortal; use serde::{Deserialize, Serialize}; use std::collections::{HashMap, HashSet, VecDeque}; +pub type DynEntity = Box<dyn Entity + Send + Sync + 'static>; +pub type Entities = Vec<DynEntity>; + pub struct EntityContext<'a> { pub game: &'a mut Game, pub packet_out: &'a mut VecDeque<PacketC>, + pub packet_in: &'a mut VecDeque<PacketS>, pub score_changed: &'a mut bool, pub dt: f32, } -pub trait EntityT: Clone { +pub trait Entity { fn tick(&mut self, c: EntityContext<'_>) -> Result<()>; + fn destructor(&mut self, _c: EntityContext<'_>) {} } -macro_rules! entities { - ($($e:ident),*) => { - #[derive(Debug, Clone)] - pub enum Entity { $($e($e)),* } - impl EntityT for Entity { - fn tick(&mut self, c: EntityContext<'_>) -> Result<()> { - match self { $(Entity::$e(x) => x.tick(c)),*, } - } - } - }; -} - -entities!( - Conveyor, - ItemPortal, - PlayerPortal, - Customers, - EnvironmentEffectController, - EnvironmentController -); +// macro_rules! entities { +// ($($e:ident),*) => { +// #[derive(Debug)] +// pub enum Entity { $($e($e)),* } +// impl EntityT for Entity { +// fn tick(&mut self, c: EntityContext<'_>) -> Result<()> { +// match self { $(Entity::$e(x) => x.tick(c)),*, } +// } +// fn destructor(&mut self, c: EntityContext<'_>) { +// match self { $(Entity::$e(x) => x.destructor(c)),*, } +// } +// } +// }; +// } +// entities!( +// Conveyor, +// ItemPortal, +// PlayerPortal, +// Customers, +// EnvironmentEffectController, +// EnvironmentController +// ); #[derive(Debug, Clone, Deserialize, Serialize)] #[serde(rename_all = "snake_case")] @@ -101,13 +109,13 @@ pub fn construct_entity( raw_demands: &[(ItemIndex, Option<ItemIndex>, f32)], recipes: &[Recipe], initial_map: &HashMap<IVec2, (TileIndex, Option<ItemIndex>)>, -) -> Result<Entity> { +) -> Result<DynEntity> { Ok(match decl.to_owned() { - EntityDecl::ItemPortal { from, to } => Entity::ItemPortal(ItemPortal { + EntityDecl::ItemPortal { from, to } => Box::new(ItemPortal { from: from.or(pos).ok_or(anyhow!("no item portal start"))?, to, }), - EntityDecl::PlayerPortal { from, to } => Entity::PlayerPortal(PlayerPortal { + EntityDecl::PlayerPortal { from, to } => Box::new(PlayerPortal { from: from .or(pos.map(|v| v.as_vec2())) .ok_or(anyhow!("no player portal start"))?, @@ -125,7 +133,7 @@ pub fn construct_entity( let to = to .or(dir.map(|s| s + from)) .ok_or(anyhow!("conveyor has no destination"))?; - Entity::Conveyor(Conveyor { + Box::new(Conveyor { from, to, max_cooldown: 1. / speed.unwrap_or(2.), @@ -142,13 +150,9 @@ pub fn construct_entity( .filter(|(_, (tile, _))| *tile == chair) .map(|(e, _)| (*e, true)) .collect(); - Entity::Customers(Customers::new(chairs, demands)?) - } - EntityDecl::EnvironmentEffect(config) => { - Entity::EnvironmentEffectController(EnvironmentEffectController::new(config)) - } - EntityDecl::Environment(names) => { - Entity::EnvironmentController(EnvironmentController(names)) + Box::new(Customers::new(chairs, demands)?) } + EntityDecl::EnvironmentEffect(config) => Box::new(EnvironmentEffectController::new(config)), + EntityDecl::Environment(names) => Box::new(EnvironmentController(names)), }) } diff --git a/server/src/entity/player_portal.rs b/server/src/entity/player_portal.rs index 11442677..53ba9c39 100644 --- a/server/src/entity/player_portal.rs +++ b/server/src/entity/player_portal.rs @@ -15,7 +15,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ -use super::{EntityContext, EntityT}; +use super::{EntityContext, Entity}; use anyhow::{anyhow, Result}; use hurrycurry_protocol::{glam::Vec2, PacketC}; @@ -25,7 +25,7 @@ pub struct PlayerPortal { pub(super) to: Vec2, } -impl EntityT for PlayerPortal { +impl Entity for PlayerPortal { fn tick(&mut self, c: EntityContext) -> Result<()> { let mut players = Vec::new(); c.game diff --git a/server/src/server.rs b/server/src/server.rs index f4ccbf35..faac080f 100644 --- a/server/src/server.rs +++ b/server/src/server.rs @@ -17,7 +17,7 @@ */ use crate::{ data::Serverdata, - entity::{Entity, EntityContext, EntityT}, + entity::{Entities, EntityContext}, interaction::{interact, tick_slot, InteractEffect, TickEffect}, }; use anyhow::{anyhow, bail, Result}; @@ -36,7 +36,7 @@ use std::{ pub struct ServerState { pub data: Arc<Serverdata>, - entities: Vec<Entity>, + pub entities: Entities, pub lobby: bool, pub player_id_counter: PlayerID, pub score_changed: bool, @@ -224,12 +224,13 @@ impl ServerState { impl Server<'_> { pub fn load( &mut self, - (gamedata, serverdata): (Gamedata, Serverdata), + (gamedata, serverdata, entities): (Gamedata, Serverdata, Entities), timer: Option<Duration>, packet_out: &mut VecDeque<PacketC>, ) { self.game.load(gamedata, &serverdata, timer, packet_out); self.state.data = serverdata.into(); + self.state.entities = entities; } pub fn join_player( @@ -585,16 +586,21 @@ impl Server<'_> { ); } + let mut packet_in = VecDeque::new(); for entity in self.state.entities.iter_mut() { if let Err(e) = entity.tick(EntityContext { game: self.game, packet_out, score_changed: &mut self.state.score_changed, + packet_in: &mut packet_in, dt, }) { warn!("entity tick failed: {e}") } } + for p in packet_in.drain(..) { + let _ = self.packet_in(p, &mut vec![], packet_out); + } let now = Instant::now(); |