From 7347bae275e65351ced7f80098e98aab48889aa4 Mon Sep 17 00:00:00 2001 From: kralverde <80051564+kralverde@users.noreply.github.com> Date: Fri, 25 Oct 2024 05:36:55 -0400 Subject: [PATCH] make commands async (#179) --- pumpkin/Cargo.toml | 3 + pumpkin/src/commands/cmd_echest.rs | 48 +++++++---- pumpkin/src/commands/cmd_gamemode.rs | 122 +++++++++++++++++---------- pumpkin/src/commands/cmd_help.rs | 97 +++++++++++++-------- pumpkin/src/commands/cmd_kick.rs | 44 +++++++--- pumpkin/src/commands/cmd_kill.rs | 45 +++++++--- pumpkin/src/commands/cmd_pumpkin.rs | 32 +++++-- pumpkin/src/commands/cmd_stop.rs | 34 ++++++-- pumpkin/src/commands/dispatcher.rs | 32 ++++--- pumpkin/src/commands/mod.rs | 16 +++- pumpkin/src/commands/tree.rs | 3 +- pumpkin/src/commands/tree_builder.rs | 8 +- pumpkin/src/server/mod.rs | 2 +- 13 files changed, 323 insertions(+), 163 deletions(-) diff --git a/pumpkin/Cargo.toml b/pumpkin/Cargo.toml index bbc747a44..4f155c434 100644 --- a/pumpkin/Cargo.toml +++ b/pumpkin/Cargo.toml @@ -63,3 +63,6 @@ png = "0.17.14" # logging simple_logger = { version = "5.0.0", features = ["threads"] } + +# commands +async-trait = "0.1.83" diff --git a/pumpkin/src/commands/cmd_echest.rs b/pumpkin/src/commands/cmd_echest.rs index 252ee26bb..cfcb7379a 100644 --- a/pumpkin/src/commands/cmd_echest.rs +++ b/pumpkin/src/commands/cmd_echest.rs @@ -1,32 +1,44 @@ +use async_trait::async_trait; +use pumpkin_inventory::OpenContainer; + use crate::commands::tree::CommandTree; +use super::RunFunctionType; + const NAMES: [&str; 2] = ["echest", "enderchest"]; const DESCRIPTION: &str = "Show your personal enderchest (this command is used for testing container behaviour)"; -#[allow(unused_variables)] +struct EchestExecutor {} -pub fn init_command_tree<'a>() -> CommandTree<'a> { - CommandTree::new(NAMES, DESCRIPTION).execute(&|sender, server, _| { +#[async_trait] +impl RunFunctionType for EchestExecutor { + async fn execute( + &self, + sender: &mut super::CommandSender, + server: &crate::server::Server, + _args: &super::tree::ConsumedArgs, + ) -> Result<(), super::dispatcher::InvalidTreeError> { if let Some(player) = sender.as_player() { let entity_id = player.entity_id(); - // player.open_container.store(Some(0)); - // { - // let mut open_containers = server.open_containers.write().await; - // match open_containers.get_mut(&0) { - // Some(ender_chest) => { - // ender_chest.add_player(entity_id); - // } - // None => { - // let open_container = OpenContainer::empty(entity_id); - // open_containers.insert(0, open_container); - // } - // } - // } - // player.open_container(server, "minecraft:generic_9x3"); + player.open_container.store(Some(0)); + { + let mut open_containers = server.open_containers.write().await; + if let Some(ender_chest) = open_containers.get_mut(&0) { + ender_chest.add_player(entity_id); + } else { + let open_container = OpenContainer::empty(entity_id); + open_containers.insert(0, open_container); + } + } + player.open_container(server, "minecraft:generic_9x3").await; } Ok(()) - }) + } +} + +pub fn init_command_tree<'a>() -> CommandTree<'a> { + CommandTree::new(NAMES, DESCRIPTION).execute(&EchestExecutor {}) } diff --git a/pumpkin/src/commands/cmd_gamemode.rs b/pumpkin/src/commands/cmd_gamemode.rs index 86d377497..042dd2779 100644 --- a/pumpkin/src/commands/cmd_gamemode.rs +++ b/pumpkin/src/commands/cmd_gamemode.rs @@ -1,8 +1,11 @@ use std::str::FromStr; +use async_trait::async_trait; use num_traits::FromPrimitive; use pumpkin_core::GameMode; +use crate::TextComponent; + use crate::commands::arg_player::{consume_arg_player, parse_arg_player}; use crate::commands::dispatcher::InvalidTreeError; @@ -15,6 +18,8 @@ use crate::commands::CommandSender; use crate::commands::CommandSender::Player; use crate::server::Server; +use super::RunFunctionType; + const NAMES: [&str; 1] = ["gamemode"]; const DESCRIPTION: &str = "Change a player's gamemode."; @@ -63,56 +68,83 @@ pub fn parse_arg_gamemode(consumed_args: &ConsumedArgs) -> Result Result<(), InvalidTreeError> { + let gamemode = parse_arg_gamemode(args)?; + + if let Player(target) = sender { + if target.gamemode.load() == gamemode { + target + .send_system_message(&TextComponent::text(&format!( + "You already in {gamemode:?} gamemode" + ))) + .await; + } else { + target.set_gamemode(gamemode).await; + target + .send_system_message(&TextComponent::text(&format!( + "Game mode was set to {gamemode:?}" + ))) + .await; + } + Ok(()) + } else { + Err(InvalidRequirementError) + } + } +} + +struct GamemodeTargetPlayer {} + +#[async_trait] +impl RunFunctionType for GamemodeTargetPlayer { + async fn execute( + &self, + sender: &mut CommandSender, + server: &Server, + args: &ConsumedArgs, + ) -> Result<(), InvalidTreeError> { + let gamemode = parse_arg_gamemode(args)?; + let target = parse_arg_player(sender, server, ARG_TARGET, args)?; + + if target.gamemode.load() == gamemode { + sender + .send_message(TextComponent::text(&format!( + "{} is already in {:?} gamemode", + target.gameprofile.name, gamemode + ))) + .await; + } else { + target.set_gamemode(gamemode).await; + sender + .send_message(TextComponent::text(&format!( + "{}'s Game mode was set to {:?}", + target.gameprofile.name, gamemode + ))) + .await; + } + + Ok(()) + } +} + +#[allow(clippy::redundant_closure_for_method_calls)] pub fn init_command_tree<'a>() -> CommandTree<'a> { CommandTree::new(NAMES, DESCRIPTION).with_child( require(&|sender| sender.permission_lvl() >= 2).with_child( argument(ARG_GAMEMODE, consume_arg_gamemode) + .with_child(require(&|sender| sender.is_player()).execute(&GamemodeTargetSelf {})) .with_child( - require(&|sender| sender.is_player()).execute(&|sender, _, args| { - let gamemode = parse_arg_gamemode(args)?; - - if let Player(target) = sender { - if target.gamemode.load() == gamemode { - // target.send_system_message(&TextComponent::text(&format!( - // "You already in {:?} gamemode", - // gamemode - // ))); - } else { - // TODO - // target.set_gamemode(gamemode); - // target.send_system_message(&TextComponent::text(&format!( - // "Game mode was set to {:?}", - // gamemode - // ))); - } - Ok(()) - } else { - Err(InvalidRequirementError) - } - }), - ) - .with_child(argument(ARG_TARGET, consume_arg_player).execute( - &|sender, server, args| { - let gamemode = parse_arg_gamemode(args)?; - let target = parse_arg_player(sender, server, ARG_TARGET, args)?; - - if target.gamemode.load() == gamemode { - // sender.send_message(TextComponent::text(&format!( - // "{} is already in {:?} gamemode", - // target.gameprofile.name, gamemode - // ))); - } else { - // TODO - // target.set_gamemode(gamemode); - // sender.send_message(TextComponent::text(&format!( - // "{}'s Game mode was set to {:?}", - // target.gameprofile.name, gamemode - // ))); - } - - Ok(()) - }, - )), + argument(ARG_TARGET, consume_arg_player).execute(&GamemodeTargetPlayer {}), + ), ), ) } diff --git a/pumpkin/src/commands/cmd_help.rs b/pumpkin/src/commands/cmd_help.rs index e37a6ff76..fc627acc1 100644 --- a/pumpkin/src/commands/cmd_help.rs +++ b/pumpkin/src/commands/cmd_help.rs @@ -1,3 +1,6 @@ +use async_trait::async_trait; +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}; @@ -5,6 +8,8 @@ use crate::commands::tree_builder::argument; use crate::commands::CommandSender; use crate::server::Server; +use super::RunFunctionType; + const NAMES: [&str; 3] = ["help", "h", "?"]; const DESCRIPTION: &str = "Print a help message."; @@ -36,41 +41,65 @@ fn parse_arg_command<'a>( .map_err(|_| InvalidConsumptionError(Some(command_name.into()))) } -#[allow(unused_variables)] +struct BaseHelpExecutor {} + +#[async_trait] +impl RunFunctionType for BaseHelpExecutor { + async fn execute( + &self, + sender: &mut CommandSender, + server: &Server, + args: &ConsumedArgs, + ) -> Result<(), InvalidTreeError> { + let tree = parse_arg_command(args, &server.command_dispatcher)?; + + sender + .send_message(TextComponent::text(&format!( + "{} - {} Usage: {}", + tree.names.join("/"), + tree.description, + tree + ))) + .await; + + Ok(()) + } +} + +struct CommandHelpExecutor {} + +#[async_trait] +impl RunFunctionType for CommandHelpExecutor { + async fn execute( + &self, + sender: &mut CommandSender, + server: &Server, + _args: &ConsumedArgs, + ) -> Result<(), InvalidTreeError> { + let mut keys: Vec<&str> = server.command_dispatcher.commands.keys().copied().collect(); + keys.sort_unstable(); + + for key in keys { + let Command::Tree(tree) = &server.command_dispatcher.commands[key] else { + continue; + }; + + sender + .send_message(TextComponent::text(&format!( + "{} - {} Usage: {}", + tree.names.join("/"), + tree.description, + tree + ))) + .await; + } + + Ok(()) + } +} pub fn init_command_tree<'a>() -> CommandTree<'a> { CommandTree::new(NAMES, DESCRIPTION) - .with_child( - argument(ARG_COMMAND, consume_arg_command).execute(&|sender, server, args| { - let tree = parse_arg_command(args, &server.command_dispatcher)?; - - // sender.send_message(TextComponent::text(&format!( - // "{} - {} Usage: {}", - // tree.names.join("/"), - // tree.description, - // tree - // ))); - - Ok(()) - }), - ) - .execute(&|sender, server, _args| { - let mut keys: Vec<&str> = server.command_dispatcher.commands.keys().copied().collect(); - keys.sort_unstable(); - - for key in keys { - let Command::Tree(tree) = &server.command_dispatcher.commands[key] else { - continue; - }; - - // sender.send_message(TextComponent::text(&format!( - // "{} - {} Usage: {}", - // tree.names.join("/"), - // tree.description, - // tree - // ))); - } - - Ok(()) - }) + .with_child(argument(ARG_COMMAND, consume_arg_command).execute(&BaseHelpExecutor {})) + .execute(&CommandHelpExecutor {}) } diff --git a/pumpkin/src/commands/cmd_kick.rs b/pumpkin/src/commands/cmd_kick.rs index 783e4516f..e4625b8bc 100644 --- a/pumpkin/src/commands/cmd_kick.rs +++ b/pumpkin/src/commands/cmd_kick.rs @@ -1,27 +1,45 @@ +use async_trait::async_trait; +use pumpkin_core::text::color::NamedColor; +use pumpkin_core::text::TextComponent; + use crate::commands::arg_player::parse_arg_player; use crate::commands::tree::CommandTree; use crate::commands::tree_builder::argument; use super::arg_player::consume_arg_player; +use super::RunFunctionType; const NAMES: [&str; 1] = ["kick"]; const DESCRIPTION: &str = "Kicks the target player from the server."; const ARG_TARGET: &str = "target"; -#[expect(unused)] +struct KickExecutor {} + +#[async_trait] +impl RunFunctionType for KickExecutor { + async fn execute( + &self, + sender: &mut super::CommandSender, + server: &crate::server::Server, + args: &super::tree::ConsumedArgs, + ) -> Result<(), super::dispatcher::InvalidTreeError> { + let target = parse_arg_player(sender, server, ARG_TARGET, args)?; + target + .kick(TextComponent::text("Kicked by an operator")) + .await; + + sender + .send_message( + TextComponent::text("Player has been kicked.").color_named(NamedColor::Blue), + ) + .await; + + Ok(()) + } +} pub fn init_command_tree<'a>() -> CommandTree<'a> { - CommandTree::new(NAMES, DESCRIPTION).with_child( - argument(ARG_TARGET, consume_arg_player).execute(&|sender, server, args| { - let target = parse_arg_player(sender, server, ARG_TARGET, args)?; - // target.kick(TextComponent::text("Kicked by an operator")); - - // sender.send_message( - // TextComponent::text("Player has been kicked.").color_named(NamedColor::Blue), - // ); - - Ok(()) - }), - ) + CommandTree::new(NAMES, DESCRIPTION) + .with_child(argument(ARG_TARGET, consume_arg_player).execute(&KickExecutor {})) } diff --git a/pumpkin/src/commands/cmd_kill.rs b/pumpkin/src/commands/cmd_kill.rs index f820a1f81..9475c6bbb 100644 --- a/pumpkin/src/commands/cmd_kill.rs +++ b/pumpkin/src/commands/cmd_kill.rs @@ -1,26 +1,43 @@ +use async_trait::async_trait; +use pumpkin_core::text::color::NamedColor; +use pumpkin_core::text::TextComponent; + use crate::commands::arg_player::{consume_arg_player, parse_arg_player}; use crate::commands::tree::CommandTree; use crate::commands::tree_builder::argument; +use super::RunFunctionType; + const NAMES: [&str; 1] = ["kill"]; const DESCRIPTION: &str = "Kills a target player."; const ARG_TARGET: &str = "target"; -#[expect(unused)] +struct KillExecutor {} + +#[async_trait] +impl RunFunctionType for KillExecutor { + async fn execute( + &self, + sender: &mut super::CommandSender, + server: &crate::server::Server, + args: &super::tree::ConsumedArgs, + ) -> Result<(), super::dispatcher::InvalidTreeError> { + // TODO parse entities not only players + let target = parse_arg_player(sender, server, ARG_TARGET, args)?; + target.living_entity.kill().await; + + sender + .send_message( + TextComponent::text("Player has been killed.").color_named(NamedColor::Blue), + ) + .await; + + Ok(()) + } +} pub fn init_command_tree<'a>() -> CommandTree<'a> { - CommandTree::new(NAMES, DESCRIPTION).with_child( - 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(); - - // sender.send_message( - // TextComponent::text("Player has been killed.").color_named(NamedColor::Blue), - // ); - - Ok(()) - }), - ) + CommandTree::new(NAMES, DESCRIPTION) + .with_child(argument(ARG_TARGET, consume_arg_player).execute(&KillExecutor {})) } diff --git a/pumpkin/src/commands/cmd_pumpkin.rs b/pumpkin/src/commands/cmd_pumpkin.rs index 29d4d73ce..c7b3daf17 100644 --- a/pumpkin/src/commands/cmd_pumpkin.rs +++ b/pumpkin/src/commands/cmd_pumpkin.rs @@ -1,20 +1,36 @@ -use crate::commands::tree::CommandTree; +use async_trait::async_trait; +use pumpkin_core::text::{color::NamedColor, TextComponent}; +use pumpkin_protocol::CURRENT_MC_PROTOCOL; + +use crate::{commands::tree::CommandTree, server::CURRENT_MC_VERSION}; + +use super::RunFunctionType; const NAMES: [&str; 1] = ["pumpkin"]; const DESCRIPTION: &str = "Display information about Pumpkin."; -#[expect(unused)] +struct PumpkinExecutor {} -pub fn init_command_tree<'a>() -> CommandTree<'a> { - CommandTree::new(NAMES, DESCRIPTION).execute(&|sender, _, _| { +#[async_trait] +impl RunFunctionType for PumpkinExecutor { + async fn execute( + &self, + sender: &mut super::CommandSender, + _server: &crate::server::Server, + _args: &super::tree::ConsumedArgs, + ) -> Result<(), super::dispatcher::InvalidTreeError> { let version = env!("CARGO_PKG_VERSION"); let description = env!("CARGO_PKG_DESCRIPTION"); - // sender.send_message(TextComponent::text( - // &format!("Pumpkin {version}, {description} (Minecraft {CURRENT_MC_VERSION}, Protocol {CURRENT_MC_PROTOCOL})") - // ).color_named(NamedColor::Green)).await; + sender.send_message(TextComponent::text( + &format!("Pumpkin {version}, {description} (Minecraft {CURRENT_MC_VERSION}, Protocol {CURRENT_MC_PROTOCOL})") + ).color_named(NamedColor::Green)).await; Ok(()) - }) + } +} + +pub fn init_command_tree<'a>() -> CommandTree<'a> { + CommandTree::new(NAMES, DESCRIPTION).execute(&PumpkinExecutor {}) } diff --git a/pumpkin/src/commands/cmd_stop.rs b/pumpkin/src/commands/cmd_stop.rs index 8de9c09fd..fcef4bd84 100644 --- a/pumpkin/src/commands/cmd_stop.rs +++ b/pumpkin/src/commands/cmd_stop.rs @@ -1,16 +1,36 @@ +use async_trait::async_trait; +use pumpkin_core::text::color::NamedColor; +use pumpkin_core::text::TextComponent; + use crate::commands::tree::CommandTree; use crate::commands::tree_builder::require; +use super::RunFunctionType; + const NAMES: [&str; 1] = ["stop"]; const DESCRIPTION: &str = "Stop the server."; +struct StopExecutor {} + +#[async_trait] +impl RunFunctionType for StopExecutor { + async fn execute( + &self, + sender: &mut super::CommandSender, + _server: &crate::server::Server, + _args: &super::tree::ConsumedArgs, + ) -> Result<(), super::dispatcher::InvalidTreeError> { + sender + .send_message(TextComponent::text("Stopping Server").color_named(NamedColor::Red)) + .await; + + // TODO: Gracefully stop + std::process::exit(0) + } +} + pub fn init_command_tree<'a>() -> CommandTree<'a> { - CommandTree::new(NAMES, DESCRIPTION).with_child( - require(&|sender| sender.permission_lvl() >= 4).execute(&|_sender, _, _args| { - // sender - // .send_message(TextComponent::text("Stopping Server").color_named(NamedColor::Red)); - std::process::exit(0) - }), - ) + CommandTree::new(NAMES, DESCRIPTION) + .with_child(require(&|sender| sender.permission_lvl() >= 4).execute(&StopExecutor {})) } diff --git a/pumpkin/src/commands/dispatcher.rs b/pumpkin/src/commands/dispatcher.rs index 1577e3c53..72a552e7a 100644 --- a/pumpkin/src/commands/dispatcher.rs +++ b/pumpkin/src/commands/dispatcher.rs @@ -26,8 +26,13 @@ pub struct CommandDispatcher<'a> { /// Stores registered [`CommandTree`]s and dispatches commands to them. impl<'a> CommandDispatcher<'a> { - pub async fn handle_command(&self, sender: &mut CommandSender<'a>, server: &Server, cmd: &str) { - if let Err(err) = self.dispatch(sender, server, cmd) { + pub async fn handle_command( + &'a self, + sender: &mut CommandSender<'a>, + server: &Server, + cmd: &'a str, + ) { + if let Err(err) = self.dispatch(sender, server, cmd).await { sender .send_message( TextComponent::text_string(err) @@ -38,13 +43,14 @@ impl<'a> CommandDispatcher<'a> { } /// Execute a command using its corresponding [`CommandTree`]. - pub(crate) fn dispatch( + pub(crate) async fn dispatch( &'a self, - src: &mut CommandSender, + src: &mut CommandSender<'a>, server: &Server, - cmd: &str, + cmd: &'a str, ) -> Result<(), String> { - let mut parts = cmd.split_ascii_whitespace(); + // Other languages dont use the ascii whitespace + let mut parts = cmd.split_whitespace(); let key = parts.next().ok_or("Empty Command")?; let raw_args: Vec<&str> = parts.rev().collect(); @@ -52,7 +58,7 @@ impl<'a> CommandDispatcher<'a> { // try paths until fitting path is found for path in tree.iter_paths() { - match Self::try_is_fitting_path(src, server, &path, tree, raw_args.clone()) { + match Self::try_is_fitting_path(src, server, &path, tree, raw_args.clone()).await { Err(InvalidConsumptionError(s)) => { println!("Error while parsing command \"{cmd}\": {s:?} was consumed, but couldn't be parsed"); return Err("Internal Error (See logs for details)".into()); @@ -90,20 +96,20 @@ impl<'a> CommandDispatcher<'a> { } } - fn try_is_fitting_path( - src: &mut CommandSender, + async fn try_is_fitting_path( + src: &mut CommandSender<'a>, server: &Server, path: &[usize], - tree: &CommandTree, - mut raw_args: RawArgs, + tree: &CommandTree<'a>, + mut raw_args: RawArgs<'a>, ) -> Result>, InvalidTreeError> { let mut parsed_args: ConsumedArgs = HashMap::new(); for node in path.iter().map(|&i| &tree.nodes[i]) { match node.node_type { - NodeType::ExecuteLeaf { run } => { + NodeType::ExecuteLeaf { executor } => { return if raw_args.is_empty() { - run(src, server, &parsed_args)?; + executor.execute(src, server, &parsed_args).await?; Ok(Ok(())) } else { Ok(Err(None)) diff --git a/pumpkin/src/commands/mod.rs b/pumpkin/src/commands/mod.rs index 36fa2abed..5089d5aad 100644 --- a/pumpkin/src/commands/mod.rs +++ b/pumpkin/src/commands/mod.rs @@ -1,5 +1,6 @@ use std::sync::Arc; +use async_trait::async_trait; use dispatcher::InvalidTreeError; use pumpkin_core::text::TextComponent; use tree::ConsumedArgs; @@ -60,7 +61,7 @@ impl<'a> CommandSender<'a> { } #[must_use] -pub fn default_dispatcher<'a>() -> CommandDispatcher<'a> { +pub fn default_dispatcher<'a>() -> Arc> { let mut dispatcher = CommandDispatcher::default(); dispatcher.register(cmd_pumpkin::init_command_tree()); @@ -71,8 +72,15 @@ pub fn default_dispatcher<'a>() -> CommandDispatcher<'a> { dispatcher.register(cmd_kill::init_command_tree()); dispatcher.register(cmd_kick::init_command_tree()); - dispatcher + Arc::new(dispatcher) } -type RunFunctionType = - (dyn Fn(&mut CommandSender, &Server, &ConsumedArgs) -> Result<(), InvalidTreeError> + Sync); +#[async_trait] +pub(crate) trait RunFunctionType: Sync { + async fn execute( + &self, + sender: &mut CommandSender, + server: &Server, + args: &ConsumedArgs, + ) -> Result<(), InvalidTreeError>; +} diff --git a/pumpkin/src/commands/tree.rs b/pumpkin/src/commands/tree.rs index 393008509..d69b72bec 100644 --- a/pumpkin/src/commands/tree.rs +++ b/pumpkin/src/commands/tree.rs @@ -20,7 +20,7 @@ pub struct Node<'a> { pub enum NodeType<'a> { ExecuteLeaf { - run: &'a RunFunctionType, + executor: &'a dyn RunFunctionType, }, Literal { string: &'a str, @@ -39,7 +39,6 @@ pub enum Command<'a> { Alias(&'a str), } -#[expect(unused)] pub struct CommandTree<'a> { pub(crate) nodes: Vec>, pub(crate) children: Vec, diff --git a/pumpkin/src/commands/tree_builder.rs b/pumpkin/src/commands/tree_builder.rs index 1ef1416b3..b8899d5dc 100644 --- a/pumpkin/src/commands/tree_builder.rs +++ b/pumpkin/src/commands/tree_builder.rs @@ -40,9 +40,9 @@ impl<'a> CommandTree<'a> { /// desired type. /// /// Also see [`NonLeafNodeBuilder::execute`]. - pub fn execute(mut self, run: &'a RunFunctionType) -> Self { + pub fn execute(mut self, executor: &'a dyn RunFunctionType) -> Self { let node = Node { - node_type: NodeType::ExecuteLeaf { run }, + node_type: NodeType::ExecuteLeaf { executor }, children: Vec::new(), }; @@ -113,9 +113,9 @@ impl<'a> NonLeafNodeBuilder<'a> { /// desired type. /// /// Also see [`CommandTree::execute`]. - pub fn execute(mut self, run: &'a RunFunctionType) -> Self { + pub fn execute(mut self, executor: &'a dyn RunFunctionType) -> Self { self.leaf_nodes.push(LeafNodeBuilder { - node_type: NodeType::ExecuteLeaf { run }, + node_type: NodeType::ExecuteLeaf { executor }, }); self diff --git a/pumpkin/src/server/mod.rs b/pumpkin/src/server/mod.rs index 810fab4c5..14f4b8924 100644 --- a/pumpkin/src/server/mod.rs +++ b/pumpkin/src/server/mod.rs @@ -84,7 +84,7 @@ impl Server { // 0 is invalid entity_id: 2.into(), worlds: vec![Arc::new(world)], - command_dispatcher: Arc::new(command_dispatcher), + command_dispatcher, auth_client, key_store: KeyStore::new(), server_listing: Mutex::new(CachedStatus::new()),