Skip to content

Commit

Permalink
make consumers async (#187)
Browse files Browse the repository at this point in the history
  • Loading branch information
kralverde authored Oct 25, 2024
1 parent c152329 commit 29b3c82
Show file tree
Hide file tree
Showing 14 changed files with 146 additions and 120 deletions.
3 changes: 1 addition & 2 deletions pumpkin/src/client/player_packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -347,8 +347,6 @@ impl Player {
}

pub async fn handle_chat_message(&self, chat_message: SChatMessage) {
log::debug!("Received chat message");

let message = chat_message.message;
if message.len() > 256 {
self.kick(TextComponent::text("Oversized message")).await;
Expand All @@ -357,6 +355,7 @@ impl Player {

// TODO: filter message & validation
let gameprofile = &self.gameprofile;
log::info!("<chat>{}: {}", gameprofile.name, message);

let entity = &self.living_entity.entity;
let world = &entity.world;
Expand Down
64 changes: 38 additions & 26 deletions pumpkin/src/commands/arg_player.rs
Original file line number Diff line number Diff line change
@@ -1,48 +1,60 @@
use std::sync::Arc;

use async_trait::async_trait;

use crate::commands::dispatcher::InvalidTreeError;
use crate::commands::dispatcher::InvalidTreeError::InvalidConsumptionError;
use crate::commands::tree::{ConsumedArgs, RawArgs};
use crate::commands::CommandSender;
use crate::server::Server;

use super::tree::ArgumentConsumer;

/// TODO: Seperate base functionality of these two methods into single method
/// todo: implement (so far only own name + @s/@p is implemented)
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());
pub(crate) struct PlayerArgumentConsumer {}

#[async_trait]
impl ArgumentConsumer for PlayerArgumentConsumer {
async fn consume<'a>(
&self,
src: &CommandSender<'a>,
server: &Server,
args: &mut RawArgs<'a>,
) -> Result<String, Option<String>> {
if let Some(arg) = args.pop() {
match arg {
"@s" => {
if src.is_player() {
return Ok(arg.into());
}
return Err(Some("You are not a Player".into()));
}
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_blocking(name).is_some() {
return Ok(name.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).await.is_some() {
return Ok(name.into());
}
}
return Err(Some(format!("Player not found: {arg}")));
}
return Err(Some(format!("Player not found: {arg}")));
}
}
Err(None)
}
Err(None)
}

/// todo: implement (so far only own name + @s/@p is implemented)
pub fn parse_arg_player(
src: &mut CommandSender,
pub async fn parse_arg_player<'a>(
src: &mut CommandSender<'a>,
server: &Server,
arg_name: &str,
consumed_args: &ConsumedArgs,
consumed_args: &ConsumedArgs<'a>,
) -> Result<Arc<crate::entity::player::Player>, InvalidTreeError> {
let s = consumed_args
.get(arg_name)
Expand All @@ -56,7 +68,7 @@ pub fn parse_arg_player(
"@a" | "@e" => todo!(), // todo: implement all players target selector
name => {
for world in &server.worlds {
if let Some(player) = world.get_player_by_name_blocking(name) {
if let Some(player) = world.get_player_by_name(name).await {
return Ok(player);
}
}
Expand Down
6 changes: 3 additions & 3 deletions pumpkin/src/commands/cmd_echest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ struct EchestExecutor {}

#[async_trait]
impl CommandExecutor for EchestExecutor {
async fn execute(
async fn execute<'a>(
&self,
sender: &mut super::CommandSender,
sender: &mut super::CommandSender<'a>,
server: &crate::server::Server,
_args: &super::tree::ConsumedArgs,
_args: &super::tree::ConsumedArgs<'a>,
) -> Result<(), super::dispatcher::InvalidTreeError> {
if let Some(player) = sender.as_player() {
let entity_id = player.entity_id();
Expand Down
61 changes: 35 additions & 26 deletions pumpkin/src/commands/cmd_gamemode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use pumpkin_core::GameMode;

use crate::TextComponent;

use crate::commands::arg_player::{consume_arg_player, parse_arg_player};
use crate::commands::arg_player::parse_arg_player;

use crate::commands::dispatcher::InvalidTreeError;
use crate::commands::dispatcher::InvalidTreeError::{
Expand All @@ -18,6 +18,8 @@ use crate::commands::CommandSender;
use crate::commands::CommandSender::Player;
use crate::server::Server;

use super::arg_player::PlayerArgumentConsumer;
use super::tree::ArgumentConsumer;
use super::CommandExecutor;

const NAMES: [&str; 1] = ["gamemode"];
Expand All @@ -27,27 +29,33 @@ 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,
_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()),
struct GamemodeArgumentConsumer {}

#[async_trait]
impl ArgumentConsumer for GamemodeArgumentConsumer {
async fn consume<'a>(
&self,
_sender: &CommandSender<'a>,
_server: &Server,
args: &mut RawArgs<'a>,
) -> 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(arg) {
Err(_) | Ok(GameMode::Undefined) => {
return Err(Some(format!("Gamemode not found: {arg}")))
match GameMode::from_str(arg) {
Err(_) | Ok(GameMode::Undefined) => {
return Err(Some(format!("Gamemode not found: {arg}")))
}
Ok(_) => return Ok(arg.into()),
}
Ok(_) => return Ok(arg.into()),
}
Err(None)
}
Err(None)
}

pub fn parse_arg_gamemode(consumed_args: &ConsumedArgs) -> Result<GameMode, InvalidTreeError> {
Expand All @@ -72,11 +80,11 @@ struct GamemodeTargetSelf {}

#[async_trait]
impl CommandExecutor for GamemodeTargetSelf {
async fn execute(
async fn execute<'a>(
&self,
sender: &mut CommandSender,
sender: &mut CommandSender<'a>,
_server: &Server,
args: &ConsumedArgs,
args: &ConsumedArgs<'a>,
) -> Result<(), InvalidTreeError> {
let gamemode = parse_arg_gamemode(args)?;

Expand Down Expand Up @@ -106,14 +114,14 @@ struct GamemodeTargetPlayer {}

#[async_trait]
impl CommandExecutor for GamemodeTargetPlayer {
async fn execute(
async fn execute<'a>(
&self,
sender: &mut CommandSender,
sender: &mut CommandSender<'a>,
server: &Server,
args: &ConsumedArgs,
args: &ConsumedArgs<'a>,
) -> Result<(), InvalidTreeError> {
let gamemode = parse_arg_gamemode(args)?;
let target = parse_arg_player(sender, server, ARG_TARGET, args)?;
let target = parse_arg_player(sender, server, ARG_TARGET, args).await?;

if target.gamemode.load() == gamemode {
sender
Expand All @@ -140,10 +148,11 @@ impl CommandExecutor for GamemodeTargetPlayer {
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)
argument(ARG_GAMEMODE, &GamemodeArgumentConsumer {})
.with_child(require(&|sender| sender.is_player()).execute(&GamemodeTargetSelf {}))
.with_child(
argument(ARG_TARGET, consume_arg_player).execute(&GamemodeTargetPlayer {}),
argument(ARG_TARGET, &PlayerArgumentConsumer {})
.execute(&GamemodeTargetPlayer {}),
),
),
)
Expand Down
41 changes: 25 additions & 16 deletions pumpkin/src/commands/cmd_help.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::commands::tree_builder::argument;
use crate::commands::CommandSender;
use crate::server::Server;

use super::tree::ArgumentConsumer;
use super::CommandExecutor;

const NAMES: [&str; 3] = ["help", "h", "?"];
Expand All @@ -16,16 +17,22 @@ const DESCRIPTION: &str = "Print a help message.";

const ARG_COMMAND: &str = "command";

fn consume_arg_command(
_src: &CommandSender,
_server: &Server,
_args: &mut RawArgs,
) -> Result<String, Option<String>> {
// let s = args.pop()?;
struct CommandArgumentConsumer {}

// dispatcher.get_tree(s).ok().map(|tree| tree.names[0].into())
// TODO
Err(None)
#[async_trait]
impl ArgumentConsumer for CommandArgumentConsumer {
async fn consume<'a>(
&self,
_sender: &CommandSender<'a>,
_server: &Server,
_args: &mut RawArgs<'a>,
) -> Result<String, Option<String>> {
//let s = args.pop()?;

// dispatcher.get_tree(s).ok().map(|tree| tree.names[0].into())
// TODO: Implement this
Err(None)
}
}

fn parse_arg_command<'a>(
Expand All @@ -45,11 +52,11 @@ struct BaseHelpExecutor {}

#[async_trait]
impl CommandExecutor for BaseHelpExecutor {
async fn execute(
async fn execute<'a>(
&self,
sender: &mut CommandSender,
sender: &mut CommandSender<'a>,
server: &Server,
args: &ConsumedArgs,
args: &ConsumedArgs<'a>,
) -> Result<(), InvalidTreeError> {
let tree = parse_arg_command(args, &server.command_dispatcher)?;

Expand All @@ -70,11 +77,11 @@ struct CommandHelpExecutor {}

#[async_trait]
impl CommandExecutor for CommandHelpExecutor {
async fn execute(
async fn execute<'a>(
&self,
sender: &mut CommandSender,
sender: &mut CommandSender<'a>,
server: &Server,
_args: &ConsumedArgs,
_args: &ConsumedArgs<'a>,
) -> Result<(), InvalidTreeError> {
let mut keys: Vec<&str> = server.command_dispatcher.commands.keys().copied().collect();
keys.sort_unstable();
Expand All @@ -100,6 +107,8 @@ impl CommandExecutor for CommandHelpExecutor {

pub fn init_command_tree<'a>() -> CommandTree<'a> {
CommandTree::new(NAMES, DESCRIPTION)
.with_child(argument(ARG_COMMAND, consume_arg_command).execute(&BaseHelpExecutor {}))
.with_child(
argument(ARG_COMMAND, &CommandArgumentConsumer {}).execute(&BaseHelpExecutor {}),
)
.execute(&CommandHelpExecutor {})
}
12 changes: 6 additions & 6 deletions pumpkin/src/commands/cmd_kick.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ 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::arg_player::PlayerArgumentConsumer;
use super::CommandExecutor;

const NAMES: [&str; 1] = ["kick"];
Expand All @@ -18,13 +18,13 @@ struct KickExecutor {}

#[async_trait]
impl CommandExecutor for KickExecutor {
async fn execute(
async fn execute<'a>(
&self,
sender: &mut super::CommandSender,
sender: &mut super::CommandSender<'a>,
server: &crate::server::Server,
args: &super::tree::ConsumedArgs,
args: &super::tree::ConsumedArgs<'a>,
) -> Result<(), super::dispatcher::InvalidTreeError> {
let target = parse_arg_player(sender, server, ARG_TARGET, args)?;
let target = parse_arg_player(sender, server, ARG_TARGET, args).await?;
target
.kick(TextComponent::text("Kicked by an operator"))
.await;
Expand All @@ -41,5 +41,5 @@ impl CommandExecutor for KickExecutor {

pub fn init_command_tree<'a>() -> CommandTree<'a> {
CommandTree::new(NAMES, DESCRIPTION)
.with_child(argument(ARG_TARGET, consume_arg_player).execute(&KickExecutor {}))
.with_child(argument(ARG_TARGET, &PlayerArgumentConsumer {}).execute(&KickExecutor {}))
}
13 changes: 7 additions & 6 deletions pumpkin/src/commands/cmd_kill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ 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::arg_player::parse_arg_player;
use crate::commands::tree::CommandTree;
use crate::commands::tree_builder::argument;

use super::arg_player::PlayerArgumentConsumer;
use super::CommandExecutor;

const NAMES: [&str; 1] = ["kill"];
Expand All @@ -17,14 +18,14 @@ struct KillExecutor {}

#[async_trait]
impl CommandExecutor for KillExecutor {
async fn execute(
async fn execute<'a>(
&self,
sender: &mut super::CommandSender,
sender: &mut super::CommandSender<'a>,
server: &crate::server::Server,
args: &super::tree::ConsumedArgs,
args: &super::tree::ConsumedArgs<'a>,
) -> Result<(), super::dispatcher::InvalidTreeError> {
// TODO parse entities not only players
let target = parse_arg_player(sender, server, ARG_TARGET, args)?;
let target = parse_arg_player(sender, server, ARG_TARGET, args).await?;
target.living_entity.kill().await;

sender
Expand All @@ -39,5 +40,5 @@ impl CommandExecutor for KillExecutor {

pub fn init_command_tree<'a>() -> CommandTree<'a> {
CommandTree::new(NAMES, DESCRIPTION)
.with_child(argument(ARG_TARGET, consume_arg_player).execute(&KillExecutor {}))
.with_child(argument(ARG_TARGET, &PlayerArgumentConsumer {}).execute(&KillExecutor {}))
}
Loading

0 comments on commit 29b3c82

Please sign in to comment.