This commit is contained in:
Alexander Medvedev 2026-05-01 14:51:45 +02:00
commit 81cffe19a2
3 changed files with 104 additions and 133 deletions

View File

@ -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<i32, CommandError> {
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,
}),
);
}

View File

@ -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",

View File

@ -61,10 +61,12 @@ pub async fn start_query_handler(server: Arc<Server>, 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,