diff options
author | metamuffin <metamuffin@disroot.org> | 2024-10-02 14:47:41 +0200 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2024-10-02 14:47:51 +0200 |
commit | a702fa55eda5fbb48fd2ea5ecea89d030ea2305a (patch) | |
tree | f8391ff21c33ce2aa2a83f6c11a693e182796119 | |
parent | ebf93598d76fbc172e9f23cde2a20a3194459e34 (diff) | |
download | hurrycurry-a702fa55eda5fbb48fd2ea5ecea89d030ea2305a.tar hurrycurry-a702fa55eda5fbb48fd2ea5ecea89d030ea2305a.tar.bz2 hurrycurry-a702fa55eda5fbb48fd2ea5ecea89d030ea2305a.tar.zst |
translate command errors
-rw-r--r-- | locale/en.ini | 11 | ||||
-rw-r--r-- | server/src/commands.rs | 91 | ||||
-rw-r--r-- | server/src/message.rs | 25 | ||||
-rw-r--r-- | server/src/state.rs | 2 |
4 files changed, 86 insertions, 43 deletions
diff --git a/locale/en.ini b/locale/en.ini index 9f54861e..b92dbe29 100644 --- a/locale/en.ini +++ b/locale/en.ini @@ -8,9 +8,9 @@ c.credits.title=Hurry Curry! - a game about cooking c.credits.translations=Translations c.error.cannot_cancel_no_game=Cannot cancel game since no game is running. c.error.empty_username=Username cannot be empty. -c.error.select_hairstyle=You must select a hairstyle. c.error.must_join_to_cancel=You must join in order to be able to cancel the current game. c.error.placeholder=This should be the error message. +c.error.select_hairstyle=You must select a hairstyle. c.error.server=Error from server: {0} c.error.version_mismatch=Server and client versions do not match. Server: {0}.{1}, Client: {2}.{3}.%nAre you sure the game is up to date? c.error.websocket.unavailable=unavailable @@ -49,6 +49,7 @@ c.menu.lobby.mapname=Map name c.menu.lobby.players=Players c.menu.lobby.start=Start game c.menu.my_chef=My Chef +c.menu.play.allow_query_registry=To show a public server list a registry c.menu.play.connect=Connect c.menu.play.fetching_list=Fetching server list... c.menu.play.list_item={0} ({1} players) @@ -65,7 +66,6 @@ c.menu.play.server=Server c.menu.play=Play c.menu.quit=Quit c.menu.settings=Settings -c.play.allow_query_registry=Do you want to query the global registry for public servers? c.score.acceptable=Acceptable service c.score.completed=Completed c.score.excellent=Excellent service @@ -202,16 +202,23 @@ s.bot.waiter=Waiter s.campaign.condition.stars=Reach at least {0} stars in {1} s.campaign.list_helper=- {0}%n - {1} s.campaign.unlock_condition=To unlock: %n%n{0} +s.error.algo_not_found=The algorhythm "{0}" does not exist. s.error.already_interacting=already interacting s.error.conn_too_many_players=Players-per-connection limit exceeded. s.error.customer_interact=You shall not interact with customers. s.error.interacting_too_far=interacting too far from player +s.error.item_not_found=The item "{0}" does not exist. s.error.map_load=Map failed to load: {0} +s.error.must_be_alone=You must be alone in this server to reload +s.error.no_info=No information available. s.error.no_player=Player does not exist. s.error.no_tile=Tile does not exist. s.error.packet_not_supported=Packet not supported in this session. s.error.packet_sender_invalid=Packet sent to a player that is not owned by this connection. +s.error.quoting_invalid=Comand quoting invalid s.error.self_interact=Interacting with yourself. This is impossible. +s.error.tutorial_already_running=Tutorial already running +s.error.tutorial_no_running=No tutorial running s.replay.cannot_join=Replays cannot be joined. s.state.abort_no_players=Game was aborted due to a lack of players. s.state.game_aborted=Game was aborted by {0}. diff --git a/server/src/commands.rs b/server/src/commands.rs index 478d88e3..feb6ab65 100644 --- a/server/src/commands.rs +++ b/server/src/commands.rs @@ -17,10 +17,11 @@ */ use crate::{ entity::{bot::BotDriver, tutorial::Tutorial}, + message::TrError, server::Server, - trm, + tre, trm, }; -use anyhow::{anyhow, bail, Result}; +use anyhow::Result; use clap::{Parser, ValueEnum}; use hurrycurry_bot::algos::ALGO_CONSTRUCTORS; use hurrycurry_protocol::{Menu, Message, PacketC, PlayerClass, PlayerID}; @@ -103,16 +104,17 @@ impl Server { &mut self, player: PlayerID, command: &str, - ) -> Result<Vec<PacketC>> { + ) -> Result<Vec<PacketC>, TrError> { let mut replies = Vec::new(); for line in command.split("\n") { self.handle_command( player, Command::try_parse_from( shlex::split(line) - .ok_or(anyhow!("quoting invalid"))? + .ok_or(tre!("s.error.quoting_invalid"))? .into_iter(), - )?, + ) + .map_err(|e| TrError::Plain(e.to_string()))?, &mut replies, ) .await?; @@ -124,7 +126,7 @@ impl Server { player: PlayerID, command: Command, replies: &mut Vec<PacketC>, - ) -> Result<()> { + ) -> Result<(), TrError> { match command { Command::Start { spec, timer } => { if !self.game.lobby { @@ -136,7 +138,7 @@ impl Server { .game .players .get(&player) - .ok_or(anyhow!("player missing"))? + .ok_or(tre!("s.error.no_player"))? .name .clone() ), @@ -144,7 +146,11 @@ impl Server { }) .ok(); } - let data = self.index.generate(&spec).await?; + let data = self + .index + .generate(&spec) + .await + .map_err(|e| TrError::Plain(e.to_string()))?; self.load(data, timer.map(Duration::from_secs)); } Command::End => { @@ -156,42 +162,59 @@ impl Server { .game .players .get(&player) - .ok_or(anyhow!("player missing"))? + .ok_or(tre!("s.error.no_player"))? .name .clone() ), error: false, }) .ok(); - self.load(self.index.generate("lobby").await?, None); + self.load( + self.index + .generate("lobby") + .await + .map_err(|e| TrError::Plain(e.to_string()))?, + None, + ); } Command::Reload => { if self.count_chefs() > 1 { - bail!("must be at most one player to reload"); + return Err(tre!("s.error.must_be_alone")); } self.load( - self.index.generate(&self.game.data.current_map).await?, + self.index + .generate(&self.game.data.current_map) + .await + .map_err(|e| TrError::Plain(e.to_string()))?, None, ); } Command::ReloadIndex => { - self.index.reload().await?; + self.index + .reload() + .await + .map_err(|e| TrError::Plain(e.to_string()))?; } Command::Book => replies.push(PacketC::Menu(Menu::Book)), 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}"); + } + .map_err(|e| TrError::Plain(e.to_string()))?; + replies.push(PacketC::ServerMessage { + message: Message::Text(source), + error: false, + }); } - Command::List => { - bail!( + Command::List => replies.push(PacketC::ServerMessage { + message: Message::Text(format!( "Maps: {:?}\nRecipes: {:?}", self.index.maps.keys().collect::<Vec<_>>(), self.index.recipes - ) - } + )), + error: false, + }), Command::Effect { name } => { self.tx.send(PacketC::Effect { name, player }).ok(); } @@ -200,7 +223,7 @@ impl Server { .game .data .get_item_by_name(&name) - .ok_or(anyhow!("unknown item"))?; + .ok_or(tre!("s.error.item_not_found", s = name))?; self.tx .send(PacketC::Communicate { player, @@ -213,7 +236,7 @@ impl Server { let (aname, cons) = ALGO_CONSTRUCTORS .iter() .find(|(name, _)| *name == algo.as_str()) - .ok_or(anyhow!("algo name unknown"))?; + .ok_or(tre!("s.error.algo_not_found", s = algo))?; let algo = cons(); self.entities.push(Box::new(BotDriver::new( format!("{}-bot", name.unwrap_or((*aname).to_owned())), @@ -235,7 +258,10 @@ impl Server { ) .unwrap(); } - bail!("{o}"); + replies.push(PacketC::ServerMessage { + message: Message::Text(o), + error: false, + }); } } Command::Info { map } => { @@ -244,20 +270,21 @@ impl Server { .index .maps .get(mapname) - .ok_or(anyhow!("no information available"))?; - bail!( - "{:?}\nRecommended player count: {}\nDifficulty: {}", - info.name, - info.difficulty, - info.players - ) + .ok_or(tre!("s.error.no_info"))?; + replies.push(PacketC::ServerMessage { + message: Message::Text(format!( + "{:?}\nRecommended player count: {}\nDifficulty: {}", + info.name, info.difficulty, info.players + )), + error: false, + }); } Command::StartTutorial { item } => { let item = self .game .data .get_item_by_name(&item) - .ok_or(anyhow!("unknown item"))?; + .ok_or(tre!("s.error.item_not_found", s = item))?; #[cfg(not(test))] // TODO rust-analyser does not undestand trait upcasting if self .entities @@ -268,7 +295,7 @@ impl Server { }) .is_some() { - bail!("Tutorial already running") + return Err(tre!("s.error.tutorial_already_running")); } self.entities.push(Box::new(Tutorial::new(player, item))); } @@ -281,7 +308,7 @@ impl Server { { tutorial.ended = true; } else { - bail!("No tutorial running") + return Err(tre!("s.error.tutorial_no_running")); } } Command::TranslateMessage { diff --git a/server/src/message.rs b/server/src/message.rs index c248fff8..79c004a2 100644 --- a/server/src/message.rs +++ b/server/src/message.rs @@ -46,28 +46,37 @@ macro_rules! trm_param { }; } -pub struct TrError { - pub id: &'static str, - pub params: Vec<Message>, +pub enum TrError { + Tr { + id: &'static str, + params: Vec<Message>, + }, + Plain(String), } impl From<TrError> for Message { fn from(value: TrError) -> Self { - Self::Translation { - id: value.id.to_owned(), - params: value.params, + match value { + TrError::Tr { id, params } => Self::Translation { + id: id.to_owned(), + params, + }, + TrError::Plain(s) => Self::Text(s), } } } impl Debug for TrError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{} {:?}", tr(self.id), self.params) + match self { + TrError::Tr { id, params } => write!(f, "{} {:?}", tr(id), params), + TrError::Plain(s) => write!(f, "{s}"), + } } } #[macro_export] macro_rules! tre { ($id:literal $(, $typ:ident = $param:expr)*) => { - crate::message::TrError { + crate::message::TrError::Tr { id: $id, params: vec![$(crate::tre_param!($typ, $param)),*] } diff --git a/server/src/state.rs b/server/src/state.rs index 068b45a8..20e2bf80 100644 --- a/server/src/state.rs +++ b/server/src/state.rs @@ -59,7 +59,7 @@ impl Server { Ok(packets) => return Ok(packets), Err(e) => { return Ok(vec![PacketC::ServerMessage { - message: Message::Text(format!("{e}")), // TODO localize + message: e.into(), error: true, }]); } |