summaryrefslogtreecommitdiff
path: root/server/src
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-06-03 19:45:05 +0200
committermetamuffin <metamuffin@disroot.org>2025-06-03 19:45:08 +0200
commit9ee7eef2919feffe4e0695494d4027e8ec011808 (patch)
tree4fbb5347e7166911d08ae31dd3c20556b61c943e /server/src
parent63f7321e50b251d19f20dc929fc37a45cccdbb38 (diff)
downloadhurrycurry-9ee7eef2919feffe4e0695494d4027e8ec011808.tar
hurrycurry-9ee7eef2919feffe4e0695494d4027e8ec011808.tar.bz2
hurrycurry-9ee7eef2919feffe4e0695494d4027e8ec011808.tar.zst
Add pedestrians (and custom spawn locations)
Diffstat (limited to 'server/src')
-rw-r--r--server/src/entity/bot.rs1
-rw-r--r--server/src/entity/mod.rs22
-rw-r--r--server/src/entity/pedestrians.rs86
-rw-r--r--server/src/entity/tram.rs1
-rw-r--r--server/src/main.rs1
-rw-r--r--server/src/server.rs11
6 files changed, 118 insertions, 4 deletions
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 })