diff --git a/pumpkin/src/client/player_packet.rs b/pumpkin/src/client/player_packet.rs index bc7936b88..db709f172 100644 --- a/pumpkin/src/client/player_packet.rs +++ b/pumpkin/src/client/player_packet.rs @@ -1,7 +1,7 @@ use std::f32::consts::PI; use crate::{ - commands::{handle_command, CommandSender}, + commands::CommandSender, entity::player::{ChatMode, Hand, Player}, server::Server, world::player_chunker, @@ -214,7 +214,8 @@ impl Player { } pub fn handle_chat_command(&mut self, server: &mut Server, command: SChatCommand) { - handle_command(&mut CommandSender::Player(self), server, &command.command); + let dispatcher = server.command_dispatcher.clone(); + dispatcher.handle_command(&mut CommandSender::Player(self), server, &command.command); } pub fn handle_player_ground(&mut self, _server: &mut Server, ground: SSetPlayerGround) { diff --git a/pumpkin/src/commands/cmd_help.rs b/pumpkin/src/commands/cmd_help.rs index 8d432a8dd..a2f3238a8 100644 --- a/pumpkin/src/commands/cmd_help.rs +++ b/pumpkin/src/commands/cmd_help.rs @@ -1,74 +1,74 @@ -use crate::commands::dispatcher::InvalidTreeError::InvalidConsumptionError; -use crate::commands::dispatcher::{CommandDispatcher, InvalidTreeError}; -use crate::commands::tree::{Command, CommandTree, ConsumedArgs, RawArgs}; -use crate::commands::tree_builder::argument; -use crate::commands::{dispatcher_init, CommandSender, DISPATCHER}; -use pumpkin_core::text::TextComponent; +// use crate::commands::dispatcher::InvalidTreeError::InvalidConsumptionError; +// 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 pumpkin_core::text::TextComponent; -const NAMES: [&str; 3] = ["help", "h", "?"]; +// const NAMES: [&str; 3] = ["help", "h", "?"]; -const DESCRIPTION: &str = "Print a help message."; +// const DESCRIPTION: &str = "Print a help message."; -const ARG_COMMAND: &str = "command"; +// const ARG_COMMAND: &str = "command"; -fn consume_arg_command(_src: &CommandSender, args: &mut RawArgs) -> Option { - let s = args.pop()?; +// fn consume_arg_command(_src: &CommandSender, args: &mut RawArgs) -> Option { +// let s = args.pop()?; - let dispatcher = DISPATCHER.get_or_init(dispatcher_init); +// let dispatcher = DISPATCHER.get_or_init(dispatcher_init); - dispatcher.get_tree(s).ok().map(|tree| tree.names[0].into()) -} +// dispatcher.get_tree(s).ok().map(|tree| tree.names[0].into()) +// } -fn parse_arg_command<'a>( - consumed_args: &'a ConsumedArgs, - dispatcher: &'a CommandDispatcher, -) -> Result<&'a CommandTree<'a>, InvalidTreeError> { - let command_name = consumed_args - .get(ARG_COMMAND) - .ok_or(InvalidConsumptionError(None))?; +// fn parse_arg_command<'a>( +// consumed_args: &'a ConsumedArgs, +// dispatcher: &'a CommandDispatcher, +// ) -> Result<&'a CommandTree<'a>, InvalidTreeError> { +// let command_name = consumed_args +// .get(ARG_COMMAND) +// .ok_or(InvalidConsumptionError(None))?; - dispatcher - .get_tree(command_name) - .map_err(|_| InvalidConsumptionError(Some(command_name.into()))) -} +// dispatcher +// .get_tree(command_name) +// .map_err(|_| InvalidConsumptionError(Some(command_name.into()))) +// } -pub(crate) fn init_command_tree<'a>() -> CommandTree<'a> { - CommandTree::new(NAMES, DESCRIPTION) - .with_child( - argument(ARG_COMMAND, consume_arg_command).execute(&|sender, _, args| { - let dispatcher = DISPATCHER.get_or_init(dispatcher_init); +// pub(crate) fn init_command_tree<'a>() -> CommandTree<'a> { +// CommandTree::new(NAMES, DESCRIPTION) +// .with_child( +// argument(ARG_COMMAND, consume_arg_command).execute(&|sender, _, args| { +// let dispatcher = DISPATCHER.get_or_init(dispatcher_init); - let tree = parse_arg_command(args, dispatcher)?; +// let tree = parse_arg_command(args, dispatcher)?; - sender.send_message(TextComponent::text(&format!( - "{} - {} Usage: {}", - tree.names.join("/"), - tree.description, - tree - ))); +// sender.send_message(TextComponent::text(&format!( +// "{} - {} Usage: {}", +// tree.names.join("/"), +// tree.description, +// tree +// ))); - Ok(()) - }), - ) - .execute(&|sender, _, _args| { - let dispatcher = DISPATCHER.get_or_init(dispatcher_init); +// Ok(()) +// }), +// ) +// .execute(&|sender, _, _args| { +// let dispatcher = DISPATCHER.get_or_init(dispatcher_init); - let mut keys: Vec<&str> = dispatcher.commands.keys().copied().collect(); - keys.sort(); +// let mut keys: Vec<&str> = dispatcher.commands.keys().copied().collect(); +// keys.sort(); - for key in keys { - let Command::Tree(tree) = &dispatcher.commands[key] else { - continue; - }; +// for key in keys { +// let Command::Tree(tree) = &dispatcher.commands[key] else { +// continue; +// }; - sender.send_message(TextComponent::text(&format!( - "{} - {} Usage: {}", - tree.names.join("/"), - tree.description, - tree - ))); - } +// sender.send_message(TextComponent::text(&format!( +// "{} - {} Usage: {}", +// tree.names.join("/"), +// tree.description, +// tree +// ))); +// } - Ok(()) - }) -} +// Ok(()) +// }) +// } diff --git a/pumpkin/src/commands/dispatcher.rs b/pumpkin/src/commands/dispatcher.rs index 25e912055..04ccc3b77 100644 --- a/pumpkin/src/commands/dispatcher.rs +++ b/pumpkin/src/commands/dispatcher.rs @@ -1,3 +1,5 @@ +use pumpkin_core::text::TextComponent; + use crate::commands::dispatcher::InvalidTreeError::{ InvalidConsumptionError, InvalidRequirementError, }; @@ -17,12 +19,21 @@ pub(crate) enum InvalidTreeError { InvalidRequirementError, } -pub(crate) struct CommandDispatcher<'a> { +#[derive(Default)] +pub struct CommandDispatcher<'a> { pub(crate) commands: HashMap<&'a str, Command<'a>>, } /// Stores registered [CommandTree]s and dispatches commands to them. impl<'a> CommandDispatcher<'a> { + pub fn handle_command(&self, sender: &mut CommandSender, server: &mut Server, cmd: &str) { + if let Err(err) = self.dispatch(sender, server, cmd) { + sender.send_message( + TextComponent::text(&err).color_named(pumpkin_core::text::color::NamedColor::Red), + ) + } + } + /// Execute a command using its corresponding [CommandTree]. pub(crate) fn dispatch( &'a self, diff --git a/pumpkin/src/commands/mod.rs b/pumpkin/src/commands/mod.rs index 1321ec665..e92cfdd79 100644 --- a/pumpkin/src/commands/mod.rs +++ b/pumpkin/src/commands/mod.rs @@ -1,16 +1,13 @@ use pumpkin_core::text::TextComponent; -use std::collections::HashMap; -use std::sync::OnceLock; use crate::commands::dispatcher::CommandDispatcher; use crate::entity::player::Player; -use crate::server::Server; mod arg_player; mod cmd_gamemode; mod cmd_help; mod cmd_pumpkin; mod cmd_stop; -mod dispatcher; +pub mod dispatcher; mod tree; mod tree_builder; mod tree_format; @@ -64,32 +61,13 @@ impl<'a> CommandSender<'a> { } } -/// todo: reconsider using constant -/// -/// Central point from which commands are dispatched. Should always be initialized using -/// [dispatcher_init]. -static DISPATCHER: OnceLock = OnceLock::new(); - -/// create [CommandDispatcher] instance for [DISPATCHER] -fn dispatcher_init<'a>() -> CommandDispatcher<'a> { - let mut dispatcher = CommandDispatcher { - commands: HashMap::new(), - }; +pub fn default_dispatcher<'a>() -> CommandDispatcher<'a> { + let mut dispatcher = CommandDispatcher::default(); dispatcher.register(cmd_pumpkin::init_command_tree()); dispatcher.register(cmd_gamemode::init_command_tree()); dispatcher.register(cmd_stop::init_command_tree()); - dispatcher.register(cmd_help::init_command_tree()); + // dispatcher.register(cmd_help::init_command_tree()); dispatcher } - -pub fn handle_command(sender: &mut CommandSender, server: &mut Server, cmd: &str) { - let dispatcher = DISPATCHER.get_or_init(dispatcher_init); - - if let Err(err) = dispatcher.dispatch(sender, server, cmd) { - sender.send_message( - TextComponent::text(&err).color_named(pumpkin_core::text::color::NamedColor::Red), - ) - } -} diff --git a/pumpkin/src/commands/tree.rs b/pumpkin/src/commands/tree.rs index 63243be59..6caf9c0d6 100644 --- a/pumpkin/src/commands/tree.rs +++ b/pumpkin/src/commands/tree.rs @@ -44,6 +44,7 @@ pub(crate) struct CommandTree<'a> { pub(crate) nodes: Vec>, pub(crate) children: Vec, pub(crate) names: Vec<&'a str>, + #[expect(dead_code)] pub(crate) description: &'a str, } diff --git a/pumpkin/src/main.rs b/pumpkin/src/main.rs index 3ac0c7840..3f88fd85d 100644 --- a/pumpkin/src/main.rs +++ b/pumpkin/src/main.rs @@ -10,7 +10,6 @@ use std::collections::HashMap; use std::io::{self}; use client::{interrupted, Client}; -use commands::handle_command; use server::Server; // Setup some tokens to allow us to identify which event is for which socket. @@ -98,7 +97,12 @@ fn main() -> io::Result<()> { if !out.is_empty() { let mut server = server1.lock().await; - handle_command(&mut commands::CommandSender::Console, &mut server, &out); + let dispatcher = server.command_dispatcher.clone(); + dispatcher.handle_command( + &mut commands::CommandSender::Console, + &mut server, + &out, + ); } } }); diff --git a/pumpkin/src/rcon/mod.rs b/pumpkin/src/rcon/mod.rs index 19a5b17d6..126ad5735 100644 --- a/pumpkin/src/rcon/mod.rs +++ b/pumpkin/src/rcon/mod.rs @@ -12,7 +12,7 @@ use packet::{Packet, PacketError, PacketType}; use pumpkin_config::RCONConfig; use thiserror::Error; -use crate::{commands::handle_command, server::Server}; +use crate::server::Server; mod packet; @@ -194,7 +194,8 @@ impl RCONClient { if self.logged_in { let mut output = Vec::new(); let mut server = server.lock().await; - handle_command( + let dispatcher = server.command_dispatcher.clone(); + dispatcher.handle_command( &mut crate::commands::CommandSender::Rcon(&mut output), &mut server, packet.get_body(), diff --git a/pumpkin/src/server/mod.rs b/pumpkin/src/server/mod.rs index 8791677d8..9f3721e1c 100644 --- a/pumpkin/src/server/mod.rs +++ b/pumpkin/src/server/mod.rs @@ -24,7 +24,12 @@ use pumpkin_world::dimension::Dimension; use pumpkin_registry::Registry; use rsa::{traits::PublicKeyParts, RsaPrivateKey, RsaPublicKey}; -use crate::{client::Client, entity::player::Player, world::World}; +use crate::{ + client::Client, + commands::{default_dispatcher, dispatcher::CommandDispatcher}, + entity::player::Player, + world::World, +}; pub const CURRENT_MC_VERSION: &str = "1.21.1"; @@ -35,6 +40,8 @@ pub struct Server { pub plugin_loader: PluginLoader, + pub command_dispatcher: Arc>, + pub worlds: Vec>>, pub status_response: StatusResponse, // We cache the json response here so we don't parse it every time someone makes a Status request. @@ -81,6 +88,8 @@ impl Server { None }; + // First register default command, after that plugins can put in their own + let command_dispatcher = default_dispatcher(); log::info!("Loading Plugins"); let plugin_loader = PluginLoader::load(); @@ -88,7 +97,6 @@ impl Server { // TODO: load form config "./world".parse().unwrap(), )); - Self { plugin_loader, cached_registry: Registry::get_static(), @@ -98,6 +106,7 @@ impl Server { public_key, cached_server_brand, private_key, + command_dispatcher: Arc::new(command_dispatcher), status_response, status_response_json, public_key_der,