Support parsing players out of commands and custom error messages
This commit is contained in:
parent
406db91f06
commit
5ac45b0ed5
@ -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<Self>, 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 /{}",
|
||||
|
||||
@ -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<String> {
|
||||
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<String, Option<String>> {
|
||||
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<Arc<crate::entity::player::Player>, 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())))
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<String> {
|
||||
let s = args.pop()?;
|
||||
|
||||
if let Ok(id) = s.parse::<u8>() {
|
||||
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<String, Option<String>> {
|
||||
if let Some(arg) = args.pop() {
|
||||
if let Ok(id) = arg.parse::<u8>() {
|
||||
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<GameMode, InvalidTreeError> {
|
||||
|
||||
@ -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<String> {
|
||||
fn consume_arg_command(
|
||||
_src: &CommandSender,
|
||||
_server: &Server,
|
||||
_args: &mut RawArgs,
|
||||
) -> Result<String, Option<String>> {
|
||||
// let s = args.pop()?;
|
||||
|
||||
// dispatcher.get_tree(s).ok().map(|tree| tree.names[0].into())
|
||||
// TODO
|
||||
None
|
||||
Err(None)
|
||||
}
|
||||
|
||||
fn parse_arg_command<'a>(
|
||||
|
||||
@ -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<String> {
|
||||
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"));
|
||||
|
||||
|
||||
@ -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<String> {
|
||||
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();
|
||||
|
||||
|
||||
@ -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<usize>,
|
||||
tree: &CommandTree,
|
||||
mut raw_args: RawArgs,
|
||||
) -> Result<bool, InvalidTreeError> {
|
||||
) -> Result<Result<(), Option<String>>, 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.
|
||||
|
||||
@ -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<String>),
|
||||
Console,
|
||||
Player(&'a Player),
|
||||
Player(Arc<Player>),
|
||||
}
|
||||
|
||||
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<Arc<Player>> {
|
||||
match self {
|
||||
CommandSender::Player(player) => Some(player),
|
||||
CommandSender::Player(player) => Some(player.clone()),
|
||||
CommandSender::Console => None,
|
||||
CommandSender::Rcon(_) => None,
|
||||
}
|
||||
|
||||
@ -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<String>;
|
||||
/// 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<String, Option<String>>;
|
||||
|
||||
pub struct Node<'a> {
|
||||
pub(crate) children: Vec<usize>,
|
||||
|
||||
@ -274,7 +274,7 @@ impl Player {
|
||||
}
|
||||
|
||||
impl Player {
|
||||
pub async fn process_packets(&self, server: &Arc<Server>) {
|
||||
pub async fn process_packets(self: &Arc<Self>, server: &Arc<Server>) {
|
||||
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<Self>,
|
||||
server: &Arc<Server>,
|
||||
packet: &mut RawPacket,
|
||||
) -> Result<(), Box<dyn PumpkinError>> {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user