Command system rewrite
Note: Help commands is currently disabled
This commit is contained in:
parent
2ee9710f93
commit
3d14e1310b
@ -1,7 +1,7 @@
|
|||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
commands::{handle_command, CommandSender},
|
commands::CommandSender,
|
||||||
entity::player::{ChatMode, Hand, Player},
|
entity::player::{ChatMode, Hand, Player},
|
||||||
server::Server,
|
server::Server,
|
||||||
world::player_chunker,
|
world::player_chunker,
|
||||||
@ -214,7 +214,8 @@ impl Player {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_chat_command(&mut self, server: &mut Server, command: SChatCommand) {
|
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) {
|
pub fn handle_player_ground(&mut self, _server: &mut Server, ground: SSetPlayerGround) {
|
||||||
|
|||||||
@ -1,74 +1,74 @@
|
|||||||
use crate::commands::dispatcher::InvalidTreeError::InvalidConsumptionError;
|
// use crate::commands::dispatcher::InvalidTreeError::InvalidConsumptionError;
|
||||||
use crate::commands::dispatcher::{CommandDispatcher, InvalidTreeError};
|
// use crate::commands::dispatcher::{CommandDispatcher, InvalidTreeError};
|
||||||
use crate::commands::tree::{Command, CommandTree, ConsumedArgs, RawArgs};
|
// use crate::commands::tree::{Command, CommandTree, ConsumedArgs, RawArgs};
|
||||||
use crate::commands::tree_builder::argument;
|
// use crate::commands::tree_builder::argument;
|
||||||
use crate::commands::{dispatcher_init, CommandSender, DISPATCHER};
|
// use crate::commands::{CommandSender};
|
||||||
use pumpkin_core::text::TextComponent;
|
// 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<String> {
|
// fn consume_arg_command(_src: &CommandSender, args: &mut RawArgs) -> Option<String> {
|
||||||
let s = args.pop()?;
|
// 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>(
|
// fn parse_arg_command<'a>(
|
||||||
consumed_args: &'a ConsumedArgs,
|
// consumed_args: &'a ConsumedArgs,
|
||||||
dispatcher: &'a CommandDispatcher,
|
// dispatcher: &'a CommandDispatcher,
|
||||||
) -> Result<&'a CommandTree<'a>, InvalidTreeError> {
|
// ) -> Result<&'a CommandTree<'a>, InvalidTreeError> {
|
||||||
let command_name = consumed_args
|
// let command_name = consumed_args
|
||||||
.get(ARG_COMMAND)
|
// .get(ARG_COMMAND)
|
||||||
.ok_or(InvalidConsumptionError(None))?;
|
// .ok_or(InvalidConsumptionError(None))?;
|
||||||
|
|
||||||
dispatcher
|
// dispatcher
|
||||||
.get_tree(command_name)
|
// .get_tree(command_name)
|
||||||
.map_err(|_| InvalidConsumptionError(Some(command_name.into())))
|
// .map_err(|_| InvalidConsumptionError(Some(command_name.into())))
|
||||||
}
|
// }
|
||||||
|
|
||||||
pub(crate) fn init_command_tree<'a>() -> CommandTree<'a> {
|
// pub(crate) fn init_command_tree<'a>() -> CommandTree<'a> {
|
||||||
CommandTree::new(NAMES, DESCRIPTION)
|
// CommandTree::new(NAMES, DESCRIPTION)
|
||||||
.with_child(
|
// .with_child(
|
||||||
argument(ARG_COMMAND, consume_arg_command).execute(&|sender, _, args| {
|
// argument(ARG_COMMAND, consume_arg_command).execute(&|sender, _, args| {
|
||||||
let dispatcher = DISPATCHER.get_or_init(dispatcher_init);
|
// 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!(
|
// sender.send_message(TextComponent::text(&format!(
|
||||||
"{} - {} Usage: {}",
|
// "{} - {} Usage: {}",
|
||||||
tree.names.join("/"),
|
// tree.names.join("/"),
|
||||||
tree.description,
|
// tree.description,
|
||||||
tree
|
// tree
|
||||||
)));
|
// )));
|
||||||
|
|
||||||
Ok(())
|
// Ok(())
|
||||||
}),
|
// }),
|
||||||
)
|
// )
|
||||||
.execute(&|sender, _, _args| {
|
// .execute(&|sender, _, _args| {
|
||||||
let dispatcher = DISPATCHER.get_or_init(dispatcher_init);
|
// let dispatcher = DISPATCHER.get_or_init(dispatcher_init);
|
||||||
|
|
||||||
let mut keys: Vec<&str> = dispatcher.commands.keys().copied().collect();
|
// let mut keys: Vec<&str> = dispatcher.commands.keys().copied().collect();
|
||||||
keys.sort();
|
// keys.sort();
|
||||||
|
|
||||||
for key in keys {
|
// for key in keys {
|
||||||
let Command::Tree(tree) = &dispatcher.commands[key] else {
|
// let Command::Tree(tree) = &dispatcher.commands[key] else {
|
||||||
continue;
|
// continue;
|
||||||
};
|
// };
|
||||||
|
|
||||||
sender.send_message(TextComponent::text(&format!(
|
// sender.send_message(TextComponent::text(&format!(
|
||||||
"{} - {} Usage: {}",
|
// "{} - {} Usage: {}",
|
||||||
tree.names.join("/"),
|
// tree.names.join("/"),
|
||||||
tree.description,
|
// tree.description,
|
||||||
tree
|
// tree
|
||||||
)));
|
// )));
|
||||||
}
|
// }
|
||||||
|
|
||||||
Ok(())
|
// Ok(())
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
use pumpkin_core::text::TextComponent;
|
||||||
|
|
||||||
use crate::commands::dispatcher::InvalidTreeError::{
|
use crate::commands::dispatcher::InvalidTreeError::{
|
||||||
InvalidConsumptionError, InvalidRequirementError,
|
InvalidConsumptionError, InvalidRequirementError,
|
||||||
};
|
};
|
||||||
@ -17,12 +19,21 @@ pub(crate) enum InvalidTreeError {
|
|||||||
InvalidRequirementError,
|
InvalidRequirementError,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct CommandDispatcher<'a> {
|
#[derive(Default)]
|
||||||
|
pub struct CommandDispatcher<'a> {
|
||||||
pub(crate) commands: HashMap<&'a str, Command<'a>>,
|
pub(crate) commands: HashMap<&'a str, Command<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stores registered [CommandTree]s and dispatches commands to them.
|
/// Stores registered [CommandTree]s and dispatches commands to them.
|
||||||
impl<'a> CommandDispatcher<'a> {
|
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].
|
/// Execute a command using its corresponding [CommandTree].
|
||||||
pub(crate) fn dispatch(
|
pub(crate) fn dispatch(
|
||||||
&'a self,
|
&'a self,
|
||||||
|
|||||||
@ -1,16 +1,13 @@
|
|||||||
use pumpkin_core::text::TextComponent;
|
use pumpkin_core::text::TextComponent;
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::sync::OnceLock;
|
|
||||||
|
|
||||||
use crate::commands::dispatcher::CommandDispatcher;
|
use crate::commands::dispatcher::CommandDispatcher;
|
||||||
use crate::entity::player::Player;
|
use crate::entity::player::Player;
|
||||||
use crate::server::Server;
|
|
||||||
mod arg_player;
|
mod arg_player;
|
||||||
mod cmd_gamemode;
|
mod cmd_gamemode;
|
||||||
mod cmd_help;
|
mod cmd_help;
|
||||||
mod cmd_pumpkin;
|
mod cmd_pumpkin;
|
||||||
mod cmd_stop;
|
mod cmd_stop;
|
||||||
mod dispatcher;
|
pub mod dispatcher;
|
||||||
mod tree;
|
mod tree;
|
||||||
mod tree_builder;
|
mod tree_builder;
|
||||||
mod tree_format;
|
mod tree_format;
|
||||||
@ -64,32 +61,13 @@ impl<'a> CommandSender<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// todo: reconsider using constant
|
pub fn default_dispatcher<'a>() -> CommandDispatcher<'a> {
|
||||||
///
|
let mut dispatcher = CommandDispatcher::default();
|
||||||
/// Central point from which commands are dispatched. Should always be initialized using
|
|
||||||
/// [dispatcher_init].
|
|
||||||
static DISPATCHER: OnceLock<CommandDispatcher> = OnceLock::new();
|
|
||||||
|
|
||||||
/// create [CommandDispatcher] instance for [DISPATCHER]
|
|
||||||
fn dispatcher_init<'a>() -> CommandDispatcher<'a> {
|
|
||||||
let mut dispatcher = CommandDispatcher {
|
|
||||||
commands: HashMap::new(),
|
|
||||||
};
|
|
||||||
|
|
||||||
dispatcher.register(cmd_pumpkin::init_command_tree());
|
dispatcher.register(cmd_pumpkin::init_command_tree());
|
||||||
dispatcher.register(cmd_gamemode::init_command_tree());
|
dispatcher.register(cmd_gamemode::init_command_tree());
|
||||||
dispatcher.register(cmd_stop::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
|
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),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -44,6 +44,7 @@ pub(crate) struct CommandTree<'a> {
|
|||||||
pub(crate) nodes: Vec<Node<'a>>,
|
pub(crate) nodes: Vec<Node<'a>>,
|
||||||
pub(crate) children: Vec<usize>,
|
pub(crate) children: Vec<usize>,
|
||||||
pub(crate) names: Vec<&'a str>,
|
pub(crate) names: Vec<&'a str>,
|
||||||
|
#[expect(dead_code)]
|
||||||
pub(crate) description: &'a str,
|
pub(crate) description: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,6 @@ use std::collections::HashMap;
|
|||||||
use std::io::{self};
|
use std::io::{self};
|
||||||
|
|
||||||
use client::{interrupted, Client};
|
use client::{interrupted, Client};
|
||||||
use commands::handle_command;
|
|
||||||
use server::Server;
|
use server::Server;
|
||||||
|
|
||||||
// Setup some tokens to allow us to identify which event is for which socket.
|
// 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() {
|
if !out.is_empty() {
|
||||||
let mut server = server1.lock().await;
|
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,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -12,7 +12,7 @@ use packet::{Packet, PacketError, PacketType};
|
|||||||
use pumpkin_config::RCONConfig;
|
use pumpkin_config::RCONConfig;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::{commands::handle_command, server::Server};
|
use crate::server::Server;
|
||||||
|
|
||||||
mod packet;
|
mod packet;
|
||||||
|
|
||||||
@ -194,7 +194,8 @@ impl RCONClient {
|
|||||||
if self.logged_in {
|
if self.logged_in {
|
||||||
let mut output = Vec::new();
|
let mut output = Vec::new();
|
||||||
let mut server = server.lock().await;
|
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 crate::commands::CommandSender::Rcon(&mut output),
|
||||||
&mut server,
|
&mut server,
|
||||||
packet.get_body(),
|
packet.get_body(),
|
||||||
|
|||||||
@ -24,7 +24,12 @@ use pumpkin_world::dimension::Dimension;
|
|||||||
use pumpkin_registry::Registry;
|
use pumpkin_registry::Registry;
|
||||||
use rsa::{traits::PublicKeyParts, RsaPrivateKey, RsaPublicKey};
|
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";
|
pub const CURRENT_MC_VERSION: &str = "1.21.1";
|
||||||
|
|
||||||
@ -35,6 +40,8 @@ pub struct Server {
|
|||||||
|
|
||||||
pub plugin_loader: PluginLoader,
|
pub plugin_loader: PluginLoader,
|
||||||
|
|
||||||
|
pub command_dispatcher: Arc<CommandDispatcher<'static>>,
|
||||||
|
|
||||||
pub worlds: Vec<Arc<tokio::sync::Mutex<World>>>,
|
pub worlds: Vec<Arc<tokio::sync::Mutex<World>>>,
|
||||||
pub status_response: StatusResponse,
|
pub status_response: StatusResponse,
|
||||||
// We cache the json response here so we don't parse it every time someone makes a Status request.
|
// 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
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// First register default command, after that plugins can put in their own
|
||||||
|
let command_dispatcher = default_dispatcher();
|
||||||
log::info!("Loading Plugins");
|
log::info!("Loading Plugins");
|
||||||
let plugin_loader = PluginLoader::load();
|
let plugin_loader = PluginLoader::load();
|
||||||
|
|
||||||
@ -88,7 +97,6 @@ impl Server {
|
|||||||
// TODO: load form config
|
// TODO: load form config
|
||||||
"./world".parse().unwrap(),
|
"./world".parse().unwrap(),
|
||||||
));
|
));
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
plugin_loader,
|
plugin_loader,
|
||||||
cached_registry: Registry::get_static(),
|
cached_registry: Registry::get_static(),
|
||||||
@ -98,6 +106,7 @@ impl Server {
|
|||||||
public_key,
|
public_key,
|
||||||
cached_server_brand,
|
cached_server_brand,
|
||||||
private_key,
|
private_key,
|
||||||
|
command_dispatcher: Arc::new(command_dispatcher),
|
||||||
status_response,
|
status_response,
|
||||||
status_response_json,
|
status_response_json,
|
||||||
public_key_der,
|
public_key_der,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user