From 0597f36294c0b7323878109fd9e02f1b4ae388f1 Mon Sep 17 00:00:00 2001 From: Kurt Thiemann Date: Fri, 1 May 2026 14:49:41 +0200 Subject: [PATCH 1/2] fix: truncate query packet buffer to actual UDP packet length (#2075) --- pumpkin/src/net/query.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pumpkin/src/net/query.rs b/pumpkin/src/net/query.rs index 14e9c2fb8..315e4482f 100644 --- a/pumpkin/src/net/query.rs +++ b/pumpkin/src/net/query.rs @@ -61,10 +61,12 @@ pub async fn start_query_handler(server: Arc, query_addr: SocketAddr) { () = STOP_INTERRUPT.cancelled() => None, }; - let Some(Ok((_, addr))) = recv_result else { + let Some(Ok((length, addr))) = recv_result else { break; }; + buf.truncate(length); + tokio::spawn(async move { if let Err(err) = handle_packet( buf, From 929bc08dcfcca3c39a399a1b57c63c06cacf4cf5 Mon Sep 17 00:00:00 2001 From: Laptop59 <90901102+Laptop59@users.noreply.github.com> Date: Fri, 1 May 2026 18:20:19 +0530 Subject: [PATCH 2/2] feat(command): reimplement `/banlist` (#2050) * reimplemented `/banlist` command with literal nodes & only one executor * fixed naming of executor * changed description --- pumpkin/src/command/commands/banlist.rs | 224 +++++++++++------------- pumpkin/src/command/commands/mod.rs | 9 +- 2 files changed, 101 insertions(+), 132 deletions(-) diff --git a/pumpkin/src/command/commands/banlist.rs b/pumpkin/src/command/commands/banlist.rs index 491aa93df..a942271dd 100644 --- a/pumpkin/src/command/commands/banlist.rs +++ b/pumpkin/src/command/commands/banlist.rs @@ -1,144 +1,120 @@ -use crate::command::{ - CommandError, CommandExecutor, CommandResult, CommandSender, - args::{Arg, ConsumedArgs, simple::SimpleArgConsumer}, - tree::{CommandTree, builder::argument}, -}; -use CommandError::InvalidConsumption; +use crate::command::argument_builder::{ArgumentBuilder, command, literal}; +use crate::command::context::command_context::CommandContext; +use crate::command::node::dispatcher::CommandDispatcher; +use crate::command::node::{CommandExecutor, CommandExecutorResult}; use pumpkin_data::translation; +use pumpkin_util::PermissionLvl; +use pumpkin_util::permission::{Permission, PermissionDefault, PermissionRegistry}; use pumpkin_util::text::TextComponent; -const NAMES: [&str; 1] = ["banlist"]; -const DESCRIPTION: &str = "shows the banlist"; +const DESCRIPTION: &str = "Prints the banlist of players, IPs, or both at once."; -const ARG_LIST_TYPE: &str = "ips|players"; +const PERMISSION: &str = "minecraft:command.banlist"; -struct ListExecutor; - -impl CommandExecutor for ListExecutor { - fn execute<'a>( - &'a self, - sender: &'a CommandSender, - server: &'a crate::server::Server, - args: &'a ConsumedArgs<'a>, - ) -> CommandResult<'a> { - Box::pin(async move { - let Some(Arg::Simple(list_type)) = args.get(&ARG_LIST_TYPE) else { - return Err(InvalidConsumption(Some(ARG_LIST_TYPE.into()))); - }; - - match *list_type { - "ips" => { - let lock = &server.data.banned_ip_list.read().await; - let entries = lock - .banned_ips - .iter() - .map(|entry| { - ( - entry.ip.to_string(), - entry.source.clone(), - entry.reason.clone(), - ) - }) - .collect(); - - handle_banlist(entries, sender).await - } - "players" => { - let lock = &server.data.banned_player_list.read().await; - let entries = lock - .banned_players - .iter() - .map(|entry| { - ( - entry.name.clone(), - entry.source.clone(), - entry.reason.clone(), - ) - }) - .collect(); - - handle_banlist(entries, sender).await - } - _ => Err(CommandError::CommandFailed(TextComponent::translate( - translation::COMMAND_UNKNOWN_ARGUMENT, - [], - ))), - } - }) - } +struct BanListEntry { + name: String, + source: String, + reason: String, } -struct ListAllExecutor; +struct BanListCommandExecutor { + players: bool, + ips: bool, +} -impl CommandExecutor for ListAllExecutor { - fn execute<'a>( - &'a self, - sender: &'a CommandSender, - server: &'a crate::server::Server, - _args: &'a ConsumedArgs<'a>, - ) -> CommandResult<'a> { +impl CommandExecutor for BanListCommandExecutor { + fn execute<'a>(&'a self, context: &'a CommandContext) -> CommandExecutorResult<'a> { Box::pin(async move { let mut entries = Vec::new(); - for entry in &server.data.banned_player_list.read().await.banned_players { - entries.push(( - entry.name.clone(), - entry.source.clone(), - entry.reason.clone(), - )); + + let data = &context.server().data; + + if self.players { + let lock = data.banned_player_list.read().await; + for entry in &lock.banned_players { + entries.push(BanListEntry { + name: entry.name.clone(), + source: entry.source.clone(), + reason: entry.reason.clone(), + }); + } } - for entry in &server.data.banned_ip_list.read().await.banned_ips { - entries.push(( - entry.ip.to_string(), - entry.source.clone(), - entry.reason.clone(), - )); + if self.ips { + let lock = data.banned_ip_list.read().await; + for entry in &lock.banned_ips { + entries.push(BanListEntry { + name: entry.ip.to_string(), + source: entry.source.clone(), + reason: entry.reason.clone(), + }); + } } - handle_banlist(entries, sender).await + let entries_len = entries.len() as i32; + let source = &context.source; + + if entries.is_empty() { + source + .send_feedback( + TextComponent::translate(translation::COMMANDS_BANLIST_NONE, []), + false, + ) + .await; + } else { + source + .send_feedback( + TextComponent::translate( + translation::COMMANDS_BANLIST_LIST, + [TextComponent::text(entries.len().to_string())], + ), + false, + ) + .await; + + for entry in entries { + source + .send_feedback( + TextComponent::translate( + translation::COMMANDS_BANLIST_ENTRY, + [ + TextComponent::text(entry.name), + TextComponent::text(entry.source), + TextComponent::text(entry.reason), + ], + ), + false, + ) + .await; + } + } + + Ok(entries_len) }) } } -/// `Vec<(name, source, reason)>` -async fn handle_banlist( - list: Vec<(String, String, String)>, - sender: &CommandSender, -) -> Result { - if list.is_empty() { - return Result::Err(CommandError::CommandFailed(TextComponent::translate( - translation::COMMANDS_BANLIST_NONE, - [], - ))); - } +pub fn register(dispatcher: &mut CommandDispatcher, registry: &mut PermissionRegistry) { + registry.register_permission_or_panic(Permission::new( + PERMISSION, + DESCRIPTION, + PermissionDefault::Op(PermissionLvl::Three), + )); - sender - .send_message(TextComponent::translate( - translation::COMMANDS_BANLIST_LIST, - [TextComponent::text(list.len().to_string())], - )) - .await; - - let count = list.len(); - - for (name, source, reason) in list { - sender - .send_message(TextComponent::translate( - translation::COMMANDS_BANLIST_ENTRY, - [ - TextComponent::text(name), - TextComponent::text(source), - TextComponent::text(reason), - ], - )) - .await; - } - - Ok(count as i32) -} - -pub fn init_command_tree() -> CommandTree { - CommandTree::new(NAMES, DESCRIPTION) - .execute(ListAllExecutor) - .then(argument(ARG_LIST_TYPE, SimpleArgConsumer).execute(ListExecutor)) + dispatcher.register( + command("banlist", DESCRIPTION) + .requires(PERMISSION) + .then(literal("ips").executes(BanListCommandExecutor { + players: false, + ips: true, + })) + .then(literal("players").executes(BanListCommandExecutor { + players: true, + ips: false, + })) + .executes(BanListCommandExecutor { + players: true, + ips: true, + }), + ); } diff --git a/pumpkin/src/command/commands/mod.rs b/pumpkin/src/command/commands/mod.rs index 39dc6621b..b37d108dd 100644 --- a/pumpkin/src/command/commands/mod.rs +++ b/pumpkin/src/command/commands/mod.rs @@ -136,7 +136,6 @@ pub async fn default_dispatcher( dispatcher.register(plugins::init_command_tree(), "pumpkin:command.plugins"); dispatcher.register(ban::init_command_tree(), "minecraft:command.ban"); dispatcher.register(banip::init_command_tree(), "minecraft:command.banip"); - dispatcher.register(banlist::init_command_tree(), "minecraft:command.banlist"); dispatcher.register(pardon::init_command_tree(), "minecraft:command.pardon"); dispatcher.register(pardonip::init_command_tree(), "minecraft:command.pardonip"); dispatcher.register( @@ -151,6 +150,7 @@ pub async fn default_dispatcher( wrapper_dispatcher }; + banlist::register(&mut dispatcher, registry); difficulty::register(&mut dispatcher, registry); help::register(&mut dispatcher, registry); kill::register(&mut dispatcher, registry); @@ -459,13 +459,6 @@ fn register_level_3_permissions(registry: &mut PermissionRegistry) { PermissionDefault::Op(PermissionLvl::Three), )) .unwrap(); - registry - .register_permission(Permission::new( - "minecraft:command.banlist", - "Displays banned players or IP addresses", - PermissionDefault::Op(PermissionLvl::Three), - )) - .unwrap(); registry .register_permission(Permission::new( "minecraft:command.pardon",