diff options
| author | metamuffin <metamuffin@disroot.org> | 2026-03-22 22:12:40 +0100 |
|---|---|---|
| committer | metamuffin <metamuffin@disroot.org> | 2026-03-22 22:12:40 +0100 |
| commit | fd8525e2307a7b5e356684705e8cdc9c1db1d420 (patch) | |
| tree | 6946ef81015217ca6629beab48d80e60f485b948 | |
| parent | 9ee90635a0e6b5847c3c39293b1ebaddd344c593 (diff) | |
| download | hurrycurry-fd8525e2307a7b5e356684705e8cdc9c1db1d420.tar hurrycurry-fd8525e2307a7b5e356684705e8cdc9c1db1d420.tar.bz2 hurrycurry-fd8525e2307a7b5e356684705e8cdc9c1db1d420.tar.zst | |
bot spawning as part of game config; /bot now only available with cheats
| -rw-r--r-- | server/data/src/entities.rs | 3 | ||||
| -rw-r--r-- | server/data/src/lib.rs | 5 | ||||
| -rw-r--r-- | server/protocol/src/lib.rs | 1 | ||||
| -rw-r--r-- | server/src/commands.rs | 61 | ||||
| -rw-r--r-- | server/src/entity/mod.rs | 27 | ||||
| -rw-r--r-- | server/src/scoreboard.rs | 2 |
6 files changed, 72 insertions, 27 deletions
diff --git a/server/data/src/entities.rs b/server/data/src/entities.rs index 7f8be049..28ea7c86 100644 --- a/server/data/src/entities.rs +++ b/server/data/src/entities.rs @@ -98,6 +98,9 @@ pub enum EntityDecl { #[serde(default)] item_indices: Vec<ItemIndex>, }, + Bot { + name: String, + }, } #[derive(Debug, Clone, Copy, Deserialize, Serialize, ValueEnum)] diff --git a/server/data/src/lib.rs b/server/data/src/lib.rs index 3bfb5095..a3c0275d 100644 --- a/server/data/src/lib.rs +++ b/server/data/src/lib.rs @@ -232,6 +232,11 @@ pub fn build_gamedata( } entities.push(e); } + + for name in config.bots.clone() { + entities.push(EntityDecl::Bot { name }); + } + debug!("{} entities created", entities.len()); filter_demands_and_recipes(&initial_map, &mut demands, &mut recipes); diff --git a/server/protocol/src/lib.rs b/server/protocol/src/lib.rs index d5228fa5..96758c80 100644 --- a/server/protocol/src/lib.rs +++ b/server/protocol/src/lib.rs @@ -362,6 +362,7 @@ pub struct GameConfig { pub map: String, pub hand_count: Option<usize>, pub timer: Option<f32>, + pub bots: Vec<String>, } #[derive(Debug, Clone, Serialize, Deserialize)] diff --git a/server/src/commands.rs b/server/src/commands.rs index 4ba9fb60..1d260631 100644 --- a/server/src/commands.rs +++ b/server/src/commands.rs @@ -16,7 +16,7 @@ */ use crate::{ - entity::{bot::BotDriver, tutorial::Tutorial}, + entity::tutorial::Tutorial, server::{AnnounceState, Server}, }; use anyhow::Result; @@ -24,8 +24,7 @@ use clap::{Parser, ValueEnum}; use hurrycurry_bot::algos::ALGO_CONSTRUCTORS; use hurrycurry_locale::{TrError, tre, trm}; use hurrycurry_protocol::{ - Character, GameConfig, Hand, ItemLocation, Menu, Message, PacketC, PacketS, PlayerClass, - PlayerID, VoteSubject, + GameConfig, Hand, ItemLocation, Menu, Message, PacketC, PacketS, PlayerID, VoteSubject, }; use std::{fmt::Write, str::FromStr}; @@ -35,7 +34,7 @@ enum Command { /// Start a new game #[clap(alias = "s")] Start { - /// Gamedata specification + /// Map name #[arg(default_value = "junior")] map: String, @@ -44,8 +43,12 @@ enum Command { hand_count: Option<usize>, /// Duration in seconds - #[arg(short = 't', long)] + #[arg(short, long)] timer: Option<f32>, + + /// Add bot by name + #[arg(short, long)] + bot: Vec<String>, }, /// Shows the best entries of the scoreboard for this map. #[clap(alias = "top", alias = "top5")] @@ -80,8 +83,6 @@ enum Command { #[arg(short, long)] unready: bool, }, - #[clap(alias = "summon", alias = "bot")] - CreateBot { algo: String, name: Option<String> }, /// Reload the current map #[clap(alias = "r")] Reload, @@ -98,6 +99,10 @@ enum Command { message_id: String, arguments: Vec<String>, }, + /// Add bots to the current game (CHEAT) + #[cfg(feature = "cheats")] + #[clap(alias = "summon", alias = "bot")] + CreateBot { algo: String, name: Option<String> }, /// Set your players hand item (CHEAT) #[cfg(feature = "cheats")] #[clap(alias = "give")] @@ -146,7 +151,14 @@ impl Server { map, hand_count, timer, + bot, } => { + for b in &bot { + ALGO_CONSTRUCTORS + .iter() + .find(|(name, _)| *name == b) + .ok_or(tre!("s.error.algo_not_found", s = b.to_string()))?; + } self.packet_in( replies, PacketS::InitiateVote { @@ -156,6 +168,7 @@ impl Server { hand_count, map, timer, + bots: bot, }, }, }, @@ -243,22 +256,6 @@ impl Server { }, )?; } - Command::CreateBot { algo, name } => { - let (aname, cons) = ALGO_CONSTRUCTORS - .iter() - .find(|(name, _)| *name == algo.as_str()) - .ok_or(tre!("s.error.algo_not_found", s = algo))?; - self.entities.push(Box::new(BotDriver::new( - format!("{}-bot", name.unwrap_or((*aname).to_owned())), - Character { - color: 0, - hairstyle: 0, - headwear: 0, - }, - PlayerClass::Bot, - cons, - ))); - } Command::Scoreboard { map, text } => { let mapname = map.as_ref().unwrap_or(&self.game.data.current_map); let mapname_pretty = &self @@ -380,6 +377,24 @@ impl Server { }); } #[cfg(feature = "cheats")] + Command::CreateBot { algo, name } => { + let (aname, cons) = ALGO_CONSTRUCTORS + .iter() + .find(|(name, _)| *name == algo.as_str()) + .ok_or(tre!("s.error.algo_not_found", s = algo))?; + self.entities + .push(Box::new(crate::entity::bot::BotDriver::new( + format!("{}-bot", name.unwrap_or((*aname).to_owned())), + hurrycurry_protocol::Character { + color: 0, + hairstyle: 0, + headwear: 0, + }, + hurrycurry_protocol::PlayerClass::Bot, + cons, + ))); + } + #[cfg(feature = "cheats")] Command::SetItem { name } => { use hurrycurry_game_core::Item; use hurrycurry_protocol::{Hand, ItemLocation}; diff --git a/server/src/entity/mod.rs b/server/src/entity/mod.rs index 709028e8..b17fbfb9 100644 --- a/server/src/entity/mod.rs +++ b/server/src/entity/mod.rs @@ -33,8 +33,8 @@ pub mod tutorial; use crate::{ entity::{ - ctf_minigame::CtfMinigame, demand_sink::DemandSink, pedestrians::Pedestrians, - player_portal_pair::PlayerPortalPair, tag_minigame::TagMinigame, + bot::BotDriver, ctf_minigame::CtfMinigame, demand_sink::DemandSink, + pedestrians::Pedestrians, player_portal_pair::PlayerPortalPair, tag_minigame::TagMinigame, }, scoreboard::ScoreboardStore, }; @@ -44,10 +44,13 @@ use campaign::{Gate, Map}; use conveyor::Conveyor; use customers::Customers; use environment_effect::{EnvironmentController, EnvironmentEffectController}; +use hurrycurry_bot::algos::ALGO_CONSTRUCTORS; use hurrycurry_data::{PrivateGamedata, entities::EntityDecl}; use hurrycurry_game_core::Game; use hurrycurry_locale::TrError; -use hurrycurry_protocol::{Character, GameConfig, ItemLocation, PacketC, PacketS, PlayerID}; +use hurrycurry_protocol::{ + Character, GameConfig, ItemLocation, PacketC, PacketS, PlayerClass, PlayerID, +}; use item_portal::ItemPortal; use player_portal::PlayerPortal; use std::{ @@ -187,5 +190,23 @@ pub fn construct_entity(decl: &EntityDecl) -> DynEntity { neutral_tile, out_tile, } => Box::new(PlayerPortalPair::new(a, b, in_tile, neutral_tile, out_tile)), + + EntityDecl::Bot { name: search_name } => { + let (name, cons) = ALGO_CONSTRUCTORS + .iter() + .find(|(name, _)| *name == search_name.as_str()) + .unwrap_or(&ALGO_CONSTRUCTORS[0]); + + Box::new(BotDriver::new( + format!("{name}-bot"), + Character { + color: 0, + hairstyle: 0, + headwear: 0, + }, + PlayerClass::Bot, + cons, + )) + } } } diff --git a/server/src/scoreboard.rs b/server/src/scoreboard.rs index 293e082c..635e347c 100644 --- a/server/src/scoreboard.rs +++ b/server/src/scoreboard.rs @@ -83,6 +83,6 @@ pub trait GameConfigScoreboardCheckExt { } impl GameConfigScoreboardCheckExt for GameConfig { fn is_valid_for_scoreboard(&self) -> bool { - self.hand_count.is_none() && self.timer.is_none() + self.hand_count.is_none() && self.timer.is_none() && self.bots.is_empty() } } |