summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock92
-rw-r--r--data/maps/debug.yaml4
-rw-r--r--data/maps/debug2.yaml4
-rw-r--r--pixel-client/src/game.rs1
-rw-r--r--server/Cargo.toml1
-rw-r--r--server/bot/src/main.rs1
-rw-r--r--server/editor/src/main.rs1
-rw-r--r--server/protocol/src/lib.rs3
-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
-rw-r--r--test-client/main.ts3
15 files changed, 203 insertions, 29 deletions
diff --git a/Cargo.lock b/Cargo.lock
index ca534e61..65a7115a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -958,7 +958,19 @@ checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [
"cfg-if",
"libc",
- "wasi",
+ "wasi 0.11.0+wasi-snapshot-preview1",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "r-efi",
+ "wasi 0.14.2+wasi-0.2.4",
]
[[package]]
@@ -1157,7 +1169,7 @@ dependencies = [
"hurrycurry-client-lib",
"hurrycurry-protocol",
"log",
- "rand 0.9.0-alpha.2",
+ "rand 0.9.1",
"rustls",
]
@@ -1250,7 +1262,7 @@ dependencies = [
"futures-util",
"hurrycurry-protocol",
"log",
- "rand 0.9.0-alpha.2",
+ "rand 0.9.1",
"rustls",
"serde",
"serde_json",
@@ -1275,7 +1287,8 @@ dependencies = [
"log",
"mdns-sd",
"pollster",
- "rand 0.9.0-alpha.2",
+ "rand 0.9.1",
+ "rand_distr",
"reqwest",
"serde",
"serde_json",
@@ -1582,6 +1595,12 @@ dependencies = [
]
[[package]]
+name = "libm"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
+
+[[package]]
name = "libyml"
version = "0.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1742,7 +1761,7 @@ checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec"
dependencies = [
"hermit-abi 0.3.9",
"libc",
- "wasi",
+ "wasi 0.11.0+wasi-snapshot-preview1",
"windows-sys 0.52.0",
]
@@ -1857,6 +1876,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
+ "libm",
]
[[package]]
@@ -1997,7 +2017,7 @@ dependencies = [
"hurrycurry-client-lib",
"hurrycurry-protocol",
"log",
- "rand 0.9.0-alpha.2",
+ "rand 0.9.1",
"rustls",
"sdl2",
"serde",
@@ -2188,6 +2208,12 @@ dependencies = [
]
[[package]]
+name = "r-efi"
+version = "5.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
+
+[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2200,13 +2226,12 @@ dependencies = [
[[package]]
name = "rand"
-version = "0.9.0-alpha.2"
+version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3e256ff62cee3e03def855c4d4260106d2bb1696fdc01af03e9935b993720a5"
+checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
dependencies = [
- "rand_chacha 0.9.0-alpha.2",
- "rand_core 0.9.0-alpha.2",
- "zerocopy",
+ "rand_chacha 0.9.0",
+ "rand_core 0.9.3",
]
[[package]]
@@ -2221,12 +2246,12 @@ dependencies = [
[[package]]
name = "rand_chacha"
-version = "0.9.0-alpha.2"
+version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d299e9db34f6623b2a9e86c015d6e173d5f46d64d4b9b8cc46ae8a982a50b04c"
+checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
dependencies = [
"ppv-lite86",
- "rand_core 0.9.0-alpha.2",
+ "rand_core 0.9.3",
]
[[package]]
@@ -2235,17 +2260,26 @@ version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
- "getrandom",
+ "getrandom 0.2.15",
]
[[package]]
name = "rand_core"
-version = "0.9.0-alpha.2"
+version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4e93f5a5e3c528cda9acb0928c31b2ba868c551cc46e67b778075e34aab9906"
+checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
dependencies = [
- "getrandom",
- "zerocopy",
+ "getrandom 0.3.3",
+]
+
+[[package]]
+name = "rand_distr"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a8615d50dcf34fa31f7ab52692afec947c4dd0ab803cc87cb3b0b4570ff7463"
+dependencies = [
+ "num-traits",
+ "rand 0.9.1",
]
[[package]]
@@ -2451,7 +2485,7 @@ checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d"
dependencies = [
"cc",
"cfg-if",
- "getrandom",
+ "getrandom 0.2.15",
"libc",
"spin",
"untrusted",
@@ -3432,6 +3466,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
+name = "wasi"
+version = "0.14.2+wasi-0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
+dependencies = [
+ "wit-bindgen-rt",
+]
+
+[[package]]
name = "wasm-bindgen"
version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3756,6 +3799,15 @@ dependencies = [
]
[[package]]
+name = "wit-bindgen-rt"
+version = "0.39.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
+dependencies = [
+ "bitflags 2.6.0",
+]
+
+[[package]]
name = "xdg"
version = "2.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/data/maps/debug.yaml b/data/maps/debug.yaml
index 2e902315..90cd3480 100644
--- a/data/maps/debug.yaml
+++ b/data/maps/debug.yaml
@@ -102,10 +102,6 @@ entities:
- !environment_effect { name: rain, on: 60, off: 40 }
- !environment_effect { name: wind, on: 60, off: 40 }
- !environment [night]
- - !tram
- length: 3
- character: 51
- points: [[1, 2], [15, 2], [15, 8], [1, 8]]
tile_entities:
"}": !conveyor { dir: [1, 0], filter: dough-foodprocessor }
diff --git a/data/maps/debug2.yaml b/data/maps/debug2.yaml
index 02e67809..3c849045 100644
--- a/data/maps/debug2.yaml
+++ b/data/maps/debug2.yaml
@@ -102,6 +102,10 @@ entities:
points: [[3, 3], [23, 3], [23, 15], [3, 15]]
smoothing: 3.
spacing: 0.3625
+ - !pedestrians
+ points: [[7, 7], [19, 7], [19, 13], [7, 13]]
+ spawn_delay: 0.5
+ spawn_delay_stdev: 1
chef_spawn: "~"
customer_spawn: "!"
diff --git a/pixel-client/src/game.rs b/pixel-client/src/game.rs
index cbcc62d5..cfac7082 100644
--- a/pixel-client/src/game.rs
+++ b/pixel-client/src/game.rs
@@ -91,6 +91,7 @@ impl Game {
name: config.username.clone(),
class: PlayerClass::Chef,
character: 0,
+ position: None,
});
Self {
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 })
diff --git a/test-client/main.ts b/test-client/main.ts
index f52e7f40..ef38494d 100644
--- a/test-client/main.ts
+++ b/test-client/main.ts
@@ -327,7 +327,7 @@ export let chat: null | HTMLInputElement = null;
const QUICK_COMMANDS: { [key: string]: string } = {
"Numpad1": "/start junior",
- "Numpad2": "/start senior",
+ "Numpad2": "/start debug2",
"Numpad3": "/start sophomore",
"Numpad4": "/start debug",
"Numpad5": "/start 5star",
@@ -336,6 +336,7 @@ const QUICK_COMMANDS: { [key: string]: string } = {
"Numpad9": "/start-tutorial plate:bun",
"Numpad7": "/end-tutorial",
"Numpad0": "/end",
+ "NumpadEnter": "/r",
}
export const keys_down = new Set();