diff options
author | metamuffin <metamuffin@disroot.org> | 2025-06-03 19:45:05 +0200 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2025-06-03 19:45:08 +0200 |
commit | 9ee7eef2919feffe4e0695494d4027e8ec011808 (patch) | |
tree | 4fbb5347e7166911d08ae31dd3c20556b61c943e /server | |
parent | 63f7321e50b251d19f20dc929fc37a45cccdbb38 (diff) | |
download | hurrycurry-9ee7eef2919feffe4e0695494d4027e8ec011808.tar hurrycurry-9ee7eef2919feffe4e0695494d4027e8ec011808.tar.bz2 hurrycurry-9ee7eef2919feffe4e0695494d4027e8ec011808.tar.zst |
Add pedestrians (and custom spawn locations)
Diffstat (limited to 'server')
-rw-r--r-- | server/Cargo.toml | 1 | ||||
-rw-r--r-- | server/bot/src/main.rs | 1 | ||||
-rw-r--r-- | server/editor/src/main.rs | 1 | ||||
-rw-r--r-- | server/protocol/src/lib.rs | 3 | ||||
-rw-r--r-- | server/src/entity/bot.rs | 1 | ||||
-rw-r--r-- | server/src/entity/mod.rs | 22 | ||||
-rw-r--r-- | server/src/entity/pedestrians.rs | 86 | ||||
-rw-r--r-- | server/src/entity/tram.rs | 1 | ||||
-rw-r--r-- | server/src/main.rs | 1 | ||||
-rw-r--r-- | server/src/server.rs | 11 |
10 files changed, 124 insertions, 4 deletions
diff --git a/server/Cargo.toml b/server/Cargo.toml index 06a22798..8f68fd17 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -15,6 +15,7 @@ tokio-tungstenite = "0.24.0" futures-util = "0.3.30" serde_yml = "0.0.12" rand = "0.9.0-alpha.2" +rand_distr = "0.5.1" shlex = "1.3.0" clap = { version = "4.5.18", features = ["derive"] } reqwest = { version = "0.12.7", optional = true, default-features = false, features = [ diff --git a/server/bot/src/main.rs b/server/bot/src/main.rs index 918be7e1..56eedc13 100644 --- a/server/bot/src/main.rs +++ b/server/bot/src/main.rs @@ -59,6 +59,7 @@ fn main() -> Result<()> { character: args.character, class: PlayerClass::Bot, id: None, + position: None, }); let mut bots = Vec::new(); diff --git a/server/editor/src/main.rs b/server/editor/src/main.rs index 2c05dfbc..620daeb5 100644 --- a/server/editor/src/main.rs +++ b/server/editor/src/main.rs @@ -411,6 +411,7 @@ fn start_map_bot(address: &str, own_addr: &str, mapname: &str) -> Result<()> { character: 0, class: PlayerClass::Bot, id: None, + position: None, }); let mut timer = 10.; diff --git a/server/protocol/src/lib.rs b/server/protocol/src/lib.rs index 4f0d5d67..db65ddd2 100644 --- a/server/protocol/src/lib.rs +++ b/server/protocol/src/lib.rs @@ -116,6 +116,9 @@ pub enum PacketS { class: PlayerClass, #[serde(skip)] // TODO fix bincode can still set id id: Option<PlayerID>, // used entity bots that cant receive a response + #[serde(skip)] // TODO fix bincode aswell + #[bincode(with_serde)] + position: Option<Vec2>, // used entity bots that spawn in different locations }, Leave { player: PlayerID, diff --git a/server/src/entity/bot.rs b/server/src/entity/bot.rs index 6e6c9162..922cc55e 100644 --- a/server/src/entity/bot.rs +++ b/server/src/entity/bot.rs @@ -57,6 +57,7 @@ impl<T: BotAlgo + Any> Entity for BotDriver<T> { character, id: Some(self.id), class, + position: None, }) } diff --git a/server/src/entity/mod.rs b/server/src/entity/mod.rs index ddafc2f7..75ea0e9b 100644 --- a/server/src/entity/mod.rs +++ b/server/src/entity/mod.rs @@ -22,12 +22,14 @@ pub mod conveyor; pub mod customers; pub mod environment_effect; pub mod item_portal; +pub mod pedestrians; pub mod player_portal; pub mod tram; pub mod tutorial; use crate::{ data::{ItemTileRegistry, Serverdata}, + entity::pedestrians::Pedestrians, message::TrError, scoreboard::ScoreboardStore, }; @@ -45,7 +47,10 @@ use hurrycurry_protocol::{ use item_portal::ItemPortal; use player_portal::PlayerPortal; use serde::{Deserialize, Serialize}; -use std::{any::Any, collections::VecDeque}; +use std::{ + any::Any, + collections::{HashMap, VecDeque}, +}; use tram::Tram; pub type DynEntity = Box<dyn Entity + Send + Sync + 'static>; @@ -143,6 +148,11 @@ pub enum EntityDecl { smoothing: f32, }, Book, + Pedestrians { + spawn_delay: f32, + spawn_delay_stdev: f32, + points: Vec<Vec2>, + }, } pub fn construct_entity( @@ -222,5 +232,15 @@ pub fn construct_entity( spacing, smoothing, }), + EntityDecl::Pedestrians { + spawn_delay, + spawn_delay_stdev, + points, + } => Box::new(Pedestrians { + players: HashMap::new(), + points, + spawn_delay_distr: rand_distr::Normal::new(spawn_delay, spawn_delay_stdev).unwrap(), + cooldown: 0., + }), }) } diff --git a/server/src/entity/pedestrians.rs b/server/src/entity/pedestrians.rs new file mode 100644 index 00000000..9b433ded --- /dev/null +++ b/server/src/entity/pedestrians.rs @@ -0,0 +1,86 @@ +use std::collections::HashMap; + +/* + Hurry Curry! - a game about cooking + Copyright 2025 metamuffin + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, version 3 of the License only. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. + +*/ +use super::{Entity, EntityContext}; +use anyhow::Result; +use hurrycurry_protocol::{glam::Vec2, PacketS, PlayerClass, PlayerID}; +use rand::{random, rng}; +use rand_distr::Distribution; + +pub struct Pedestrians { + pub players: HashMap<PlayerID, usize>, + pub points: Vec<Vec2>, + pub spawn_delay_distr: rand_distr::Normal<f32>, + pub cooldown: f32, +} + +impl Entity for Pedestrians { + fn finished(&self) -> bool { + false + } + fn tick(&mut self, c: EntityContext<'_>) -> Result<()> { + self.cooldown -= c.dt; + if self.cooldown <= 0. && self.players.len() < 32 { + let id = PlayerID(random()); + c.packet_in.push_back(PacketS::Join { + name: "Pedestrian".to_string(), + character: 0, + class: PlayerClass::Customer, + id: Some(id), + position: self.points.get(0).copied(), + }); + self.players.insert(id, 0); + self.cooldown += self.spawn_delay_distr.sample(&mut rng()).max(0.1); + } + + let mut remove = Vec::new(); + + for (id, index) in &mut self.players { + if let Some(player) = c.game.players.get(id) { + let diff = self.points[*index] - player.movement.position; + if diff.length() < 0.8 { + *index += 1; + if *index >= self.points.len() { + remove.push(*id) + } + } else { + c.packet_in.push_back(PacketS::Movement { + player: *id, + dir: diff, + boost: false, + pos: None, + }); + } + } + } + + for id in remove { + if self.players.remove(&id).is_some() { + c.packet_in.push_back(PacketS::Leave { player: id }); + } + } + + Ok(()) + } + fn destructor(&mut self, c: EntityContext<'_>) { + for (id, _) in self.players.drain() { + c.packet_in.push_back(PacketS::Leave { player: id }) + } + } +} diff --git a/server/src/entity/tram.rs b/server/src/entity/tram.rs index 5b7fcaa8..26a191aa 100644 --- a/server/src/entity/tram.rs +++ b/server/src/entity/tram.rs @@ -43,6 +43,7 @@ impl Entity for Tram { character: self.character, class: PlayerClass::Bot, id: Some(id), + position: None, }); self.ids.push(id); } diff --git a/server/src/main.rs b/server/src/main.rs index 7f3de073..b1dc503b 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -359,6 +359,7 @@ mod test { character: 1, class: PlayerClass::Chef, id: None, + position: None, }, ) .await diff --git a/server/src/server.rs b/server/src/server.rs index a06f4f36..f9342add 100644 --- a/server/src/server.rs +++ b/server/src/server.rs @@ -76,6 +76,7 @@ pub trait GameServerExt { character: i32, class: PlayerClass, serverdata: &Serverdata, + custom_position: Option<Vec2>, packet_out: Option<&mut VecDeque<PacketC>>, ); fn prime_client(&self) -> Vec<PacketC>; @@ -143,7 +144,7 @@ impl GameServerExt for Game { } } for (id, (name, character, class)) in players { - self.join_player(id, name, character, class, serverdata, None); + self.join_player(id, name, character, class, serverdata, None, None); } packet_out.extend(self.prime_client()); @@ -247,12 +248,13 @@ impl GameServerExt for Game { character: i32, class: PlayerClass, serverdata: &Serverdata, + custom_position: Option<Vec2>, packet_out: Option<&mut VecDeque<PacketC>>, ) { - let position = match class { + let position = custom_position.unwrap_or(match class { PlayerClass::Customer => serverdata.customer_spawn, PlayerClass::Bot | PlayerClass::Chef => serverdata.chef_spawn, - } + (Vec2::new(random(), random()) - 0.5); + }) + (Vec2::new(random(), random()) - 0.5); self.players.insert( id, Player { @@ -353,6 +355,7 @@ impl Server { load_map: &mut None, }); } + self.tick(0.); self.game.load( gamedata, &serverdata, @@ -375,6 +378,7 @@ impl Server { character, id, class, + position, } => { if name.chars().count() > 32 || name.len() > 64 { return Err(tre!( @@ -397,6 +401,7 @@ impl Server { character, class, &self.data, + position, Some(&mut self.packet_out), ); replies.push(PacketC::Joined { id }) |