diff options
Diffstat (limited to 'server/src/commands.rs')
-rw-r--r-- | server/src/commands.rs | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/server/src/commands.rs b/server/src/commands.rs new file mode 100644 index 00000000..e2d40f05 --- /dev/null +++ b/server/src/commands.rs @@ -0,0 +1,168 @@ +/* + Hurry Curry! - a game about cooking + Copyright 2024 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 crate::{entity::bot::BotDriver, server::Server}; +use anyhow::{anyhow, bail, Result}; +use clap::{Parser, ValueEnum}; +use hurrycurry_bot::algos::ALGO_CONSTRUCTORS; +use hurrycurry_protocol::{Message, PacketC, PlayerID}; +use std::time::Duration; + +#[derive(Parser)] +#[clap(multicall = true)] +enum Command { + /// Start a new game + Start { + /// Gamedata specification + #[arg(default_value = "junior")] + spec: String, + /// Duration in seconds + #[arg(default_value = "420")] + timer: u64, + }, + /// Abort the current game + End, + /// Download recipe/map's source declaration + Download { + /// Resource kind + #[arg(value_enum)] + r#type: DownloadType, + /// Name + name: String, + }, + /// List all recipes and maps + List, + /// Send an effect + Effect { name: String }, + /// Send an item + Item { name: String }, + /// Reload the resource index + ReloadIndex, + #[clap(alias = "summon-bot", alias = "spawn-bot")] + CreateBot { algo: String, name: Option<String> }, + /// Reload the current map + #[clap(alias = "r")] + Reload, +} + +#[derive(ValueEnum, Clone)] +enum DownloadType { + Map, + Recipes, +} + +impl Server { + pub async fn handle_command_parse(&mut self, player: PlayerID, command: &str) -> Result<()> { + for line in command.split("\n") { + self.handle_command( + player, + Command::try_parse_from( + shlex::split(line) + .ok_or(anyhow!("quoting invalid"))? + .into_iter(), + )?, + ) + .await?; + } + Ok(()) + } + async fn handle_command(&mut self, player: PlayerID, command: Command) -> Result<()> { + match command { + Command::Start { spec, timer } => { + let data = self.index.generate(&spec).await?; + self.load(data, Some(Duration::from_secs(timer))); + } + Command::End => { + self.tx + .send(PacketC::ServerMessage { + text: format!( + "Game was aborted by {}.", + self.game + .players + .get(&player) + .ok_or(anyhow!("player missing"))? + .name + ), + }) + .ok(); + self.load(self.index.generate("lobby").await?, None); + } + Command::Reload => { + if self.count_chefs() > 1 { + bail!("must be at most one player to reload"); + } + self.load( + self.index.generate(&self.game.data.current_map).await?, + None, + ); + } + Command::ReloadIndex => { + self.index.reload().await?; + } + Command::Download { r#type, name } => { + let source = match r#type { + DownloadType::Map => self.index.read_map(&name).await, + DownloadType::Recipes => self.index.read_recipes(&name).await, + }?; + bail!("{source}"); + } + Command::List => { + bail!( + "Maps: {:?}\nRecipes: {:?}", + self.index.maps.keys().collect::<Vec<_>>(), + self.index.recipes + ) + } + Command::Effect { name } => { + self.tx + .send(PacketC::Communicate { + player, + message: Some(Message::Effect(name)), + timeout: None, + }) + .ok(); + } + Command::Item { name } => { + let item = self + .game + .data + .get_item_by_name(&name) + .ok_or(anyhow!("unknown item"))?; + self.tx + .send(PacketC::Communicate { + player, + message: Some(Message::Item(item)), + timeout: None, + }) + .ok(); + } + Command::CreateBot { algo, name } => { + let (aname, cons) = ALGO_CONSTRUCTORS + .iter() + .find(|(name, _)| *name == algo.as_str()) + .ok_or(anyhow!("algo name unknown"))?; + let algo = cons(); + self.entities.push(Box::new(BotDriver::new( + format!("{}-bot", name.unwrap_or((*aname).to_owned())), + 51, + algo, + ))); + } + } + Ok(()) + } +} |