Skip to content

Commit

Permalink
make command dispatcher writable (#405)
Browse files Browse the repository at this point in the history
  • Loading branch information
kralverde authored Dec 25, 2024
1 parent 991ac37 commit 0e9b1af
Show file tree
Hide file tree
Showing 12 changed files with 44 additions and 33 deletions.
10 changes: 5 additions & 5 deletions pumpkin/src/command/args/arg_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ impl ArgumentConsumer for CommandTreeArgumentConsumer {
) -> Option<Arg<'a>> {
let s = args.pop()?;

let dispatcher = &server.command_dispatcher;
return dispatcher
let dispatcher = server.command_dispatcher.read().await;
dispatcher
.get_tree(s)
.map_or_else(|_| None, |tree| Some(Arg::CommandTree(tree)));
.map_or_else(|_| None, |tree| Some(Arg::CommandTree(tree)))
}

async fn suggest<'a>(
Expand All @@ -53,8 +53,8 @@ impl ArgumentConsumer for CommandTreeArgumentConsumer {
return Ok(None);
};

let suggestions = server
.command_dispatcher
let dispatcher = server.command_dispatcher.read().await;
let suggestions = dispatcher
.commands
.keys()
.filter(|suggestion| suggestion.starts_with(input))
Expand Down
2 changes: 1 addition & 1 deletion pumpkin/src/command/args/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ pub(crate) enum Arg<'a> {
Pos2D(Vector2<f64>),
Rotation(f32, f32),
GameMode(GameMode),
CommandTree(&'a CommandTree<'a>),
CommandTree(CommandTree<'a>),
Item(&'a str),
ResourceLocation(&'a str),
Block(&'a str),
Expand Down
8 changes: 5 additions & 3 deletions pumpkin/src/command/client_cmd_suggestions.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::sync::Arc;

use pumpkin_protocol::client::play::{CCommands, ProtoNode, ProtoNodeType};
use tokio::sync::RwLock;

use crate::entity::player::Player;

Expand All @@ -11,11 +12,12 @@ use super::{

pub async fn send_c_commands_packet<'a>(
player: &Arc<Player>,
dispatcher: &'a CommandDispatcher<'a>,
dispatcher: &RwLock<CommandDispatcher<'a>>,
) {
let cmd_src = super::CommandSender::Player(player.clone());
let mut first_level = Vec::new();

let dispatcher = dispatcher.read().await;
for key in dispatcher.commands.keys() {
let Ok(tree) = dispatcher.get_tree(key) else {
continue;
Expand Down Expand Up @@ -72,8 +74,8 @@ impl<'a> ProtoNodeBuilder<'a> {

fn nodes_to_proto_node_builders<'a>(
cmd_src: &super::CommandSender,
nodes: &'a [Node<'a>],
children: &'a [usize],
nodes: &[Node<'a>],
children: &[usize],
) -> (bool, Vec<ProtoNodeBuilder<'a>>) {
let mut child_nodes = Vec::new();
let mut is_executable = false;
Expand Down
4 changes: 2 additions & 2 deletions pumpkin/src/command/commands/cmd_help.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,8 @@ impl CommandExecutor for BaseHelpExecutor {
}
};

let mut commands: Vec<&CommandTree> = server
.command_dispatcher
let dispatcher = server.command_dispatcher.read().await;
let mut commands: Vec<&CommandTree> = dispatcher
.commands
.values()
.filter_map(|cmd| match cmd {
Expand Down
24 changes: 18 additions & 6 deletions pumpkin/src/command/dispatcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ impl<'a> CommandDispatcher<'a> {
// try paths and collect the nodes that fail
// todo: make this more fine-grained
for path in tree.iter_paths() {
match Self::try_find_suggestions_on_path(src, server, &path, tree, &mut raw_args, cmd)
match Self::try_find_suggestions_on_path(src, server, &path, &tree, &mut raw_args, cmd)
.await
{
Err(InvalidConsumption(s)) => {
Expand Down Expand Up @@ -151,7 +151,7 @@ impl<'a> CommandDispatcher<'a> {

// try paths until fitting path is found
for path in tree.iter_paths() {
if Self::try_is_fitting_path(src, server, &path, tree, &mut raw_args.clone()).await? {
if Self::try_is_fitting_path(src, server, &path, &tree, &mut raw_args.clone()).await? {
return Ok(());
}
}
Expand All @@ -160,22 +160,22 @@ impl<'a> CommandDispatcher<'a> {
)))
}

pub(crate) fn get_tree(&'a self, key: &str) -> Result<&'a CommandTree<'a>, CommandError> {
pub(crate) fn get_tree(&self, key: &str) -> Result<CommandTree<'a>, CommandError> {
let command = self
.commands
.get(key)
.ok_or(GeneralCommandIssue("Command not found".to_string()))?;

match command {
Command::Tree(tree) => Ok(tree),
Command::Tree(tree) => Ok(tree.clone()),
Command::Alias(target) => {
let Some(Command::Tree(tree)) = &self.commands.get(target) else {
let Some(Command::Tree(tree)) = self.commands.get(target) else {
log::error!("Error while parsing command alias \"{key}\": pointing to \"{target}\" which is not a valid tree");
return Err(GeneralCommandIssue(
"Internal Error (See logs for details)".into(),
));
};
Ok(tree)
Ok(tree.clone())
}
}
}
Expand Down Expand Up @@ -282,3 +282,15 @@ impl<'a> CommandDispatcher<'a> {
self.commands.insert(primary_name, Command::Tree(tree));
}
}

#[cfg(test)]
mod test {
use crate::command::{default_dispatcher, tree::CommandTree};

#[test]
fn test_dynamic_command() {
let mut dispatcher = default_dispatcher();
let tree = CommandTree::new(["test"], "test_desc");
dispatcher.register(tree);
}
}
4 changes: 2 additions & 2 deletions pumpkin/src/command/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ impl<'a> CommandSender<'a> {
}

#[must_use]
pub fn default_dispatcher<'a>() -> Arc<CommandDispatcher<'a>> {
pub fn default_dispatcher<'a>() -> CommandDispatcher<'a> {
let mut dispatcher = CommandDispatcher::default();

dispatcher.register(cmd_pumpkin::init_command_tree());
Expand All @@ -129,7 +129,7 @@ pub fn default_dispatcher<'a>() -> Arc<CommandDispatcher<'a>> {
dispatcher.register(cmd_transfer::init_command_tree());
dispatcher.register(cmd_fill::init_command_tree());

Arc::new(dispatcher)
dispatcher
}

#[async_trait]
Expand Down
5 changes: 3 additions & 2 deletions pumpkin/src/command/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ use std::{collections::VecDeque, fmt::Debug};
/// see [`crate::commands::tree_builder::argument`]
pub type RawArgs<'a> = Vec<&'a str>;

#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct Node<'a> {
pub(crate) children: Vec<usize>,
pub(crate) node_type: NodeType<'a>,
}

#[derive(Clone)]
pub enum NodeType<'a> {
ExecuteLeaf {
executor: &'a dyn CommandExecutor,
Expand Down Expand Up @@ -50,7 +51,7 @@ pub enum Command<'a> {
Alias(&'a str),
}

#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct CommandTree<'a> {
pub(crate) nodes: Vec<Node<'a>>,
pub(crate) children: Vec<usize>,
Expand Down
2 changes: 1 addition & 1 deletion pumpkin/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ fn setup_console(server: Arc<Server>) {
.expect("Failed to read console line");

if !out.is_empty() {
let dispatcher = server.command_dispatcher.clone();
let dispatcher = server.command_dispatcher.read().await;
dispatcher
.handle_command(&mut command::CommandSender::Console, &server, &out)
.await;
Expand Down
8 changes: 3 additions & 5 deletions pumpkin/src/net/packet/play.rs
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ impl Player {
server: &Arc<Server>,
command: SChatCommand,
) {
let dispatcher = server.command_dispatcher.clone();
let dispatcher = server.command_dispatcher.read().await;
dispatcher
.handle_command(
&mut CommandSender::Player(self.clone()),
Expand Down Expand Up @@ -877,10 +877,8 @@ impl Player {
return;
};

let suggestions = server
.command_dispatcher
.find_suggestions(&mut src, server, cmd)
.await;
let dispatcher = server.command_dispatcher.read().await;
let suggestions = dispatcher.find_suggestions(&mut src, server, cmd).await;

let response = CCommandSuggestions::new(
packet.id,
Expand Down
2 changes: 1 addition & 1 deletion pumpkin/src/net/rcon/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ impl RCONClient {
ServerboundPacket::ExecCommand => {
if self.logged_in {
let output = tokio::sync::Mutex::new(Vec::new());
let dispatcher = server.command_dispatcher.clone();
let dispatcher = server.command_dispatcher.read().await;
dispatcher
.handle_command(
&mut crate::command::CommandSender::Rcon(&output),
Expand Down
4 changes: 2 additions & 2 deletions pumpkin/src/server/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ pub struct Server {
/// Saves server branding information.
server_branding: CachedBranding,
/// Saves and Dispatches commands to appropriate handlers.
pub command_dispatcher: Arc<CommandDispatcher<'static>>,
pub command_dispatcher: RwLock<CommandDispatcher<'static>>,
/// Saves and calls blocks blocks
pub block_manager: Arc<BlockManager>,
/// Manages multiple worlds within the server.
Expand Down Expand Up @@ -79,7 +79,7 @@ impl Server {
});

// First register default command, after that plugins can put in their own
let command_dispatcher = default_dispatcher();
let command_dispatcher = RwLock::new(default_dispatcher());

let world = World::load(
Dimension::OverWorld.into_level(
Expand Down
4 changes: 1 addition & 3 deletions pumpkin/src/world/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,6 @@ impl World {
player: Arc<Player>,
server: &Server,
) {
let command_dispatcher = &server.command_dispatcher;
let dimensions: Vec<Identifier> =
server.dimensions.iter().map(DimensionType::name).collect();

Expand Down Expand Up @@ -270,8 +269,7 @@ impl World {
.await;
// permissions, i. e. the commands a player may use
player.send_permission_lvl_update().await;
client_cmd_suggestions::send_c_commands_packet(&player, command_dispatcher).await;

client_cmd_suggestions::send_c_commands_packet(&player, &server.command_dispatcher).await;
// teleport
let mut position = Vector3::new(10.0, 120.0, 10.0);
let yaw = 10.0;
Expand Down

0 comments on commit 0e9b1af

Please sign in to comment.