diff --git a/pumpkin/src/client/player_packet.rs b/pumpkin/src/client/player_packet.rs index ee9920f9e..cfc9526ac 100644 --- a/pumpkin/src/client/player_packet.rs +++ b/pumpkin/src/client/player_packet.rs @@ -1,4 +1,4 @@ -use std::f32::consts::PI; +use std::{f32::consts::PI, sync::Arc}; use crate::{ commands::CommandSender, @@ -216,9 +216,13 @@ impl Player { world.broadcast_packet_expect(&[self.client.id], &packet); } - pub fn handle_chat_command(&self, server: &Server, command: SChatCommand) { + pub fn handle_chat_command(self: &Arc, server: &Server, command: SChatCommand) { let dispatcher = server.command_dispatcher.clone(); - dispatcher.handle_command(&mut CommandSender::Player(self), server, &command.command); + dispatcher.handle_command( + &mut CommandSender::Player(self.clone()), + server, + &command.command, + ); if ADVANCED_CONFIG.commands.log_console { log::info!( "Player ({}): executed command /{}", diff --git a/pumpkin/src/commands/arg_player.rs b/pumpkin/src/commands/arg_player.rs index 24c91a7c4..316e152cc 100644 --- a/pumpkin/src/commands/arg_player.rs +++ b/pumpkin/src/commands/arg_player.rs @@ -1,39 +1,50 @@ +use std::sync::Arc; + use crate::commands::dispatcher::InvalidTreeError; use crate::commands::dispatcher::InvalidTreeError::InvalidConsumptionError; use crate::commands::tree::{ConsumedArgs, RawArgs}; use crate::commands::CommandSender; -use crate::commands::CommandSender::Player; use crate::server::Server; /// todo: implement (so far only own name + @s/@p is implemented) -pub fn consume_arg_player(src: &CommandSender, args: &mut RawArgs) -> Option { - let s = args.pop()?; - - match s { - "@s" if src.is_player() => Some(s.into()), - "@p" if src.is_player() => Some(s.into()), - "@r" => None, // todo: implement random player target selector - "@a" | "@e" => None, // todo: implement all players target selector - _ => { - // todo: implement any other player than sender - if let Player(player) = src { - let profile = &player.gameprofile; - if profile.name == s { - return Some(s.into()); - }; - }; - None +pub fn consume_arg_player( + src: &CommandSender, + server: &Server, + args: &mut RawArgs, +) -> Result> { + if let Some(arg) = args.pop() { + match arg { + "@s" => { + if src.is_player() { + return Ok(arg.into()); + } else { + return Err(Some("You are not a Player".into())); + } + } + "@p" if src.is_player() => return Ok(arg.into()), + "@r" => todo!(), // todo: implement random player target selector + "@a" | "@e" => todo!(), // todo: implement all players target selector + name => { + // todo: implement any other player than sender + for world in &server.worlds { + if world.get_player_by_name(name).is_some() { + return Ok(name.into()); + } + } + return Err(Some(format!("Player not found: {}", arg))); + } } } + Err(None) } /// todo: implement (so far only own name + @s/@p is implemented) -pub fn parse_arg_player<'a>( - src: &'a mut CommandSender, - _server: &Server, +pub fn parse_arg_player( + src: &mut CommandSender, + server: &Server, arg_name: &str, consumed_args: &ConsumedArgs, -) -> Result<&'a crate::entity::player::Player, InvalidTreeError> { +) -> Result, InvalidTreeError> { let s = consumed_args .get(arg_name) .ok_or(InvalidConsumptionError(None))? @@ -44,14 +55,12 @@ pub fn parse_arg_player<'a>( "@p" if src.is_player() => Ok(src.as_mut_player().unwrap()), "@r" => Err(InvalidConsumptionError(Some(s.into()))), // todo: implement random player target selector "@a" | "@e" => Err(InvalidConsumptionError(Some(s.into()))), // todo: implement all players target selector - _ => { - // todo: implement any other player than sender - if let Player(player) = src { - let profile = &player.gameprofile; - if profile.name == s { + name => { + for world in &server.worlds { + if let Some(player) = world.get_player_by_name(name) { return Ok(player); - }; - }; + } + } Err(InvalidConsumptionError(Some(s.into()))) } } diff --git a/pumpkin/src/commands/cmd_gamemode.rs b/pumpkin/src/commands/cmd_gamemode.rs index 484d85c0e..4fe656e84 100644 --- a/pumpkin/src/commands/cmd_gamemode.rs +++ b/pumpkin/src/commands/cmd_gamemode.rs @@ -14,6 +14,7 @@ use crate::commands::tree::{CommandTree, ConsumedArgs, RawArgs}; use crate::commands::tree_builder::{argument, require}; use crate::commands::CommandSender; use crate::commands::CommandSender::Player; +use crate::server::Server; const NAMES: [&str; 1] = ["gamemode"]; @@ -22,20 +23,27 @@ const DESCRIPTION: &str = "Change a player's gamemode."; const ARG_GAMEMODE: &str = "gamemode"; const ARG_TARGET: &str = "target"; -pub fn consume_arg_gamemode(_src: &CommandSender, args: &mut RawArgs) -> Option { - let s = args.pop()?; - - if let Ok(id) = s.parse::() { - match GameMode::from_u8(id) { - None | Some(GameMode::Undefined) => {} - Some(_) => return Some(s.into()), +pub fn consume_arg_gamemode( + _src: &CommandSender, + _server: &Server, + args: &mut RawArgs, +) -> Result> { + if let Some(arg) = args.pop() { + if let Ok(id) = arg.parse::() { + match GameMode::from_u8(id) { + None | Some(GameMode::Undefined) => {} + Some(_) => return Ok(arg.into()), + }; }; - }; - match GameMode::from_str(s) { - Err(_) | Ok(GameMode::Undefined) => None, - Ok(_) => Some(s.into()), + match GameMode::from_str(arg) { + Err(_) | Ok(GameMode::Undefined) => { + return Err(Some(format!("Gamemode not found: {}", arg))) + } + Ok(_) => return Ok(arg.into()), + } } + Err(None) } pub fn parse_arg_gamemode(consumed_args: &ConsumedArgs) -> Result { diff --git a/pumpkin/src/commands/cmd_help.rs b/pumpkin/src/commands/cmd_help.rs index a955f4c8c..18dddc6e7 100644 --- a/pumpkin/src/commands/cmd_help.rs +++ b/pumpkin/src/commands/cmd_help.rs @@ -3,6 +3,7 @@ use crate::commands::dispatcher::{CommandDispatcher, InvalidTreeError}; use crate::commands::tree::{Command, CommandTree, ConsumedArgs, RawArgs}; use crate::commands::tree_builder::argument; use crate::commands::CommandSender; +use crate::server::Server; use pumpkin_core::text::TextComponent; const NAMES: [&str; 3] = ["help", "h", "?"]; @@ -11,12 +12,16 @@ const DESCRIPTION: &str = "Print a help message."; const ARG_COMMAND: &str = "command"; -fn consume_arg_command(_src: &CommandSender, _args: &mut RawArgs) -> Option { +fn consume_arg_command( + _src: &CommandSender, + _server: &Server, + _args: &mut RawArgs, +) -> Result> { // let s = args.pop()?; // dispatcher.get_tree(s).ok().map(|tree| tree.names[0].into()) // TODO - None + Err(None) } fn parse_arg_command<'a>( diff --git a/pumpkin/src/commands/cmd_kick.rs b/pumpkin/src/commands/cmd_kick.rs index 50b8f9b3a..43a24a27a 100644 --- a/pumpkin/src/commands/cmd_kick.rs +++ b/pumpkin/src/commands/cmd_kick.rs @@ -1,22 +1,19 @@ -use crate::commands::arg_player::{consume_arg_player, parse_arg_player}; +use crate::commands::arg_player::parse_arg_player; use crate::commands::tree::CommandTree; -use crate::commands::tree::RawArgs; use crate::commands::tree_builder::argument; -use crate::commands::CommandSender; use pumpkin_core::text::{color::NamedColor, TextComponent}; +use super::arg_player::consume_arg_player; + const NAMES: [&str; 1] = ["kick"]; const DESCRIPTION: &str = "Kicks the target player from the server."; const ARG_TARGET: &str = "target"; -pub fn consume_arg_target(_src: &CommandSender, args: &mut RawArgs) -> Option { - consume_arg_player(_src, args) -} - pub fn init_command_tree<'a>() -> CommandTree<'a> { CommandTree::new(NAMES, DESCRIPTION).with_child( - argument(ARG_TARGET, consume_arg_target).execute(&|sender, server, args| { + argument(ARG_TARGET, consume_arg_player).execute(&|sender, server, args| { + dbg!("aa"); let target = parse_arg_player(sender, server, ARG_TARGET, args)?; target.kick(TextComponent::text("Kicked by an operator")); diff --git a/pumpkin/src/commands/cmd_kill.rs b/pumpkin/src/commands/cmd_kill.rs index 77c95f40e..cf4208652 100644 --- a/pumpkin/src/commands/cmd_kill.rs +++ b/pumpkin/src/commands/cmd_kill.rs @@ -1,8 +1,6 @@ use crate::commands::arg_player::{consume_arg_player, parse_arg_player}; use crate::commands::tree::CommandTree; -use crate::commands::tree::RawArgs; use crate::commands::tree_builder::argument; -use crate::commands::CommandSender; use pumpkin_core::text::{color::NamedColor, TextComponent}; const NAMES: [&str; 1] = ["kill"]; @@ -10,13 +8,10 @@ const DESCRIPTION: &str = "Kills a target player."; const ARG_TARGET: &str = "target"; -pub fn consume_arg_target(_src: &CommandSender, args: &mut RawArgs) -> Option { - consume_arg_player(_src, args) -} - pub fn init_command_tree<'a>() -> CommandTree<'a> { CommandTree::new(NAMES, DESCRIPTION).with_child( - argument(ARG_TARGET, consume_arg_target).execute(&|sender, server, args| { + argument(ARG_TARGET, consume_arg_player).execute(&|sender, server, args| { + // TODO parse entities not only players let target = parse_arg_player(sender, server, ARG_TARGET, args)?; target.living_entity.kill(); diff --git a/pumpkin/src/commands/dispatcher.rs b/pumpkin/src/commands/dispatcher.rs index a636e8144..889bec72c 100644 --- a/pumpkin/src/commands/dispatcher.rs +++ b/pumpkin/src/commands/dispatcher.rs @@ -58,14 +58,17 @@ impl<'a> CommandDispatcher<'a> { println!("Error while parsing command \"{cmd}\": a requirement that was expected was not met."); return Err("Internal Error (See logs for details)".into()); } - Ok(is_fitting_path) => { - if is_fitting_path { - return Ok(()); + Ok(is_fitting_path) => match is_fitting_path { + Ok(_) => return Ok(()), + Err(error) => { + // Custom error message or not ? + if let Some(error) = error { + return Err(error); + } } - } + }, } } - Err(format!("Invalid Syntax. Usage: {}", tree)) } @@ -90,7 +93,7 @@ impl<'a> CommandDispatcher<'a> { path: Vec, tree: &CommandTree, mut raw_args: RawArgs, - ) -> Result { + ) -> Result>, InvalidTreeError> { let mut parsed_args: ConsumedArgs = HashMap::new(); for node in path.iter().map(|&i| &tree.nodes[i]) { @@ -98,36 +101,37 @@ impl<'a> CommandDispatcher<'a> { NodeType::ExecuteLeaf { run } => { return if raw_args.is_empty() { run(src, server, &parsed_args)?; - Ok(true) + Ok(Ok(())) } else { - Ok(false) + Ok(Err(None)) }; } NodeType::Literal { string, .. } => { if raw_args.pop() != Some(string) { - return Ok(false); + return Ok(Err(None)); } } NodeType::Argument { consumer: consume, name, .. - } => { - if let Some(consumed) = consume(src, &mut raw_args) { + } => match consume(src, server, &mut raw_args) { + Ok(consumed) => { parsed_args.insert(name, consumed); - } else { - return Ok(false); } - } + Err(err) => { + return Ok(Err(err)); + } + }, NodeType::Require { predicate, .. } => { if !predicate(src) { - return Ok(false); + return Ok(Err(None)); } } } } - Ok(false) + Ok(Err(None)) } /// Register a command with the dispatcher. diff --git a/pumpkin/src/commands/mod.rs b/pumpkin/src/commands/mod.rs index ef6e1b230..64825aeba 100644 --- a/pumpkin/src/commands/mod.rs +++ b/pumpkin/src/commands/mod.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use dispatcher::InvalidTreeError; use pumpkin_core::text::TextComponent; use tree::ConsumedArgs; @@ -21,7 +23,7 @@ mod tree_format; pub enum CommandSender<'a> { Rcon(&'a mut Vec), Console, - Player(&'a Player), + Player(Arc), } impl<'a> CommandSender<'a> { @@ -49,9 +51,9 @@ impl<'a> CommandSender<'a> { CommandSender::Rcon(_) => true, } } - pub fn as_mut_player(&mut self) -> Option<&Player> { + pub fn as_mut_player(&mut self) -> Option> { match self { - CommandSender::Player(player) => Some(player), + CommandSender::Player(player) => Some(player.clone()), CommandSender::Console => None, CommandSender::Rcon(_) => None, } diff --git a/pumpkin/src/commands/tree.rs b/pumpkin/src/commands/tree.rs index ebbe3d801..65407dbcb 100644 --- a/pumpkin/src/commands/tree.rs +++ b/pumpkin/src/commands/tree.rs @@ -1,5 +1,5 @@ use super::RunFunctionType; -use crate::commands::CommandSender; +use crate::{commands::CommandSender, server::Server}; use std::collections::{HashMap, VecDeque}; /// see [crate::commands::tree_builder::argument] @@ -9,7 +9,9 @@ pub type RawArgs<'a> = Vec<&'a str>; pub type ConsumedArgs<'a> = HashMap<&'a str, String>; /// see [crate::commands::tree_builder::argument] -pub type ArgumentConsumer<'a> = fn(&CommandSender, &mut RawArgs) -> Option; +/// Provide value or an Optional error message, If no Error message provided the default will be used +pub type ArgumentConsumer<'a> = + fn(&CommandSender, &Server, &mut RawArgs) -> Result>; pub struct Node<'a> { pub(crate) children: Vec, diff --git a/pumpkin/src/entity/player.rs b/pumpkin/src/entity/player.rs index 865c8a58a..5ec86c950 100644 --- a/pumpkin/src/entity/player.rs +++ b/pumpkin/src/entity/player.rs @@ -274,7 +274,7 @@ impl Player { } impl Player { - pub async fn process_packets(&self, server: &Arc) { + pub async fn process_packets(self: &Arc, server: &Arc) { let mut packets = self.client.client_packets_queue.lock(); while let Some(mut packet) = packets.pop_back() { match self.handle_play_packet(server, &mut packet).await { @@ -297,7 +297,7 @@ impl Player { } pub async fn handle_play_packet( - &self, + self: &Arc, server: &Arc, packet: &mut RawPacket, ) -> Result<(), Box> {