remove async_trait from Commands

This decreased compile time by 30%, Plugins also are not required anymore to use async_trait when adding custom Commands
This commit is contained in:
Alexander Medvedev 2025-12-03 18:25:58 +01:00
parent 644023d89f
commit 71392b4a38
86 changed files with 4617 additions and 4575 deletions

58
Cargo.lock generated
View File

@ -493,9 +493,9 @@ checksum = "0dabb6555f92fb9ee4140454eb5dcd14c7960e1225c6d1a6cc361f032947713e"
[[package]]
name = "convert_case"
version = "0.7.1"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb402b8d4c85569410425650ce3eddc7d698ed96d39a73f941b08fb63082f1e7"
checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9"
dependencies = [
"unicode-segmentation",
]
@ -812,22 +812,23 @@ dependencies = [
[[package]]
name = "derive_more"
version = "2.0.1"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678"
checksum = "10b768e943bed7bf2cab53df09f4bc34bfd217cdb57d971e769874c9a6710618"
dependencies = [
"derive_more-impl",
]
[[package]]
name = "derive_more-impl"
version = "2.0.1"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3"
checksum = "6d286bfdaf75e988b4a78e013ecd79c581e06399ab53fbacd2d916c2f904f30b"
dependencies = [
"convert_case",
"proc-macro2",
"quote",
"rustc_version",
"syn",
]
@ -1373,9 +1374,9 @@ dependencies = [
[[package]]
name = "hyper-util"
version = "0.1.18"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52e9a2a24dc5c6821e71a7030e1e14b7b632acac55c40e9d2e082c621261bb56"
checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f"
dependencies = [
"bytes",
"futures-channel",
@ -1587,9 +1588,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.2.177"
version = "0.2.178"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091"
[[package]]
name = "libloading"
@ -1636,9 +1637,9 @@ dependencies = [
[[package]]
name = "log"
version = "0.4.28"
version = "0.4.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
[[package]]
name = "lru"
@ -2132,9 +2133,9 @@ dependencies = [
[[package]]
name = "prost"
version = "0.14.2"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "101fec8d036f8d9d4a1e8ebf90d566d1d798f3b1aa379d2576a54a0d9acea5bd"
checksum = "7231bd9b3d3d33c86b58adbac74b5ec0ad9f496b19d22801d773636feaa95f3d"
dependencies = [
"bytes",
"prost-derive",
@ -2142,9 +2143,9 @@ dependencies = [
[[package]]
name = "prost-derive"
version = "0.14.2"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2d93e596a829ebe00afa41c3a056e6308d6b8a4c7d869edf184e2c91b1ba564"
checksum = "9120690fafc389a67ba3803df527d0ec9cbbc9cc45e4cc20b332996dfb672425"
dependencies = [
"anyhow",
"itertools 0.14.0",
@ -2155,9 +2156,9 @@ dependencies = [
[[package]]
name = "prost-types"
version = "0.14.2"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5d7b7346e150de32340ae3390b8b3ffa37ad93ec31fb5dad86afe817619e4e7"
checksum = "b9b4db3d6da204ed77bb26ba83b6122a73aeb2e87e25fbf7ad2e84c4ccbf8f72"
dependencies = [
"prost",
]
@ -2555,6 +2556,15 @@ version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
[[package]]
name = "rustc_version"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
dependencies = [
"semver",
]
[[package]]
name = "rustix"
version = "1.1.2"
@ -2668,6 +2678,12 @@ dependencies = [
"zeroize",
]
[[package]]
name = "semver"
version = "1.0.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
[[package]]
name = "serde"
version = "1.0.228"
@ -3441,14 +3457,14 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "uuid"
version = "1.18.1"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2"
checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a"
dependencies = [
"getrandom 0.3.4",
"js-sys",
"md-5",
"serde",
"serde_core",
"wasm-bindgen",
]

View File

@ -43,7 +43,7 @@ futures = { version = "0.3", default-features = false, features = ["executor"] }
rayon = "1.11"
crossbeam = "0.8"
uuid = { version = "1.18", features = ["serde", "v3", "v4"] }
uuid = { version = "1.19", features = ["serde", "v3", "v4"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

View File

@ -1,9 +1,9 @@
use async_trait::async_trait;
use pumpkin_data::Block;
use pumpkin_data::tag::{RegistryKey, get_tag_ids};
use pumpkin_protocol::java::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders};
use pumpkin_protocol::java::client::play::{ArgumentType, SuggestionProviders};
use pumpkin_util::text::TextComponent;
use crate::command::args::ConsumeResult;
use crate::{command::dispatcher::CommandError, server::Server};
use super::{
@ -26,25 +26,18 @@ impl GetClientSideArgParser for BlockArgumentConsumer {
}
}
#[async_trait]
impl ArgumentConsumer for BlockArgumentConsumer {
async fn consume<'a>(
fn consume<'a>(
&'a self,
_sender: &CommandSender,
_sender: &'a CommandSender,
_server: &'a Server,
args: &mut RawArgs<'a>,
) -> Option<Arg<'a>> {
let s = args.pop()?;
Some(Arg::Block(s))
) -> ConsumeResult<'a> {
let block = args.pop();
match block {
Some(s) => Box::pin(async move { Some(Arg::Block(s)) }),
None => Box::pin(async move { None }),
}
async fn suggest<'a>(
&'a self,
_sender: &CommandSender,
_server: &'a Server,
_input: &'a str,
) -> Result<Option<Vec<CommandSuggestion>>, CommandError> {
Ok(None)
}
}
@ -101,25 +94,18 @@ impl GetClientSideArgParser for BlockPredicateArgumentConsumer {
}
}
#[async_trait]
impl ArgumentConsumer for BlockPredicateArgumentConsumer {
async fn consume<'a>(
fn consume<'a>(
&'a self,
_sender: &CommandSender,
_sender: &'a CommandSender,
_server: &'a Server,
args: &mut RawArgs<'a>,
) -> Option<Arg<'a>> {
let s = args.pop()?;
Some(Arg::BlockPredicate(s))
) -> ConsumeResult<'a> {
let block = args.pop();
match block {
Some(s) => Box::pin(async move { Some(Arg::BlockPredicate(s)) }),
None => Box::pin(async move { None }),
}
async fn suggest<'a>(
&'a self,
_sender: &CommandSender,
_server: &'a Server,
_input: &'a str,
) -> Result<Option<Vec<CommandSuggestion>>, CommandError> {
Ok(None)
}
}

View File

@ -1,10 +1,9 @@
use crate::command::CommandSender;
use crate::command::args::{Arg, ArgumentConsumer, FindArg, GetClientSideArgParser};
use crate::command::args::{Arg, ArgumentConsumer, ConsumeResult, FindArg, GetClientSideArgParser};
use crate::command::dispatcher::CommandError;
use crate::command::tree::RawArgs;
use crate::server::Server;
use async_trait::async_trait;
use pumpkin_protocol::java::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders};
use pumpkin_protocol::java::client::play::{ArgumentType, SuggestionProviders};
pub struct BoolArgConsumer;
@ -18,30 +17,25 @@ impl GetClientSideArgParser for BoolArgConsumer {
}
}
#[async_trait]
impl ArgumentConsumer for BoolArgConsumer {
async fn consume<'a>(
fn consume<'a, 'b>(
&'a self,
_sender: &CommandSender,
_sender: &'a CommandSender,
_server: &'a Server,
args: &mut RawArgs<'a>,
) -> Option<Arg<'a>> {
let s = args.pop()?;
args: &'b mut RawArgs<'a>,
) -> ConsumeResult<'a> {
let s_opt: Option<&'a str> = args.pop();
match s {
let result: Option<Arg<'a>> = s_opt.map_or_else(
|| None,
|s| match s {
"false" => Some(Arg::Bool(false)),
"true" => Some(Arg::Bool(true)),
_ => None,
}
}
},
);
async fn suggest<'a>(
&'a self,
_sender: &CommandSender,
_server: &'a Server,
_input: &'a str,
) -> Result<Option<Vec<CommandSuggestion>>, CommandError> {
Ok(None)
Box::pin(async move { result })
}
}

View File

@ -1,12 +1,12 @@
use crate::command::CommandSender;
use crate::command::args::{
Arg, ArgumentConsumer, DefaultNameArgConsumer, FindArg, GetClientSideArgParser,
Arg, ArgumentConsumer, ConsumeResult, DefaultNameArgConsumer, FindArg, GetClientSideArgParser,
SuggestResult,
};
use crate::command::dispatcher::CommandError;
use crate::command::tree::RawArgs;
use crate::server::Server;
use crate::world::bossbar::BossbarColor;
use async_trait::async_trait;
use pumpkin_protocol::java::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders};
pub struct BossbarColorArgumentConsumer;
@ -22,16 +22,18 @@ impl GetClientSideArgParser for BossbarColorArgumentConsumer {
}
}
#[async_trait]
impl ArgumentConsumer for BossbarColorArgumentConsumer {
async fn consume<'a>(
fn consume<'a, 'b>(
&'a self,
_sender: &CommandSender,
_sender: &'a CommandSender,
_server: &'a Server,
args: &mut RawArgs<'a>,
) -> Option<Arg<'a>> {
let s = args.pop()?;
args: &'b mut RawArgs<'a>,
) -> ConsumeResult<'a> {
let s_opt: Option<&'a str> = args.pop();
let result: Option<Arg<'a>> = s_opt.map_or_else(
|| None,
|s| {
let color = match s {
"blue" => Some(BossbarColor::Blue),
"green" => Some(BossbarColor::Green),
@ -44,20 +46,26 @@ impl ArgumentConsumer for BossbarColorArgumentConsumer {
};
color.map(Arg::BossbarColor)
},
);
Box::pin(async move { result })
}
async fn suggest<'a>(
fn suggest<'a>(
&'a self,
_sender: &CommandSender,
_server: &'a Server,
_input: &'a str,
) -> Result<Option<Vec<CommandSuggestion>>, CommandError> {
) -> SuggestResult<'a> {
Box::pin(async move {
let colors = ["blue", "green", "pink", "purple", "red", "white", "yellow"];
let suggestions: Vec<CommandSuggestion> = colors
.iter()
.map(|color| CommandSuggestion::new((*color).to_string(), None))
.collect();
Ok(Some(suggestions))
})
}
}

View File

@ -1,12 +1,12 @@
use crate::command::CommandSender;
use crate::command::args::{
Arg, ArgumentConsumer, DefaultNameArgConsumer, FindArg, GetClientSideArgParser,
Arg, ArgumentConsumer, ConsumeResult, DefaultNameArgConsumer, FindArg, GetClientSideArgParser,
SuggestResult,
};
use crate::command::dispatcher::CommandError;
use crate::command::tree::RawArgs;
use crate::server::Server;
use crate::world::bossbar::BossbarDivisions;
use async_trait::async_trait;
use pumpkin_protocol::java::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders};
pub struct BossbarStyleArgumentConsumer;
@ -22,16 +22,18 @@ impl GetClientSideArgParser for BossbarStyleArgumentConsumer {
}
}
#[async_trait]
impl ArgumentConsumer for BossbarStyleArgumentConsumer {
async fn consume<'a>(
fn consume<'a, 'b>(
&'a self,
_sender: &CommandSender,
_sender: &'a CommandSender,
_server: &'a Server,
args: &mut RawArgs<'a>,
) -> Option<Arg<'a>> {
let s = args.pop()?;
args: &'b mut RawArgs<'a>,
) -> ConsumeResult<'a> {
let s_opt: Option<&'a str> = args.pop();
let result: Option<Arg<'a>> = s_opt.map_or_else(
|| None,
|s| {
let style = match s {
"notched_10" => Some(BossbarDivisions::Notches10),
"notched_12" => Some(BossbarDivisions::Notches12),
@ -42,14 +44,19 @@ impl ArgumentConsumer for BossbarStyleArgumentConsumer {
};
style.map(Arg::BossbarStyle)
},
);
Box::pin(async move { result })
}
async fn suggest<'a>(
fn suggest<'a>(
&'a self,
_sender: &CommandSender,
_server: &'a Server,
_input: &'a str,
) -> Result<Option<Vec<CommandSuggestion>>, CommandError> {
) -> SuggestResult<'a> {
Box::pin(async move {
let styles = [
"notched_10",
"notched_12",
@ -62,6 +69,7 @@ impl ArgumentConsumer for BossbarStyleArgumentConsumer {
.map(|style| CommandSuggestion::new((*style).to_string(), None))
.collect();
Ok(Some(suggestions))
})
}
}

View File

@ -2,11 +2,11 @@ use core::f64;
use std::fmt::{Display, Formatter};
use std::str::FromStr;
use async_trait::async_trait;
use pumpkin_protocol::java::client::play::{ArgumentType, CommandSuggestion};
use pumpkin_protocol::java::client::play::ArgumentType;
use pumpkin_util::text::TextComponent;
use crate::command::CommandSender;
use crate::command::args::ConsumeResult;
use crate::command::dispatcher::CommandError;
use crate::command::tree::RawArgs;
use crate::server::Server;
@ -21,47 +21,44 @@ pub struct BoundedNumArgumentConsumer<T: ToFromNumber> {
name: Option<&'static str>,
}
#[async_trait]
impl<T: ToFromNumber> ArgumentConsumer for BoundedNumArgumentConsumer<T>
where
Self: GetClientSideArgParser,
{
async fn consume<'a>(
fn consume<'a, 'b>(
&'a self,
_src: &CommandSender,
_sender: &'a CommandSender,
_server: &'a Server,
args: &mut RawArgs<'a>,
) -> Option<Arg<'a>> {
let x = args.pop()?.parse::<T>().ok()?;
args: &'b mut RawArgs<'a>,
) -> ConsumeResult<'a> {
// 1. Perform the synchronous mutable operation (pop) outside the Future.
let s_opt: Option<&'a str> = args.pop();
// 2. Process the entire argument and check bounds synchronously.
let result: Option<Arg<'a>> = s_opt
// Replace args.pop()?.parse::<T>().ok()?
.and_then(|s| s.parse::<T>().ok())
.map(|x| {
// Check Upper Bound (max_inclusive)
if let Some(max) = self.max_inclusive
&& x > max
{
return Some(Arg::Num(Err(NotInBounds::UpperBound(
x.to_number(),
max.to_number(),
))));
return Arg::Num(Err(NotInBounds::UpperBound(x.to_number(), max.to_number())));
}
// Check Lower Bound (min_inclusive)
if let Some(min) = self.min_inclusive
&& x < min
{
return Some(Arg::Num(Err(NotInBounds::LowerBound(
x.to_number(),
min.to_number(),
))));
return Arg::Num(Err(NotInBounds::LowerBound(x.to_number(), min.to_number())));
}
Some(Arg::Num(Ok(x.to_number())))
}
// Success case
Arg::Num(Ok(x.to_number()))
});
async fn suggest<'a>(
&'a self,
_sender: &CommandSender,
_server: &'a Server,
_input: &'a str,
) -> Result<Option<Vec<CommandSuggestion>>, CommandError> {
Ok(None)
// 3. Return a Future that immediately resolves to the calculated result.
Box::pin(async move { result })
}
}

View File

@ -1,4 +1,3 @@
use async_trait::async_trait;
use pumpkin_protocol::java::client::play::{
ArgumentType, CommandSuggestion, StringProtoArgBehavior, SuggestionProviders,
};
@ -6,7 +5,7 @@ use pumpkin_protocol::java::client::play::{
use crate::{
command::{
CommandSender,
args::SplitSingleWhitespaceIncludingEmptyParts,
args::{ConsumeResult, SplitSingleWhitespaceIncludingEmptyParts, SuggestResult},
dispatcher::CommandError,
tree::{CommandTree, RawArgs},
},
@ -27,28 +26,36 @@ impl GetClientSideArgParser for CommandTreeArgumentConsumer {
}
}
#[async_trait]
impl ArgumentConsumer for CommandTreeArgumentConsumer {
async fn consume<'a>(
fn consume<'a, 'b>(
&'a self,
_sender: &CommandSender,
_sender: &'a CommandSender,
server: &'a Server,
args: &mut RawArgs<'a>,
) -> Option<Arg<'a>> {
let s = args.pop()?;
args: &'b mut RawArgs<'a>,
) -> ConsumeResult<'a> {
let s_opt: Option<&'a str> = args.pop();
let Some(s) = s_opt else {
return Box::pin(async move { None });
};
Box::pin(async move {
let dispatcher = server.command_dispatcher.read().await;
dispatcher
.get_tree(s)
.map_or_else(|_| None, |tree| Some(Arg::CommandTree(tree.clone())))
.ok()
.map(|tree| Arg::CommandTree(tree.clone()))
})
}
async fn suggest<'a>(
fn suggest<'a>(
&'a self,
_sender: &CommandSender,
server: &'a Server,
input: &'a str,
) -> Result<Option<Vec<CommandSuggestion>>, CommandError> {
) -> SuggestResult<'a> {
Box::pin(async move {
let Some(input) = input.split_single_whitespace_including_empty_parts().last() else {
return Ok(None);
};
@ -61,6 +68,7 @@ impl ArgumentConsumer for CommandTreeArgumentConsumer {
.map(|suggestion| CommandSuggestion::new(suggestion.clone(), None))
.collect();
Ok(Some(suggestions))
})
}
}

View File

@ -1,11 +1,15 @@
use std::str::FromStr;
use async_trait::async_trait;
use pumpkin_protocol::java::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders};
use pumpkin_util::Difficulty;
use crate::{
command::{CommandSender, dispatcher::CommandError, tree::RawArgs},
command::{
CommandSender,
args::{ConsumeResult, SuggestResult},
dispatcher::CommandError,
tree::RawArgs,
},
server::Server,
};
@ -25,32 +29,35 @@ impl GetClientSideArgParser for DifficultyArgumentConsumer {
}
}
#[async_trait]
impl ArgumentConsumer for DifficultyArgumentConsumer {
async fn consume<'a>(
fn consume<'a>(
&'a self,
_sender: &CommandSender,
_server: &'a Server,
args: &mut RawArgs<'a>,
) -> Option<Arg<'a>> {
let s = args.pop()?;
) -> ConsumeResult<'a> {
let s_opt: Option<&'a str> = args.pop();
Difficulty::from_str(s)
.map_or_else(|_| None, |difficulty| Some(Arg::Difficulty(difficulty)))
let result: Option<Arg<'a>> =
s_opt.and_then(|s| Difficulty::from_str(s).map(Arg::Difficulty).ok());
Box::pin(async move { result })
}
async fn suggest<'a>(
fn suggest<'a>(
&'a self,
_sender: &CommandSender,
_server: &'a Server,
_input: &'a str,
) -> Result<Option<Vec<CommandSuggestion>>, CommandError> {
) -> SuggestResult<'a> {
Box::pin(async move {
let difficulties = ["easy", "normal", "hard", "peaceful"];
let suggestions: Vec<CommandSuggestion> = difficulties
.iter()
.map(|difficulty| CommandSuggestion::new((*difficulty).to_string(), None))
.collect();
Ok(Some(suggestions))
})
}
}

View File

@ -2,14 +2,14 @@ use std::str::FromStr;
use std::sync::Arc;
use crate::command::CommandSender;
use crate::command::args::ConsumeResult;
use crate::command::dispatcher::CommandError;
use crate::command::tree::RawArgs;
use crate::entity::EntityBase;
use crate::server::Server;
use async_trait::async_trait;
use pumpkin_data::entity::EntityType;
use pumpkin_nbt::compound::NbtCompound;
use pumpkin_protocol::java::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders};
use pumpkin_protocol::java::client::play::{ArgumentType, SuggestionProviders};
use pumpkin_util::GameMode;
use uuid::Uuid;
@ -250,35 +250,34 @@ impl GetClientSideArgParser for EntitiesArgumentConsumer {
}
}
#[async_trait]
impl ArgumentConsumer for EntitiesArgumentConsumer {
async fn consume<'a>(
fn consume<'a, 'b>(
&'a self,
src: &CommandSender,
sender: &'a CommandSender,
server: &'a Server,
args: &mut RawArgs<'a>,
) -> Option<Arg<'a>> {
let s = args.pop()?;
args: &'b mut RawArgs<'a>,
) -> ConsumeResult<'a> {
let s_opt: Option<&'a str> = args.pop();
let Some(s) = s_opt else {
return Box::pin(async move { None });
};
let entity_selector = match s.parse::<TargetSelector>() {
Ok(selector) => selector,
Err(e) => {
log::debug!("Failed to parse target selector '{s}': {e}");
return None;
return Box::pin(async move { None }); // Return a Future resolving to None
}
};
Box::pin(async move {
// todo: command context
let entities = server.select_entities(&entity_selector, Some(src)).await;
// This is the required asynchronous operation.
let entities = server.select_entities(&entity_selector, Some(sender)).await;
Some(Arg::Entities(entities))
}
async fn suggest<'a>(
&'a self,
_sender: &CommandSender,
_server: &'a Server,
_input: &'a str,
) -> Result<Option<Vec<CommandSuggestion>>, CommandError> {
Ok(None)
})
}
}

View File

@ -1,13 +1,13 @@
use std::sync::Arc;
use crate::command::CommandSender;
use crate::command::args::ConsumeResult;
use crate::command::args::entities::TargetSelector;
use crate::command::dispatcher::CommandError;
use crate::command::tree::RawArgs;
use crate::entity::EntityBase;
use crate::server::Server;
use async_trait::async_trait;
use pumpkin_protocol::java::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders};
use pumpkin_protocol::java::client::play::{ArgumentType, SuggestionProviders};
use super::super::args::ArgumentConsumer;
use super::{Arg, DefaultNameArgConsumer, FindArg, GetClientSideArgParser};
@ -32,41 +32,38 @@ impl GetClientSideArgParser for EntityArgumentConsumer {
}
}
#[async_trait]
impl ArgumentConsumer for EntityArgumentConsumer {
async fn consume<'a>(
fn consume<'a, 'b>(
&'a self,
src: &CommandSender,
sender: &'a CommandSender,
server: &'a Server,
args: &mut RawArgs<'a>,
) -> Option<Arg<'a>> {
let s = args.pop()?;
args: &'b mut RawArgs<'a>,
) -> ConsumeResult<'a> {
let s_opt: Option<&'a str> = args.pop();
let Some(s) = s_opt else {
return Box::pin(async move { None });
};
let entity_selector = match s.parse::<TargetSelector>() {
Ok(selector) => selector,
Err(e) => {
log::debug!("Failed to parse target selector '{s}': {e}");
return None;
return Box::pin(async move { None });
}
};
if entity_selector.get_limit() > 1 {
log::debug!("Target selector '{s}' has limit > 1, expected single entity");
return None;
return Box::pin(async move { None });
}
Box::pin(async move {
// todo: command context
let entities = server.select_entities(&entity_selector, Some(src)).await;
let entities = server.select_entities(&entity_selector, Some(sender)).await;
// Take first
entities.into_iter().next().map(Arg::Entity)
}
async fn suggest<'a>(
&'a self,
_sender: &CommandSender,
_server: &'a Server,
_input: &'a str,
) -> Result<Option<Vec<CommandSuggestion>>, CommandError> {
Ok(None)
})
}
}

View File

@ -1,11 +1,10 @@
use std::str::FromStr;
use async_trait::async_trait;
use pumpkin_protocol::java::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders};
use pumpkin_protocol::java::client::play::{ArgumentType, SuggestionProviders};
use pumpkin_util::GameMode;
use crate::{
command::{CommandSender, dispatcher::CommandError, tree::RawArgs},
command::{CommandSender, args::ConsumeResult, dispatcher::CommandError, tree::RawArgs},
server::Server,
};
@ -23,32 +22,26 @@ impl GetClientSideArgParser for GamemodeArgumentConsumer {
}
}
#[async_trait]
impl ArgumentConsumer for GamemodeArgumentConsumer {
async fn consume<'a>(
fn consume<'a, 'b>(
&'a self,
_sender: &CommandSender,
_sender: &'a CommandSender,
_server: &'a Server,
args: &mut RawArgs<'a>,
) -> Option<Arg<'a>> {
let s = args.pop()?;
args: &'b mut RawArgs<'a>,
) -> ConsumeResult<'a> {
let s_opt: Option<&'a str> = args.pop();
let result: Option<Arg<'a>> = s_opt.and_then(|s| {
if let Ok(id) = s.parse::<i8>()
&& let Ok(gamemode) = GameMode::try_from(id)
{
return Some(Arg::GameMode(gamemode));
}
GameMode::from_str(s).map_or_else(|_| None, |gamemode| Some(Arg::GameMode(gamemode)))
}
GameMode::from_str(s).map(Arg::GameMode).ok() // Convert Result to Option<T>
});
async fn suggest<'a>(
&'a self,
_sender: &CommandSender,
_server: &'a Server,
_input: &'a str,
) -> Result<Option<Vec<CommandSuggestion>>, CommandError> {
Ok(None)
Box::pin(async move { result })
}
}

View File

@ -1,9 +1,11 @@
use async_trait::async_trait;
use pumpkin_protocol::java::client::play::{
ArgumentType, CommandSuggestion, StringProtoArgBehavior, SuggestionProviders,
ArgumentType, StringProtoArgBehavior, SuggestionProviders,
};
use crate::{command::dispatcher::CommandError, server::Server};
use crate::{
command::{args::ConsumeResult, dispatcher::CommandError},
server::Server,
};
use super::{
super::{
@ -26,31 +28,26 @@ impl GetClientSideArgParser for MsgArgConsumer {
}
}
#[async_trait]
impl ArgumentConsumer for MsgArgConsumer {
async fn consume<'a>(
fn consume<'a>(
&'a self,
_sender: &CommandSender,
_sender: &'a CommandSender,
_server: &'a Server,
args: &mut RawArgs<'a>,
) -> Option<Arg<'a>> {
let mut msg = args.pop()?.to_string();
) -> ConsumeResult<'a> {
let first_word_opt = args.pop();
let mut msg = match first_word_opt {
Some(word) => word.to_string(),
None => return Box::pin(async move { None }),
};
while let Some(word) = args.pop() {
msg.push(' ');
msg.push_str(word);
}
Some(Arg::Msg(msg))
}
async fn suggest<'a>(
&'a self,
_sender: &CommandSender,
_server: &'a Server,
_input: &'a str,
) -> Result<Option<Vec<CommandSuggestion>>, CommandError> {
Ok(None)
Box::pin(async move { Some(Arg::Msg(msg)) })
}
}

View File

@ -1,6 +1,6 @@
use std::pin::Pin;
use std::{collections::HashMap, hash::Hash, sync::Arc};
use async_trait::async_trait;
use bounded_num::{NotInBounds, Number};
use pumpkin_data::Enchantment;
use pumpkin_data::damage::DamageType;
@ -51,24 +51,30 @@ pub mod textcomponent;
pub mod time;
/// see [`crate::commands::tree::builder::argument`]
#[async_trait]
pub trait ArgumentConsumer: Sync + GetClientSideArgParser {
async fn consume<'a>(
pub type ConsumeResult<'a> = Pin<Box<dyn Future<Output = Option<Arg<'a>>> + Send + 'a>>;
pub type SuggestResult<'a> =
Pin<Box<dyn Future<Output = Result<Option<Vec<CommandSuggestion>>, CommandError>> + Send + 'a>>;
pub trait ArgumentConsumer: Sync + Send + GetClientSideArgParser {
fn consume<'a>(
&'a self,
sender: &CommandSender,
sender: &'a CommandSender,
server: &'a Server,
args: &mut RawArgs<'a>,
) -> Option<Arg>;
) -> ConsumeResult<'a>;
/// Used for tab completion (but only if argument suggestion type is "`minecraft:ask_server`"!).
///
/// NOTE: This is called after this consumer's [`ArgumentConsumer::consume`] method returned None, so if args is used here, make sure [`ArgumentConsumer::consume`] never returns None after mutating args.
async fn suggest<'a>(
fn suggest<'a>(
&'a self,
sender: &CommandSender,
server: &'a Server,
input: &'a str,
) -> Result<Option<Vec<CommandSuggestion>>, CommandError>;
_sender: &CommandSender,
_server: &'a Server,
_input: &'a str,
) -> SuggestResult<'a> {
Box::pin(async move { Ok(None) })
}
}
pub trait GetClientSideArgParser {

View File

@ -1,9 +1,9 @@
use std::sync::Arc;
use async_trait::async_trait;
use pumpkin_protocol::java::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders};
use pumpkin_protocol::java::client::play::{ArgumentType, SuggestionProviders};
use crate::command::CommandSender;
use crate::command::args::ConsumeResult;
use crate::command::dispatcher::CommandError;
use crate::command::tree::RawArgs;
use crate::entity::player::Player;
@ -28,45 +28,49 @@ impl GetClientSideArgParser for PlayersArgumentConsumer {
}
}
#[async_trait]
impl ArgumentConsumer for PlayersArgumentConsumer {
async fn consume<'a>(
fn consume<'a, 'b>(
&'a self,
src: &CommandSender,
sender: &'a CommandSender,
server: &'a Server,
args: &mut RawArgs<'a>,
) -> Option<Arg<'a>> {
let s = args.pop()?;
args: &'b mut RawArgs<'a>,
) -> ConsumeResult<'a> {
let s_opt: Option<&'a str> = args.pop();
let players = match s {
"@s" => match src {
let Some(s) = s_opt else {
return Box::pin(async move { None });
};
let sync_result: Option<Vec<Arc<Player>>> = match s {
"@s" => match sender {
CommandSender::Player(p) => Some(vec![p.clone()]),
_ => None,
},
#[allow(clippy::match_same_arms)]
// todo: implement for non-players and remove this line
"@n" | "@p" => match src {
"@n" | "@p" => match sender {
CommandSender::Player(p) => Some(vec![p.clone()]),
// todo: implement for non-players: how should this behave when sender is console/rcon?
_ => None,
},
"@r" => {
(server.get_random_player().await).map_or_else(|| Some(vec![]), |p| Some(vec![p]))
_ => None,
};
if let Some(players) = sync_result {
return Box::pin(async move { Some(Arg::Players(players)) });
}
Box::pin(async move {
let players = match s {
"@r" => server
.get_random_player()
.await
.map_or_else(|| Some(vec![]), |p| Some(vec![p])),
"@a" | "@e" => Some(server.get_all_players().await),
name => server.get_player_by_name(name).await.map(|p| vec![p]),
};
players.map(Arg::Players)
}
async fn suggest<'a>(
&'a self,
_sender: &CommandSender,
_server: &'a Server,
_input: &'a str,
) -> Result<Option<Vec<CommandSuggestion>>, CommandError> {
Ok(None)
})
}
}

View File

@ -1,9 +1,9 @@
use async_trait::async_trait;
use pumpkin_protocol::java::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders};
use pumpkin_protocol::java::client::play::{ArgumentType, SuggestionProviders};
use pumpkin_util::math::vector2::Vector2;
use pumpkin_util::math::vector3::Vector3;
use crate::command::CommandSender;
use crate::command::args::ConsumeResult;
use crate::command::dispatcher::CommandError;
use crate::command::tree::RawArgs;
use crate::server::Server;
@ -27,28 +27,25 @@ impl GetClientSideArgParser for Position2DArgumentConsumer {
}
}
#[async_trait]
impl ArgumentConsumer for Position2DArgumentConsumer {
async fn consume<'a>(
fn consume<'a, 'b>(
&'a self,
src: &CommandSender,
sender: &'a CommandSender,
_server: &'a Server,
args: &mut RawArgs<'a>,
) -> Option<Arg<'a>> {
let pos = MaybeRelativePosition2D::try_new(args.pop()?, args.pop()?)?;
args: &'b mut RawArgs<'a>,
) -> ConsumeResult<'a> {
let x_str_opt = args.pop();
let z_str_opt = args.pop();
let vec2 = pos.try_to_absolute(src.position())?;
let (Some(x_str), Some(z_str)) = (x_str_opt, z_str_opt) else {
return Box::pin(async move { None });
};
Some(Arg::Pos2D(vec2))
}
let result: Option<Arg<'a>> = MaybeRelativePosition2D::try_new(x_str, z_str)
.and_then(|pos| pos.try_to_absolute(sender.position()))
.map(Arg::Pos2D);
async fn suggest<'a>(
&'a self,
_sender: &CommandSender,
_server: &'a Server,
_input: &'a str,
) -> Result<Option<Vec<CommandSuggestion>>, CommandError> {
Ok(None)
Box::pin(async move { result })
}
}

View File

@ -1,8 +1,8 @@
use async_trait::async_trait;
use pumpkin_protocol::java::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders};
use pumpkin_protocol::java::client::play::{ArgumentType, SuggestionProviders};
use pumpkin_util::math::vector3::Vector3;
use crate::command::CommandSender;
use crate::command::args::ConsumeResult;
use crate::command::dispatcher::CommandError;
use crate::command::tree::RawArgs;
use crate::server::Server;
@ -24,28 +24,26 @@ impl GetClientSideArgParser for Position3DArgumentConsumer {
}
}
#[async_trait]
impl ArgumentConsumer for Position3DArgumentConsumer {
async fn consume<'a>(
fn consume<'a, 'b>(
&'a self,
src: &CommandSender,
sender: &'a CommandSender,
_server: &'a Server,
args: &mut RawArgs<'a>,
) -> Option<Arg<'a>> {
let pos = MaybeRelativePosition3D::try_new(args.pop()?, args.pop()?, args.pop()?)?;
args: &'b mut RawArgs<'a>,
) -> ConsumeResult<'a> {
let x_str_opt = args.pop();
let y_str_opt = args.pop();
let z_str_opt = args.pop();
let vec3 = pos.try_to_absolute(src.position())?;
let (Some(x_str), Some(y_str), Some(z_str)) = (x_str_opt, y_str_opt, z_str_opt) else {
return Box::pin(async move { None });
};
Some(Arg::Pos3D(vec3))
}
let result: Option<Arg<'a>> = MaybeRelativePosition3D::try_new(x_str, y_str, z_str)
.and_then(|pos| pos.try_to_absolute(sender.position()))
.map(Arg::Pos3D);
async fn suggest<'a>(
&'a self,
_sender: &CommandSender,
_server: &'a Server,
_input: &'a str,
) -> Result<Option<Vec<CommandSuggestion>>, CommandError> {
Ok(None)
Box::pin(async move { result })
}
}

View File

@ -1,9 +1,9 @@
use async_trait::async_trait;
use pumpkin_protocol::java::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders};
use pumpkin_protocol::java::client::play::{ArgumentType, SuggestionProviders};
use pumpkin_util::math::position::BlockPos;
use pumpkin_util::math::vector3::Vector3;
use crate::command::CommandSender;
use crate::command::args::ConsumeResult;
use crate::command::dispatcher::CommandError;
use crate::command::tree::RawArgs;
use crate::server::Server;
@ -25,28 +25,26 @@ impl GetClientSideArgParser for BlockPosArgumentConsumer {
}
}
#[async_trait]
impl ArgumentConsumer for BlockPosArgumentConsumer {
async fn consume<'a>(
fn consume<'a, 'b>(
&'a self,
src: &CommandSender,
sender: &'a CommandSender,
_server: &'a Server,
args: &mut RawArgs<'a>,
) -> Option<Arg<'a>> {
let pos = MaybeRelativeBlockPos::try_new(args.pop()?, args.pop()?, args.pop()?)?;
args: &'b mut RawArgs<'a>,
) -> ConsumeResult<'a> {
let x_str_opt = args.pop();
let y_str_opt = args.pop();
let z_str_opt = args.pop();
let vec3 = pos.try_to_absolute(src.position())?;
let (Some(x_str), Some(y_str), Some(z_str)) = (x_str_opt, y_str_opt, z_str_opt) else {
return Box::pin(async move { None });
};
Some(Arg::BlockPos(vec3))
}
let result: Option<Arg<'a>> = MaybeRelativeBlockPos::try_new(x_str, y_str, z_str)
.and_then(|pos| pos.try_to_absolute(sender.position()))
.map(Arg::BlockPos);
async fn suggest<'a>(
&'a self,
_sender: &CommandSender,
_server: &'a Server,
_input: &'a str,
) -> Result<Option<Vec<CommandSuggestion>>, CommandError> {
Ok(None)
Box::pin(async move { result })
}
}

View File

@ -1,11 +1,10 @@
use async_trait::async_trait;
use pumpkin_data::damage::DamageType;
use pumpkin_protocol::java::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders};
use pumpkin_protocol::java::client::play::{ArgumentType, SuggestionProviders};
use crate::command::{
CommandSender,
args::{
Arg, ArgumentConsumer, ConsumedArgs, DefaultNameArgConsumer, FindArg,
Arg, ArgumentConsumer, ConsumeResult, ConsumedArgs, DefaultNameArgConsumer, FindArg,
GetClientSideArgParser,
},
dispatcher::CommandError,
@ -27,30 +26,24 @@ impl GetClientSideArgParser for DamageTypeArgumentConsumer {
}
}
#[async_trait]
impl ArgumentConsumer for DamageTypeArgumentConsumer {
async fn consume<'a>(
fn consume<'a, 'b>(
&'a self,
_sender: &CommandSender,
_sender: &'a CommandSender,
_server: &'a Server,
args: &mut RawArgs<'a>,
) -> Option<Arg<'a>> {
let name = args.pop()?;
args: &'b mut RawArgs<'a>,
) -> ConsumeResult<'a> {
let name_opt: Option<&'a str> = args.pop();
let result: Option<Arg<'a>> = name_opt.map_or_else(
|| None,
|name| {
let name = name.strip_prefix("minecraft:").unwrap_or(name);
DamageType::from_name(name).map(Arg::DamageType)
},
);
// Create a static damage type first
let damage_type = DamageType::from_name(name)?;
// Find matching static damage type from values array
Some(Arg::DamageType(damage_type))
}
async fn suggest<'a>(
&'a self,
_sender: &CommandSender,
_server: &'a Server,
_input: &'a str,
) -> Result<Option<Vec<CommandSuggestion>>, CommandError> {
Ok(None)
Box::pin(async move { result })
}
}

View File

@ -1,11 +1,11 @@
use async_trait::async_trait;
use pumpkin_data::effect::StatusEffect;
use pumpkin_protocol::java::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders};
use pumpkin_protocol::java::client::play::{ArgumentType, SuggestionProviders};
use crate::command::{
CommandSender,
args::{
Arg, ArgumentConsumer, ConsumedArgs, DefaultNameArgConsumer, FindArg,
Arg, ArgumentConsumer, ConsumeResult, ConsumedArgs, DefaultNameArgConsumer, FindArg,
GetClientSideArgParser,
},
dispatcher::CommandError,
@ -29,27 +29,22 @@ impl GetClientSideArgParser for EffectTypeArgumentConsumer {
#[async_trait]
impl ArgumentConsumer for EffectTypeArgumentConsumer {
async fn consume<'a>(
fn consume<'a, 'b>(
&'a self,
_sender: &CommandSender,
_sender: &'a CommandSender,
_server: &'a Server,
args: &mut RawArgs<'a>,
) -> Option<Arg<'a>> {
let name = args.pop()?;
args: &'b mut RawArgs<'a>,
) -> ConsumeResult<'a> {
let status_effect: Option<&'a str> = args.pop();
// Create a static damage type first
let damage_type = StatusEffect::from_name(name.strip_prefix("minecraft:").unwrap_or(name))?;
// Find matching static damage type from values array
Some(Arg::Effect(damage_type))
match status_effect {
Some(name) => Box::pin(async move {
let status_effect =
StatusEffect::from_name(name.strip_prefix("minecraft:").unwrap_or(name))?;
Some(Arg::Effect(status_effect))
}),
None => Box::pin(async move { None }),
}
async fn suggest<'a>(
&'a self,
_sender: &CommandSender,
_server: &'a Server,
_input: &'a str,
) -> Result<Option<Vec<CommandSuggestion>>, CommandError> {
Ok(None)
}
}

View File

@ -1,11 +1,11 @@
use async_trait::async_trait;
use pumpkin_data::Enchantment;
use pumpkin_protocol::java::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders};
use pumpkin_protocol::java::client::play::{ArgumentType, SuggestionProviders};
use crate::command::{
CommandSender,
args::{
Arg, ArgumentConsumer, ConsumedArgs, DefaultNameArgConsumer, FindArg,
Arg, ArgumentConsumer, ConsumeResult, ConsumedArgs, DefaultNameArgConsumer, FindArg,
GetClientSideArgParser,
},
dispatcher::CommandError,
@ -29,27 +29,19 @@ impl GetClientSideArgParser for EnchantmentArgumentConsumer {
#[async_trait]
impl ArgumentConsumer for EnchantmentArgumentConsumer {
async fn consume<'a>(
fn consume<'a, 'b>(
&'a self,
_sender: &CommandSender,
_sender: &'a CommandSender,
_server: &'a Server,
args: &mut RawArgs<'a>,
) -> Option<Arg<'a>> {
let name = args.pop()?;
args: &'b mut RawArgs<'a>,
) -> ConsumeResult<'a> {
let name_opt: Option<&'a str> = args.pop();
// Create a static damage type first
let enchantment = Enchantment::from_name(name)?;
// Find matching static damage type from values array
Some(Arg::Enchantment(enchantment))
}
async fn suggest<'a>(
&'a self,
_sender: &CommandSender,
_server: &'a Server,
_input: &'a str,
) -> Result<Option<Vec<CommandSuggestion>>, CommandError> {
Ok(None)
let result: Option<Arg<'a>> = name_opt.map_or_else(
|| None,
|name| Enchantment::from_name(name).map(Arg::Enchantment),
);
Box::pin(async move { result })
}
}

View File

@ -1,12 +1,12 @@
use async_trait::async_trait;
use pumpkin_data::item::Item;
use pumpkin_protocol::java::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders};
use pumpkin_protocol::java::client::play::{ArgumentType, SuggestionProviders};
use pumpkin_util::text::TextComponent;
use crate::command::{
CommandSender,
args::{
Arg, ArgumentConsumer, ConsumedArgs, DefaultNameArgConsumer, FindArg,
Arg, ArgumentConsumer, ConsumeResult, ConsumedArgs, DefaultNameArgConsumer, FindArg,
GetClientSideArgParser,
},
dispatcher::CommandError,
@ -28,23 +28,17 @@ impl GetClientSideArgParser for ItemArgumentConsumer {
#[async_trait]
impl ArgumentConsumer for ItemArgumentConsumer {
async fn consume<'a>(
fn consume<'a>(
&'a self,
_sender: &CommandSender,
_sender: &'a CommandSender,
_server: &'a Server,
args: &mut RawArgs<'a>,
) -> Option<Arg<'a>> {
// todo: get an actual item
Some(Arg::Item(args.pop()?))
) -> ConsumeResult<'a> {
let item = args.pop();
match item {
Some(s) => Box::pin(async move { Some(Arg::Item(s)) }),
None => Box::pin(async move { None }),
}
async fn suggest<'a>(
&'a self,
_sender: &CommandSender,
_server: &'a Server,
_input: &'a str,
) -> Result<Option<Vec<CommandSuggestion>>, CommandError> {
Ok(None)
}
}

View File

@ -1,11 +1,11 @@
use async_trait::async_trait;
use pumpkin_data::particle::Particle;
use pumpkin_protocol::java::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders};
use pumpkin_protocol::java::client::play::{ArgumentType, SuggestionProviders};
use crate::command::{
CommandSender,
args::{
Arg, ArgumentConsumer, ConsumedArgs, DefaultNameArgConsumer, FindArg,
Arg, ArgumentConsumer, ConsumeResult, ConsumedArgs, DefaultNameArgConsumer, FindArg,
GetClientSideArgParser,
},
dispatcher::CommandError,
@ -29,27 +29,23 @@ impl GetClientSideArgParser for ParticleArgumentConsumer {
#[async_trait]
impl ArgumentConsumer for ParticleArgumentConsumer {
async fn consume<'a>(
fn consume<'a, 'b>(
&'a self,
_sender: &CommandSender,
_sender: &'a CommandSender,
_server: &'a Server,
args: &mut RawArgs<'a>,
) -> Option<Arg<'a>> {
let name = args.pop()?;
args: &'b mut RawArgs<'a>,
) -> ConsumeResult<'a> {
let name_opt: Option<&'a str> = args.pop();
// Create a static damage type first
let particle = Particle::from_name(name.strip_prefix("minecraft:").unwrap_or(name))?;
// Find matching static damage type from values array
Some(Arg::Particle(particle))
}
let result: Option<Arg<'a>> = name_opt.map_or_else(
|| None,
|name| {
Particle::from_name(name.strip_prefix("minecraft:").unwrap_or(name))
.map(Arg::Particle)
},
);
async fn suggest<'a>(
&'a self,
_sender: &CommandSender,
_server: &'a Server,
_input: &'a str,
) -> Result<Option<Vec<CommandSuggestion>>, CommandError> {
Ok(None)
Box::pin(async move { result })
}
}

View File

@ -1,12 +1,11 @@
use crate::command::CommandSender;
use crate::command::args::{
Arg, ArgumentConsumer, DefaultNameArgConsumer, FindArg, GetClientSideArgParser,
Arg, ArgumentConsumer, ConsumeResult, DefaultNameArgConsumer, FindArg, GetClientSideArgParser,
};
use crate::command::dispatcher::CommandError;
use crate::command::tree::RawArgs;
use crate::server::Server;
use async_trait::async_trait;
use pumpkin_protocol::java::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders};
use pumpkin_protocol::java::client::play::{ArgumentType, SuggestionProviders};
pub struct ResourceLocationArgumentConsumer {
autocomplete: bool,
@ -22,39 +21,43 @@ impl GetClientSideArgParser for ResourceLocationArgumentConsumer {
}
}
#[async_trait]
impl ArgumentConsumer for ResourceLocationArgumentConsumer {
async fn consume<'a>(
fn consume<'a, 'b>(
&'a self,
_sender: &CommandSender,
_sender: &'a CommandSender,
_server: &'a Server,
args: &mut RawArgs<'a>,
) -> Option<Arg<'a>> {
Some(Arg::ResourceLocation(args.pop()?))
}
async fn suggest<'a>(
&'a self,
_sender: &CommandSender,
_server: &'a Server,
_input: &'a str,
) -> Result<Option<Vec<CommandSuggestion>>, CommandError> {
args: &'b mut RawArgs<'a>,
) -> ConsumeResult<'a> {
if !self.autocomplete {
return Ok(None);
return Box::pin(async move { None });
}
// TODO
let s_opt: Option<&'a str> = args.pop();
// let suggestions = server
// .bossbars
// .lock()
// .await
// .custom_bossbars
// .keys()
// .map(|suggestion| CommandSuggestion::new(suggestion, None))
// .collect();
Ok(None)
Box::pin(async move { s_opt.map(Arg::ResourceLocation) })
}
// async fn suggest<'a>(
// &'a self,
// _sender: &CommandSender,
// _server: &'a Server,
// _input: &'a str,
// ) -> Result<Option<Vec<CommandSuggestion>>, CommandError> {
// if !self.autocomplete {
// return Ok(None);
// }
// // TODO
// // let suggestions = server
// // .bossbars
// // .lock()
// // .await
// // .custom_bossbars
// // .keys()
// // .map(|suggestion| CommandSuggestion::new(suggestion, None))
// // .collect();
// Ok(None)
// }
}
impl DefaultNameArgConsumer for ResourceLocationArgumentConsumer {

View File

@ -1,7 +1,7 @@
use async_trait::async_trait;
use pumpkin_protocol::java::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders};
use pumpkin_protocol::java::client::play::{ArgumentType, SuggestionProviders};
use crate::command::CommandSender;
use crate::command::args::ConsumeResult;
use crate::command::dispatcher::CommandError;
use crate::command::tree::RawArgs;
use crate::server::Server;
@ -22,20 +22,22 @@ impl GetClientSideArgParser for RotationArgumentConsumer {
}
}
#[async_trait]
impl ArgumentConsumer for RotationArgumentConsumer {
async fn consume<'a>(
fn consume<'a, 'b>(
&'a self,
_src: &CommandSender,
_sender: &'a CommandSender,
_server: &'a Server,
args: &mut RawArgs<'a>,
) -> Option<Arg<'a>> {
let yaw = args.pop()?;
let pitch = args.pop()?;
args: &'b mut RawArgs<'a>,
) -> ConsumeResult<'a> {
let yaw_str_opt = args.pop();
let pitch_str_opt = args.pop();
let mut yaw = yaw.parse::<f32>().ok()?;
let mut pitch = pitch.parse::<f32>().ok()?;
let (Some(yaw_str), Some(pitch_str)) = (yaw_str_opt, pitch_str_opt) else {
return Box::pin(async move { None });
};
let result: Option<Arg<'a>> = yaw_str.parse::<f32>().ok().and_then(|mut yaw| {
pitch_str.parse::<f32>().ok().map(|mut pitch| {
yaw %= 360.0;
if yaw >= 180.0 {
yaw -= 360.0;
@ -45,16 +47,11 @@ impl ArgumentConsumer for RotationArgumentConsumer {
pitch -= 360.0;
}
Some(Arg::Rotation(yaw, pitch))
}
Arg::Rotation(yaw, pitch)
})
});
async fn suggest<'a>(
&'a self,
_sender: &CommandSender,
_server: &'a Server,
_input: &'a str,
) -> Result<Option<Vec<CommandSuggestion>>, CommandError> {
Ok(None)
Box::pin(async move { result })
}
}

View File

@ -1,9 +1,11 @@
use async_trait::async_trait;
use pumpkin_protocol::java::client::play::{
ArgumentType, CommandSuggestion, StringProtoArgBehavior, SuggestionProviders,
ArgumentType, StringProtoArgBehavior, SuggestionProviders,
};
use crate::{command::dispatcher::CommandError, server::Server};
use crate::{
command::{args::ConsumeResult, dispatcher::CommandError},
server::Server,
};
use super::{
super::{
@ -27,24 +29,16 @@ impl GetClientSideArgParser for SimpleArgConsumer {
}
}
#[async_trait]
impl ArgumentConsumer for SimpleArgConsumer {
async fn consume<'a>(
fn consume<'a, 'b>(
&'a self,
_sender: &CommandSender,
_sender: &'a CommandSender,
_server: &'a Server,
args: &mut RawArgs<'a>,
) -> Option<Arg<'a>> {
Some(Arg::Simple(args.pop()?))
}
args: &'b mut RawArgs<'a>,
) -> ConsumeResult<'a> {
let s_opt: Option<&'a str> = args.pop();
async fn suggest<'a>(
&'a self,
_sender: &CommandSender,
_server: &'a Server,
_input: &'a str,
) -> Result<Option<Vec<CommandSuggestion>>, CommandError> {
Ok(None)
Box::pin(async move { s_opt.map(Arg::Simple) })
}
}

View File

@ -1,9 +1,11 @@
use async_trait::async_trait;
use pumpkin_data::sound::Sound;
use pumpkin_protocol::java::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders};
use pumpkin_protocol::java::client::play::{ArgumentType, SuggestionProviders};
use pumpkin_util::text::TextComponent;
use crate::{command::dispatcher::CommandError, server::Server};
use crate::{
command::{args::ConsumeResult, dispatcher::CommandError},
server::Server,
};
use super::{
super::{
@ -25,25 +27,16 @@ impl GetClientSideArgParser for SoundArgumentConsumer {
}
}
#[async_trait]
impl ArgumentConsumer for SoundArgumentConsumer {
async fn consume<'a>(
fn consume<'a, 'b>(
&'a self,
_sender: &CommandSender,
_sender: &'a CommandSender,
_server: &'a Server,
args: &mut RawArgs<'a>,
) -> Option<Arg<'a>> {
let s = args.pop()?;
Some(Arg::Block(s))
}
args: &'b mut RawArgs<'a>,
) -> ConsumeResult<'a> {
let s_opt: Option<&'a str> = args.pop();
async fn suggest<'a>(
&'a self,
_sender: &CommandSender,
_server: &'a Server,
_input: &'a str,
) -> Result<Option<Vec<CommandSuggestion>>, CommandError> {
Ok(None)
Box::pin(async move { s_opt.map(Arg::Block) })
}
}

View File

@ -1,11 +1,11 @@
use crate::command::CommandSender;
use crate::command::args::{
Arg, ArgumentConsumer, DefaultNameArgConsumer, FindArg, GetClientSideArgParser,
Arg, ArgumentConsumer, ConsumeResult, DefaultNameArgConsumer, FindArg, GetClientSideArgParser,
SuggestResult,
};
use crate::command::dispatcher::CommandError;
use crate::command::tree::RawArgs;
use crate::server::Server;
use async_trait::async_trait;
use pumpkin_data::sound::SoundCategory;
use pumpkin_protocol::java::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders};
@ -24,42 +24,44 @@ impl GetClientSideArgParser for SoundCategoryArgumentConsumer {
}
}
#[async_trait]
impl ArgumentConsumer for SoundCategoryArgumentConsumer {
async fn consume<'a>(
fn consume<'a, 'b>(
&'a self,
_sender: &CommandSender,
_sender: &'a CommandSender,
_server: &'a Server,
args: &mut RawArgs<'a>,
) -> Option<Arg<'a>> {
let s = args.pop()?;
args: &'b mut RawArgs<'a>,
) -> ConsumeResult<'a> {
let s_opt: Option<&'a str> = args.pop();
// Convert string input to SoundCategory enum
// Uses lowercase to make the command case-insensitive
let result: Option<Arg<'a>> = s_opt.and_then(|s| {
let category = match s.to_lowercase().as_str() {
"master" => Some(SoundCategory::Master), // Default category, affects all sounds
"music" => Some(SoundCategory::Music), // Background music
"master" => Some(SoundCategory::Master),
"music" => Some(SoundCategory::Music),
// i don't use SoundCategory::from_name because its is record and not records :c
"record" => Some(SoundCategory::Records), // Music discs
"weather" => Some(SoundCategory::Weather), // Rain, thunder
"block" => Some(SoundCategory::Blocks), // Block sounds
"hostile" => Some(SoundCategory::Hostile), // Hostile mob sounds
"neutral" => Some(SoundCategory::Neutral), // Neutral mob sounds
"player" => Some(SoundCategory::Players), // Player sounds
"ambient" => Some(SoundCategory::Ambient), // Ambient environment
"voice" => Some(SoundCategory::Voice), // Voice/speech
"record" => Some(SoundCategory::Records),
"weather" => Some(SoundCategory::Weather),
"block" => Some(SoundCategory::Blocks),
"hostile" => Some(SoundCategory::Hostile),
"neutral" => Some(SoundCategory::Neutral),
"player" => Some(SoundCategory::Players),
"ambient" => Some(SoundCategory::Ambient),
"voice" => Some(SoundCategory::Voice),
_ => None,
};
category.map(Arg::SoundCategory) // Simplified by removing redundant closure
category.map(Arg::SoundCategory)
});
Box::pin(async move { result })
}
async fn suggest<'a>(
fn suggest<'a>(
&'a self,
_sender: &CommandSender,
_server: &'a Server,
_input: &'a str,
) -> Result<Option<Vec<CommandSuggestion>>, CommandError> {
) -> SuggestResult<'a> {
Box::pin(async move {
let categories = [
"master", "music", "record", "weather", "block", "hostile", "neutral", "player",
"ambient", "voice",
@ -69,6 +71,7 @@ impl ArgumentConsumer for SoundCategoryArgumentConsumer {
.map(|cat| CommandSuggestion::new((*cat).to_string(), None))
.collect();
Ok(Some(suggestions))
})
}
}

View File

@ -1,9 +1,12 @@
use async_trait::async_trait;
use pumpkin_data::entity::EntityType;
use pumpkin_protocol::java::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders};
use pumpkin_protocol::java::client::play::{ArgumentType, SuggestionProviders};
use pumpkin_util::text::TextComponent;
use crate::{command::dispatcher::CommandError, server::Server};
use crate::{
command::{args::ConsumeResult, dispatcher::CommandError},
server::Server,
};
use super::{
super::{
@ -27,23 +30,15 @@ impl GetClientSideArgParser for SummonableEntitiesArgumentConsumer {
#[async_trait]
impl ArgumentConsumer for SummonableEntitiesArgumentConsumer {
async fn consume<'a>(
fn consume<'a, 'b>(
&'a self,
_sender: &CommandSender,
_sender: &'a CommandSender,
_server: &'a Server,
args: &mut RawArgs<'a>,
) -> Option<Arg<'a>> {
let s = args.pop()?;
Some(Arg::Block(s))
}
args: &'b mut RawArgs<'a>,
) -> ConsumeResult<'a> {
let s_opt: Option<&'a str> = args.pop();
async fn suggest<'a>(
&'a self,
_sender: &CommandSender,
_server: &'a Server,
_input: &'a str,
) -> Result<Option<Vec<CommandSuggestion>>, CommandError> {
Ok(None)
Box::pin(async move { s_opt.map(Arg::Block) })
}
}

View File

@ -1,10 +1,9 @@
use crate::command::CommandSender;
use crate::command::args::{Arg, ArgumentConsumer, FindArg, GetClientSideArgParser};
use crate::command::args::{Arg, ArgumentConsumer, ConsumeResult, FindArg, GetClientSideArgParser};
use crate::command::dispatcher::CommandError;
use crate::command::tree::RawArgs;
use crate::server::Server;
use async_trait::async_trait;
use pumpkin_protocol::java::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders};
use pumpkin_protocol::java::client::play::{ArgumentType, SuggestionProviders};
use pumpkin_util::text::TextComponent;
pub struct TextComponentArgConsumer;
@ -19,36 +18,32 @@ impl GetClientSideArgParser for TextComponentArgConsumer {
}
}
#[async_trait]
impl ArgumentConsumer for TextComponentArgConsumer {
async fn consume<'a>(
fn consume<'a, 'b>(
&'a self,
_sender: &CommandSender,
_sender: &'a CommandSender,
_server: &'a Server,
args: &mut RawArgs<'a>,
) -> Option<Arg<'a>> {
let s = args.pop()?;
args: &'b mut RawArgs<'a>,
) -> ConsumeResult<'a> {
let s_opt: Option<&'a str> = args.pop();
let text_component = parse_text_component(s);
let Some(text_component) = text_component else {
if s.starts_with('"') && s.ends_with('"') {
let s = s.replace('"', "");
return Some(Arg::TextComponent(TextComponent::text(s)));
}
return None;
let Some(s) = s_opt else {
return Box::pin(async move { None });
};
Some(Arg::TextComponent(text_component))
}
let text_component_opt = parse_text_component(s);
async fn suggest<'a>(
&'a self,
_sender: &CommandSender,
_server: &'a Server,
_input: &'a str,
) -> Result<Option<Vec<CommandSuggestion>>, CommandError> {
Ok(None)
let final_arg: Option<Arg<'a>> = text_component_opt.map_or_else(
|| {
(s.starts_with('"') && s.ends_with('"')).then(|| {
let s_owned = s.replace('"', "");
Arg::TextComponent(TextComponent::text(s_owned))
})
},
|text_component| Some(Arg::TextComponent(text_component)),
);
Box::pin(async move { final_arg })
}
}

View File

@ -1,9 +1,11 @@
use async_trait::async_trait;
use pumpkin_protocol::java::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders};
use pumpkin_protocol::java::client::play::{ArgumentType, SuggestionProviders};
use crate::command::{
CommandSender,
args::{Arg, ArgumentConsumer, DefaultNameArgConsumer, FindArg, GetClientSideArgParser},
args::{
Arg, ArgumentConsumer, ConsumeResult, DefaultNameArgConsumer, FindArg,
GetClientSideArgParser,
},
dispatcher::CommandError,
tree::RawArgs,
};
@ -21,27 +23,26 @@ impl GetClientSideArgParser for TimeArgumentConsumer {
}
}
#[async_trait]
impl ArgumentConsumer for TimeArgumentConsumer {
async fn consume<'a>(
fn consume<'a, 'b>(
&'a self,
_sender: &CommandSender,
_sender: &'a CommandSender,
_server: &'a Server,
args: &mut RawArgs<'a>,
) -> Option<Arg<'a>> {
let s = args.pop()?;
args: &'b mut RawArgs<'a>,
) -> ConsumeResult<'a> {
let s_opt: Option<&'a str> = args.pop();
// Parse number and unit
let result: Option<Arg<'a>> = s_opt.and_then(|s| {
let (num_str, unit) = s
.find(|c: char| c.is_alphabetic())
.map_or((s, "t"), |pos| (&s[..pos], &s[pos..]));
let number = num_str.parse::<f32>().ok()?;
let number = num_str.parse::<f32>().ok()?; // Replaces .ok()?
if number < 0.0 {
return None;
}
// Convert to ticks based on unit
let ticks = match unit {
"d" => number * 24000.0,
"s" => number * 20.0,
@ -49,19 +50,12 @@ impl ArgumentConsumer for TimeArgumentConsumer {
_ => return None,
};
// Round to nearest integer
let ticks = ticks.round() as i32;
Some(Arg::Time(ticks))
}
});
async fn suggest<'a>(
&'a self,
_sender: &CommandSender,
_server: &'a Server,
_input: &'a str,
) -> Result<Option<Vec<CommandSuggestion>>, CommandError> {
Ok(None)
Box::pin(async move { result })
}
}

View File

@ -1,3 +1,4 @@
use crate::command::CommandResult;
use crate::entity::EntityBase;
use crate::{
command::{
@ -13,7 +14,6 @@ use crate::{
net::DisconnectReason,
};
use CommandError::InvalidConsumption;
use async_trait::async_trait;
use pumpkin_util::text::TextComponent;
const NAMES: [&str; 1] = ["ban"];
@ -24,33 +24,34 @@ const ARG_REASON: &str = "reason";
struct NoReasonExecutor;
#[async_trait]
impl CommandExecutor for NoReasonExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
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::Players(targets)) = args.get(&ARG_TARGET) else {
return Err(InvalidConsumption(Some(ARG_TARGET.into())));
};
ban_player(sender, &targets[0], None).await;
Ok(())
})
}
}
struct ReasonExecutor;
#[async_trait]
impl CommandExecutor for ReasonExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
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::Players(targets)) = args.get(&ARG_TARGET) else {
return Err(InvalidConsumption(Some(ARG_TARGET.into())));
};
@ -61,6 +62,7 @@ impl CommandExecutor for ReasonExecutor {
ban_player(sender, &targets[0], Some(reason.clone())).await;
Ok(())
})
}
}

View File

@ -2,7 +2,7 @@ use std::{net::IpAddr, str::FromStr};
use crate::{
command::{
CommandError, CommandExecutor, CommandSender,
CommandError, CommandExecutor, CommandResult, CommandSender,
args::{Arg, ConsumedArgs, message::MsgArgConsumer, simple::SimpleArgConsumer},
tree::{CommandTree, builder::argument},
},
@ -13,7 +13,6 @@ use crate::{
server::Server,
};
use CommandError::InvalidConsumption;
use async_trait::async_trait;
use pumpkin_util::text::TextComponent;
const NAMES: [&str; 1] = ["ban-ip"];
@ -37,33 +36,34 @@ async fn parse_ip(target: &str, server: &Server) -> Option<IpAddr> {
struct NoReasonExecutor;
#[async_trait]
impl CommandExecutor for NoReasonExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
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(target)) = args.get(&ARG_TARGET) else {
return Err(InvalidConsumption(Some(ARG_TARGET.into())));
};
ban_ip(sender, server, target, None).await;
Ok(())
})
}
}
struct ReasonExecutor;
#[async_trait]
impl CommandExecutor for ReasonExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
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(target)) = args.get(&ARG_TARGET) else {
return Err(InvalidConsumption(Some(ARG_TARGET.into())));
};
@ -74,6 +74,7 @@ impl CommandExecutor for ReasonExecutor {
ban_ip(sender, server, target, Some(reason.clone())).await;
Ok(())
})
}
}

View File

@ -1,14 +1,12 @@
use crate::{
command::{
CommandError, CommandExecutor, CommandSender,
CommandError, CommandExecutor, CommandResult, CommandSender,
args::{Arg, ConsumedArgs, simple::SimpleArgConsumer},
tree::CommandTree,
tree::builder::argument,
tree::{CommandTree, builder::argument},
},
data::{banned_ip_data::BANNED_IP_LIST, banned_player_data::BANNED_PLAYER_LIST},
};
use CommandError::InvalidConsumption;
use async_trait::async_trait;
use pumpkin_util::text::TextComponent;
const NAMES: [&str; 1] = ["banlist"];
@ -18,14 +16,14 @@ const ARG_LIST_TYPE: &str = "ips|players";
struct ListExecutor;
#[async_trait]
impl CommandExecutor for ListExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
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())));
};
@ -71,19 +69,20 @@ impl CommandExecutor for ListExecutor {
}
Ok(())
})
}
}
struct ListAllExecutor;
#[async_trait]
impl CommandExecutor for ListAllExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &crate::server::Server,
_args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
_server: &'a crate::server::Server,
_args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let mut entries = Vec::new();
for entry in &BANNED_PLAYER_LIST.read().await.banned_players {
entries.push((
@ -103,6 +102,7 @@ impl CommandExecutor for ListAllExecutor {
handle_banlist(entries, sender).await;
Ok(())
})
}
}

View File

@ -6,16 +6,13 @@ use crate::command::args::players::PlayersArgumentConsumer;
use crate::command::args::resource_location::ResourceLocationArgumentConsumer;
use crate::command::args::{ConsumedArgs, FindArg, FindArgDefaultName};
use crate::command::dispatcher::CommandError;
use crate::command::args::textcomponent::TextComponentArgConsumer;
use crate::command::tree::CommandTree;
use crate::command::tree::builder::{argument, argument_default_name, literal};
use crate::command::{CommandExecutor, CommandSender};
use crate::server::Server;
use crate::command::{CommandExecutor, CommandResult, CommandSender};
use crate::world::bossbar::Bossbar;
use crate::world::custom_bossbar::BossbarUpdateError;
use async_trait::async_trait;
use pumpkin_util::text::TextComponent;
use pumpkin_util::text::color::{Color, NamedColor};
use pumpkin_util::text::hover::HoverEvent;
@ -55,14 +52,14 @@ enum CommandValueSet {
struct AddExecuter;
#[async_trait]
impl CommandExecutor for AddExecuter {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
server: &'a crate::server::Server,
args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let mut namespace = non_autocomplete_consumer()
.find_arg_default_name(args)?
.to_string();
@ -99,19 +96,20 @@ impl CommandExecutor for AddExecuter {
.await;
Ok(())
})
}
}
struct GetExecuter(CommandValueGet);
#[async_trait]
impl CommandExecutor for GetExecuter {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
server: &'a crate::server::Server,
args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let namespace = autocomplete_consumer()
.find_arg_default_name(args)?
.to_string();
@ -131,7 +129,10 @@ impl CommandExecutor for GetExecuter {
.send_message(TextComponent::translate(
"commands.bossbar.get.max",
[
bossbar_prefix(bossbar.bossbar_data.title.clone(), namespace.clone()),
bossbar_prefix(
bossbar.bossbar_data.title.clone(),
namespace.clone(),
),
TextComponent::text(bossbar.max.to_string()),
],
))
@ -144,7 +145,10 @@ impl CommandExecutor for GetExecuter {
.send_message(TextComponent::translate(
"commands.bossbar.get.value",
[
bossbar_prefix(bossbar.bossbar_data.title.clone(), namespace.clone()),
bossbar_prefix(
bossbar.bossbar_data.title.clone(),
namespace.clone(),
),
TextComponent::text(bossbar.value.to_string()),
],
))
@ -171,19 +175,20 @@ impl CommandExecutor for GetExecuter {
}
Ok(())
})
}
}
struct ListExecuter;
#[async_trait]
impl CommandExecutor for ListExecuter {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &Server,
_args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
server: &'a crate::server::Server,
_args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let bossbars = server.bossbars.lock().await.get_all_bossbars();
let Some(bossbars) = bossbars else {
sender
@ -212,11 +217,12 @@ impl CommandExecutor for ListExecuter {
bossbar.namespace.clone(),
));
} else {
bossbars_text =
bossbars_text.add_child(TextComponent::text(", ").add_child(bossbar_prefix(
bossbars_text = bossbars_text.add_child(TextComponent::text(", ").add_child(
bossbar_prefix(
bossbar.bossbar_data.title.clone(),
bossbar.namespace.clone(),
)));
),
));
}
}
@ -230,19 +236,20 @@ impl CommandExecutor for ListExecuter {
))
.await;
Ok(())
})
}
}
struct RemoveExecuter;
#[async_trait]
impl CommandExecutor for RemoveExecuter {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
server: &'a crate::server::Server,
args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let namespace = autocomplete_consumer()
.find_arg_default_name(args)?
.to_string();
@ -281,20 +288,21 @@ impl CommandExecutor for RemoveExecuter {
}
Ok(())
})
}
}
struct SetExecuter(CommandValueSet);
#[async_trait]
impl CommandExecutor for SetExecuter {
#[expect(clippy::too_many_lines)]
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
server: &'a crate::server::Server,
args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let namespace = autocomplete_consumer().find_arg_default_name(args)?;
let Some(bossbar) = server.bossbars.lock().await.get_bossbar(namespace) else {
@ -572,6 +580,7 @@ impl CommandExecutor for SetExecuter {
Ok(())
}
}
})
}
}

View File

@ -1,6 +1,5 @@
use std::sync::Arc;
use async_trait::async_trait;
use pumpkin_util::text::TextComponent;
use pumpkin_util::text::color::NamedColor;
use pumpkin_world::item::ItemStack;
@ -9,7 +8,7 @@ use crate::command::args::players::PlayersArgumentConsumer;
use crate::command::args::{Arg, ConsumedArgs};
use crate::command::tree::CommandTree;
use crate::command::tree::builder::{argument, require};
use crate::command::{CommandError, CommandExecutor, CommandSender};
use crate::command::{CommandError, CommandExecutor, CommandResult, CommandSender};
use crate::entity::EntityBase;
use crate::entity::player::Player;
use CommandError::InvalidConsumption;
@ -71,14 +70,14 @@ async fn clear_command_text_output(item_count: u64, targets: &[Arc<Player>]) ->
struct Executor;
#[async_trait]
impl CommandExecutor for Executor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
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::Players(targets)) = args.get(&ARG_TARGET) else {
return Err(InvalidConsumption(Some(ARG_TARGET.into())));
};
@ -93,19 +92,20 @@ impl CommandExecutor for Executor {
sender.send_message(msg).await;
Ok(())
})
}
}
struct SelfExecutor;
#[async_trait]
impl CommandExecutor for SelfExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &crate::server::Server,
_args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
_server: &'a crate::server::Server,
_args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let target = sender.as_player().ok_or(CommandError::InvalidRequirement)?;
let item_count = clear_player(&target).await;
@ -116,12 +116,13 @@ impl CommandExecutor for SelfExecutor {
sender.send_message(msg).await;
Ok(())
})
}
}
#[allow(clippy::redundant_closure_for_method_calls)] // causes lifetime issues
// #[allow(clippy::redundant_closure_for_method_calls)] // causes lifetime issues
pub fn init_command_tree() -> CommandTree {
CommandTree::new(NAMES, DESCRIPTION)
.then(argument(ARG_TARGET, PlayersArgumentConsumer).execute(Executor))
.then(require(|sender| sender.is_player()).execute(SelfExecutor))
.then(require(super::super::CommandSender::is_player).execute(SelfExecutor))
}

View File

@ -1,4 +1,3 @@
use async_trait::async_trait;
use pumpkin_data::damage::DamageType;
use pumpkin_util::text::{
TextComponent,
@ -6,7 +5,7 @@ use pumpkin_util::text::{
};
use crate::command::{
CommandError, CommandExecutor, CommandSender,
CommandExecutor, CommandResult, CommandSender,
args::{
Arg, ConsumedArgs, FindArg, bounded_num::BoundedNumArgumentConsumer,
entity::EntityArgumentConsumer, position_3d::Position3DArgumentConsumer,
@ -59,17 +58,18 @@ async fn send_damage_result(
.await;
}
#[async_trait]
impl CommandExecutor for LocationExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
_server: &'a crate::server::Server,
args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let target = EntityArgumentConsumer::find_arg(args, ARG_TARGET)?;
let Ok(Ok(amount)) = BoundedNumArgumentConsumer::<f32>::find_arg(args, ARG_AMOUNT) else {
let Ok(Ok(amount)) = BoundedNumArgumentConsumer::<f32>::find_arg(args, ARG_AMOUNT)
else {
sender
.send_message(
TextComponent::text("Invalid damage amount")
@ -79,8 +79,8 @@ impl CommandExecutor for LocationExecutor {
return Ok(());
};
let damage_type = args
.get(ARG_DAMAGE_TYPE)
let damage_type =
args.get(ARG_DAMAGE_TYPE)
.map_or(DamageType::GENERIC, |arg| match arg {
Arg::DamageType(dt) => *dt,
_ => DamageType::GENERIC,
@ -102,20 +102,22 @@ impl CommandExecutor for LocationExecutor {
send_damage_result(sender, success, amount, target.get_display_name().await).await;
Ok(())
})
}
}
#[async_trait]
impl CommandExecutor for EntityExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
_server: &'a crate::server::Server,
args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let target = EntityArgumentConsumer::find_arg(args, ARG_TARGET)?;
let Ok(Ok(amount)) = BoundedNumArgumentConsumer::<f32>::find_arg(args, ARG_AMOUNT) else {
let Ok(Ok(amount)) = BoundedNumArgumentConsumer::<f32>::find_arg(args, ARG_AMOUNT)
else {
sender
.send_message(
TextComponent::text("Invalid damage amount")
@ -125,8 +127,8 @@ impl CommandExecutor for EntityExecutor {
return Ok(());
};
let damage_type = args
.get(ARG_DAMAGE_TYPE)
let damage_type =
args.get(ARG_DAMAGE_TYPE)
.map_or(DamageType::GENERIC, |arg| match arg {
Arg::DamageType(dt) => *dt,
_ => DamageType::GENERIC,
@ -153,6 +155,7 @@ impl CommandExecutor for EntityExecutor {
send_damage_result(sender, success, amount, target.get_display_name().await).await;
Ok(())
})
}
}

View File

@ -1,3 +1,4 @@
use crate::command::CommandResult;
use crate::command::args::entity::EntityArgumentConsumer;
use crate::command::tree::builder::literal;
use crate::command::{
@ -7,7 +8,6 @@ use crate::command::{
};
use crate::entity::NBTStorage;
use CommandError::InvalidConsumption;
use async_trait::async_trait;
use pumpkin_nbt::compound::NbtCompound;
use pumpkin_nbt::tag::NbtTag;
use pumpkin_util::text::TextComponent;
@ -20,14 +20,14 @@ const ARG_ENTITY: &str = "entity";
struct GetEntityDataExecutor;
#[async_trait]
impl CommandExecutor for GetEntityDataExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
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::Entity(entity)) = args.get(&ARG_ENTITY) else {
return Err(InvalidConsumption(Some(ARG_ENTITY.into())));
};
@ -37,6 +37,7 @@ impl CommandExecutor for GetEntityDataExecutor {
.send_message(display_data(data_storage, entity.get_display_name().await).await?)
.await;
Ok(())
})
}
}

View File

@ -1,11 +1,9 @@
use crate::command::CommandResult;
use crate::command::args::gamemode::GamemodeArgumentConsumer;
use crate::command::args::{Arg, GetCloned};
use crate::command::dispatcher::CommandError::InvalidConsumption;
use crate::command::tree::builder::argument;
use crate::command::{
CommandError, CommandExecutor, CommandSender, args::ConsumedArgs, tree::CommandTree,
};
use async_trait::async_trait;
use crate::command::{CommandExecutor, CommandSender, args::ConsumedArgs, tree::CommandTree};
use pumpkin_config::BASIC_CONFIG;
use pumpkin_util::GameMode;
use pumpkin_util::text::TextComponent;
@ -22,14 +20,14 @@ pub struct DefaultGamemode {
struct DefaultGamemodeExecutor;
#[async_trait]
impl CommandExecutor for DefaultGamemodeExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
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::GameMode(gamemode)) = args.get_cloned(&ARG_GAMEMODE) else {
return Err(InvalidConsumption(Some(ARG_GAMEMODE.into())));
};
@ -54,6 +52,7 @@ impl CommandExecutor for DefaultGamemodeExecutor {
server.defaultgamemode.lock().await.gamemode = gamemode;
Ok(())
})
}
}

View File

@ -1,3 +1,4 @@
use crate::command::CommandResult;
use crate::entity::EntityBase;
use crate::{
command::{
@ -9,7 +10,6 @@ use crate::{
data::{SaveJSONConfiguration, op_data::OPERATOR_CONFIG},
};
use CommandError::InvalidConsumption;
use async_trait::async_trait;
use pumpkin_util::text::TextComponent;
const NAMES: [&str; 1] = ["deop"];
@ -18,14 +18,14 @@ const ARG_TARGETS: &str = "targets";
struct Executor;
#[async_trait]
impl CommandExecutor for Executor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
server: &'a crate::server::Server,
args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let mut config = OPERATOR_CONFIG.write().await;
let Some(Arg::Players(targets)) = args.get(&ARG_TARGETS) else {
@ -56,6 +56,7 @@ impl CommandExecutor for Executor {
sender.send_message(msg).await;
}
Ok(())
})
}
}

View File

@ -1,11 +1,9 @@
use crate::command::CommandResult;
use crate::command::args::difficulty::DifficultyArgumentConsumer;
use crate::command::args::{Arg, GetCloned};
use crate::command::dispatcher::CommandError::InvalidConsumption;
use crate::command::tree::builder::argument;
use crate::command::{
CommandError, CommandExecutor, CommandSender, args::ConsumedArgs, tree::CommandTree,
};
use async_trait::async_trait;
use crate::command::{CommandExecutor, CommandSender, args::ConsumedArgs, tree::CommandTree};
use pumpkin_util::text::TextComponent;
@ -16,14 +14,14 @@ const DESCRIPTION: &str = "Change the difficulty of the world.";
pub const ARG_DIFFICULTY: &str = "difficulty";
struct DifficultyExecutor;
#[async_trait]
impl CommandExecutor for DifficultyExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
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::Difficulty(difficulty)) = args.get_cloned(&ARG_DIFFICULTY) else {
return Err(InvalidConsumption(Some(ARG_DIFFICULTY.into())));
};
@ -55,6 +53,7 @@ impl CommandExecutor for DifficultyExecutor {
.await;
Ok(())
})
}
}

View File

@ -4,14 +4,11 @@ use crate::command::args::bounded_num::BoundedNumArgumentConsumer;
use crate::command::args::players::PlayersArgumentConsumer;
use crate::command::args::resource::effect::EffectTypeArgumentConsumer;
use crate::command::args::{Arg, ConsumedArgs, FindArgDefaultName};
use crate::command::dispatcher::CommandError;
use crate::command::dispatcher::CommandError::InvalidConsumption;
use crate::command::tree::CommandTree;
use crate::command::tree::builder::{argument, literal};
use crate::command::{CommandExecutor, CommandSender};
use crate::command::{CommandExecutor, CommandResult, CommandSender};
use crate::entity::EntityBase;
use crate::server::Server;
use async_trait::async_trait;
use pumpkin_data::potion::Effect;
use pumpkin_util::text::color::{Color, NamedColor};
@ -41,14 +38,14 @@ enum Amplifier {
struct GiveExecutor(Time, Amplifier, bool);
#[async_trait]
impl CommandExecutor for GiveExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
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::Players(targets)) = args.get(ARG_TARGET) else {
return Err(InvalidConsumption(Some(ARG_TARGET.into())));
};
@ -146,19 +143,20 @@ impl CommandExecutor for GiveExecutor {
}
Ok(())
})
}
}
struct ClearExecutor(bool); //the param -> true = delete every effect, false = only one
#[async_trait]
impl CommandExecutor for ClearExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
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::Players(targets)) = args.get(ARG_TARGET) else {
return Err(InvalidConsumption(Some(ARG_TARGET.into())));
};
@ -219,7 +217,10 @@ impl CommandExecutor for ClearExecutor {
if targets.len() == 1 || !has_effect.contains(&true) {
sender
.send_message(
TextComponent::translate("commands.effect.clear.specific.failed", [])
TextComponent::translate(
"commands.effect.clear.specific.failed",
[],
)
.color(Color::Named(NamedColor::Red)),
)
.await;
@ -253,6 +254,7 @@ impl CommandExecutor for ClearExecutor {
}
Ok(())
})
}
}

View File

@ -1,4 +1,3 @@
use async_trait::async_trait;
use pumpkin_util::text::TextComponent;
use crate::command::args::bounded_num::{BoundedNumArgumentConsumer, NotInBounds};
@ -7,7 +6,7 @@ use crate::command::args::resource::enchantment::EnchantmentArgumentConsumer;
use crate::command::args::{ConsumedArgs, FindArgDefaultName};
use crate::command::tree::CommandTree;
use crate::command::tree::builder::argument_default_name;
use crate::command::{CommandError, CommandExecutor, CommandSender};
use crate::command::{CommandError, CommandExecutor, CommandResult, CommandSender};
use pumpkin_data::data_component_impl::EnchantmentsImpl;
const NAMES: [&str; 1] = ["enchant"];
@ -15,15 +14,15 @@ const DESCRIPTION: &str = "Adds an enchantment to a player's selected item, subj
struct Executor;
#[async_trait]
impl CommandExecutor for Executor {
#[allow(clippy::too_many_lines)]
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
_server: &'a crate::server::Server,
args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let targets = EntitiesArgumentConsumer.find_arg_default_name(args)?;
let enchantment = EnchantmentArgumentConsumer.find_arg_default_name(args)?;
let level = match enchantment_level_consumer().find_arg_default_name(args) {
@ -143,6 +142,7 @@ impl CommandExecutor for Executor {
sender.send_message(msg).await;
}
Ok(())
})
}
}

View File

@ -1,6 +1,5 @@
use std::sync::atomic::Ordering;
use async_trait::async_trait;
use pumpkin_util::math::experience;
use pumpkin_util::text::TextComponent;
use pumpkin_util::text::color::{Color, NamedColor};
@ -10,7 +9,7 @@ use crate::command::args::players::PlayersArgumentConsumer;
use crate::command::args::{ConsumedArgs, FindArg};
use crate::command::tree::CommandTree;
use crate::command::tree::builder::{argument, literal};
use crate::command::{CommandError, CommandExecutor, CommandSender};
use crate::command::{CommandExecutor, CommandResult, CommandSender};
use crate::entity::EntityBase;
use crate::entity::player::Player;
@ -196,14 +195,14 @@ impl Executor {
}
}
#[async_trait]
impl CommandExecutor for Executor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
_server: &'a crate::server::Server,
args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let targets = PlayersArgumentConsumer::find_arg(args, ARG_TARGETS)?;
match self.mode {
@ -266,6 +265,7 @@ impl CommandExecutor for Executor {
}
Ok(())
})
}
}

View File

@ -5,9 +5,8 @@ use crate::command::args::position_block::BlockPosArgumentConsumer;
use crate::command::args::{ConsumedArgs, FindArg};
use crate::command::tree::CommandTree;
use crate::command::tree::builder::{argument, literal};
use crate::command::{CommandError, CommandExecutor, CommandSender};
use crate::command::{CommandError, CommandExecutor, CommandResult, CommandSender};
use async_trait::async_trait;
use pumpkin_data::Block;
use pumpkin_util::math::position::BlockPos;
use pumpkin_util::math::vector3::Vector3;
@ -50,14 +49,14 @@ fn not_in_filter(filter: &BlockPredicate, old_block: &Block) -> bool {
}
#[expect(clippy::too_many_lines)]
#[async_trait]
impl CommandExecutor for Executor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
_server: &'a crate::server::Server,
args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let block = BlockArgumentConsumer::find_arg(args, ARG_BLOCK)?;
let block_state_id = block.default_state.id;
let from = BlockPosArgumentConsumer::find_arg(args, ARG_FROM)?;
@ -139,7 +138,10 @@ impl CommandExecutor for Executor {
let old_state = world.get_block_state(&block_position).await;
if old_state.is_air() {
if let Some(filter) = &option_filter
&& not_in_filter(filter, world.get_block(&block_position).await)
&& not_in_filter(
filter,
world.get_block(&block_position).await,
)
{
continue;
}
@ -183,7 +185,11 @@ impl CommandExecutor for Executor {
.await;
} else {
world
.set_block_state(&block_position, 0, BlockFlags::FORCE_STATE)
.set_block_state(
&block_position,
0,
BlockFlags::FORCE_STATE,
)
.await;
}
placed_blocks += 1;
@ -260,6 +266,7 @@ impl CommandExecutor for Executor {
.await;
Ok(())
})
}
}

View File

@ -1,5 +1,3 @@
use async_trait::async_trait;
use crate::command::args::GetCloned;
use crate::command::args::gamemode::GamemodeArgumentConsumer;
@ -9,13 +7,11 @@ use crate::command::args::players::PlayersArgumentConsumer;
use crate::command::CommandSender::Player;
use crate::command::args::{Arg, ConsumedArgs};
use crate::command::dispatcher::CommandError;
use crate::command::dispatcher::CommandError::{InvalidConsumption, InvalidRequirement};
use crate::command::tree::CommandTree;
use crate::command::tree::builder::{argument, require};
use crate::command::{CommandExecutor, CommandSender};
use crate::command::{CommandExecutor, CommandResult, CommandSender};
use crate::entity::EntityBase;
use crate::server::Server;
const NAMES: [&str; 1] = ["gamemode"];
@ -26,14 +22,14 @@ const ARG_TARGET: &str = "target";
struct TargetSelfExecutor;
#[async_trait]
impl CommandExecutor for TargetSelfExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
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::GameMode(gamemode)) = args.get_cloned(&ARG_GAMEMODE) else {
return Err(InvalidConsumption(Some(ARG_GAMEMODE.into())));
};
@ -54,19 +50,20 @@ impl CommandExecutor for TargetSelfExecutor {
} else {
Err(InvalidRequirement)
}
})
}
}
struct TargetPlayerExecutor;
#[async_trait]
impl CommandExecutor for TargetPlayerExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
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::GameMode(gamemode)) = args.get_cloned(&ARG_GAMEMODE) else {
return Err(InvalidConsumption(Some(ARG_GAMEMODE.into())));
};
@ -102,6 +99,7 @@ impl CommandExecutor for TargetPlayerExecutor {
}
Ok(())
})
}
}

View File

@ -1,4 +1,3 @@
use async_trait::async_trait;
use pumpkin_data::game_rules::{GameRule, GameRuleRegistry, GameRuleValue};
use crate::command::args::FindArg;
@ -8,11 +7,9 @@ use crate::command::args::bounded_num::BoundedNumArgumentConsumer;
use crate::TextComponent;
use crate::command::args::ConsumedArgs;
use crate::command::dispatcher::CommandError;
use crate::command::tree::CommandTree;
use crate::command::tree::builder::{argument, literal};
use crate::command::{CommandExecutor, CommandSender};
use crate::server::Server;
use crate::command::{CommandExecutor, CommandResult, CommandSender};
const NAMES: [&str; 1] = ["gamerule"];
@ -22,14 +19,14 @@ const ARG_NAME: &str = "value";
struct QueryExecutor(GameRule);
#[async_trait]
impl CommandExecutor for QueryExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &Server,
_args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
server: &'a crate::server::Server,
_args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let key = TextComponent::text(self.0.to_string());
let level_info = server.level_info.read().await;
let value = TextComponent::text(level_info.game_rules.get(&self.0).to_string());
@ -42,19 +39,20 @@ impl CommandExecutor for QueryExecutor {
))
.await;
Ok(())
})
}
}
struct SetExecutor(GameRule);
#[async_trait]
impl CommandExecutor for SetExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
server: &'a crate::server::Server,
args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let key = TextComponent::text(self.0.to_string());
let mut level_info = server.level_info.write().await;
let raw_value = level_info.game_rules.get_mut(&self.0);
@ -80,6 +78,7 @@ impl CommandExecutor for SetExecutor {
))
.await;
Ok(())
})
}
}

View File

@ -1,4 +1,3 @@
use async_trait::async_trait;
use pumpkin_data::data_component::DataComponent::MaxStackSize;
use pumpkin_data::data_component_impl::{MaxStackSizeImpl, get};
use pumpkin_util::text::TextComponent;
@ -12,7 +11,7 @@ use crate::command::args::resource::item::ItemArgumentConsumer;
use crate::command::args::{ConsumedArgs, FindArg, FindArgDefaultName};
use crate::command::tree::CommandTree;
use crate::command::tree::builder::{argument, argument_default_name};
use crate::command::{CommandError, CommandExecutor, CommandSender};
use crate::command::{CommandExecutor, CommandResult, CommandSender};
use crate::entity::EntityBase;
const NAMES: [&str; 1] = ["give"];
@ -30,14 +29,14 @@ fn item_count_consumer() -> BoundedNumArgumentConsumer<i32> {
struct Executor;
#[async_trait]
impl CommandExecutor for Executor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
_server: &'a crate::server::Server,
args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let targets = PlayersArgumentConsumer.find_arg_default_name(args)?;
let (item_name, item) = ItemArgumentConsumer::find_arg(args, ARG_ITEM)?;
@ -56,7 +55,9 @@ impl CommandExecutor for Executor {
};
sender
.send_message(TextComponent::text(err_msg).color(Color::Named(NamedColor::Red)))
.send_message(
TextComponent::text(err_msg).color(Color::Named(NamedColor::Red)),
)
.await;
return Ok(());
}
@ -117,6 +118,7 @@ impl CommandExecutor for Executor {
sender.send_message(msg).await;
Ok(())
})
}
}

View File

@ -1,4 +1,3 @@
use async_trait::async_trait;
use futures::StreamExt;
use pumpkin_util::text::TextComponent;
use pumpkin_util::text::click::ClickEvent;
@ -7,12 +6,10 @@ use pumpkin_util::text::color::{Color, NamedColor};
use crate::command::args::bounded_num::BoundedNumArgumentConsumer;
use crate::command::args::command::CommandTreeArgumentConsumer;
use crate::command::args::{Arg, ConsumedArgs, FindArgDefaultName};
use crate::command::dispatcher::CommandError;
use crate::command::dispatcher::CommandError::InvalidConsumption;
use crate::command::tree::builder::{argument, argument_default_name};
use crate::command::tree::{Command, CommandTree};
use crate::command::{CommandExecutor, CommandSender};
use crate::server::Server;
use crate::command::{CommandExecutor, CommandResult, CommandSender};
const NAMES: [&str; 3] = ["help", "h", "?"];
@ -28,14 +25,14 @@ fn page_number_consumer() -> BoundedNumArgumentConsumer<i32> {
struct Executor;
#[async_trait]
impl CommandExecutor for Executor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
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::CommandTree(tree)) = args.get(&ARG_COMMAND) else {
return Err(InvalidConsumption(Some(ARG_COMMAND.into())));
};
@ -83,33 +80,35 @@ impl CommandExecutor for Executor {
TextComponent::text("Usage: ")
.color_named(NamedColor::Aqua)
.add_child(
TextComponent::text(format!("{usage}\n")).color_named(NamedColor::White),
TextComponent::text(format!("{usage}\n"))
.color_named(NamedColor::White),
)
.click_event(ClickEvent::SuggestCommand {
command: format!("{tree}").into(),
}),
);
message =
message.add_child(TextComponent::text("-".repeat(52)).color_named(NamedColor::Yellow));
message = message
.add_child(TextComponent::text("-".repeat(52)).color_named(NamedColor::Yellow));
sender.send_message(message).await;
Ok(())
})
}
}
struct BaseHelpExecutor;
#[async_trait]
impl CommandExecutor for BaseHelpExecutor {
#[expect(clippy::too_many_lines)]
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
server: &'a crate::server::Server,
args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let page_number = match page_number_consumer().find_arg_default_name(args) {
Err(_) => 1,
Ok(Ok(number)) => number,
@ -201,7 +200,9 @@ impl CommandExecutor for BaseHelpExecutor {
TextComponent::text(tree.description.clone() + "\n")
.color_named(NamedColor::White),
)
.add_child(TextComponent::text(" Usage: ").color_named(NamedColor::Yellow))
.add_child(
TextComponent::text(" Usage: ").color_named(NamedColor::Yellow),
)
.add_child(
TextComponent::text(format!("{tree}")).color_named(NamedColor::White),
)
@ -222,13 +223,16 @@ impl CommandExecutor for BaseHelpExecutor {
.add_child(TextComponent::text(footer_text.clone()))
.add_child(arrow_right)
.add_child(
TextComponent::text(" ".to_owned() + &"-".repeat((52 - footer_text.len() - 3) / 2))
TextComponent::text(
" ".to_owned() + &"-".repeat((52 - footer_text.len() - 3) / 2),
)
.color_named(NamedColor::Yellow),
);
sender.send_message(message).await;
Ok(())
})
}
}

View File

@ -1,13 +1,12 @@
use async_trait::async_trait;
use pumpkin_util::text::TextComponent;
use pumpkin_util::text::color::NamedColor;
use crate::command::CommandError;
use crate::command::args::message::MsgArgConsumer;
use crate::command::args::players::PlayersArgumentConsumer;
use crate::command::args::{Arg, ConsumedArgs};
use crate::command::tree::CommandTree;
use crate::command::tree::builder::argument;
use crate::command::{CommandError, CommandResult};
use crate::command::{CommandExecutor, CommandSender};
use crate::entity::EntityBase;
use crate::net::DisconnectReason;
@ -22,14 +21,14 @@ const ARG_REASON: &str = "reason";
struct Executor;
#[async_trait]
impl CommandExecutor for Executor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
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::Players(targets)) = args.get(&ARG_TARGETS) else {
return Err(InvalidConsumption(Some(ARG_TARGETS.into())));
};
@ -47,6 +46,7 @@ impl CommandExecutor for Executor {
}
Ok(())
})
}
}

View File

@ -1,11 +1,10 @@
use async_trait::async_trait;
use pumpkin_util::text::TextComponent;
use crate::command::args::entities::EntitiesArgumentConsumer;
use crate::command::args::{Arg, ConsumedArgs};
use crate::command::tree::CommandTree;
use crate::command::tree::builder::{argument, require};
use crate::command::{CommandError, CommandExecutor, CommandSender};
use crate::command::{CommandError, CommandExecutor, CommandResult, CommandSender};
use crate::entity::EntityBase;
use CommandError::InvalidConsumption;
@ -16,14 +15,14 @@ const ARG_TARGET: &str = "target";
struct Executor;
#[async_trait]
impl CommandExecutor for Executor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
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::Entities(targets)) = args.get(&ARG_TARGET) else {
return Err(InvalidConsumption(Some(ARG_TARGET.into())));
};
@ -48,19 +47,20 @@ impl CommandExecutor for Executor {
sender.send_message(msg).await;
Ok(())
})
}
}
struct SelfExecutor;
#[async_trait]
impl CommandExecutor for SelfExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &crate::server::Server,
_args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
_server: &'a crate::server::Server,
_args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let target = sender.as_player().ok_or(CommandError::InvalidRequirement)?;
target.kill(target.clone()).await;
@ -72,6 +72,7 @@ impl CommandExecutor for SelfExecutor {
.await;
Ok(())
})
}
}

View File

@ -1,12 +1,11 @@
use std::sync::Arc;
use async_trait::async_trait;
use pumpkin_config::BASIC_CONFIG;
use pumpkin_util::text::TextComponent;
use crate::{
command::{
CommandError, CommandExecutor, CommandSender, args::ConsumedArgs, tree::CommandTree,
CommandExecutor, CommandResult, CommandSender, args::ConsumedArgs, tree::CommandTree,
},
entity::player::Player,
};
@ -17,14 +16,14 @@ const DESCRIPTION: &str = "Print the list of online players.";
struct Executor;
#[async_trait]
impl CommandExecutor for Executor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &crate::server::Server,
_args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
server: &'a crate::server::Server,
_args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let players: Vec<Arc<Player>> = server.get_all_players().await;
sender
@ -39,6 +38,7 @@ impl CommandExecutor for Executor {
.await;
Ok(())
})
}
}

View File

@ -1,12 +1,10 @@
use async_trait::async_trait;
use pumpkin_data::world::EMOTE_COMMAND;
use pumpkin_util::text::TextComponent;
use crate::command::{
CommandError, CommandExecutor, CommandSender,
CommandError, CommandExecutor, CommandResult, CommandSender,
args::{Arg, ConsumedArgs, message::MsgArgConsumer},
tree::CommandTree,
tree::builder::argument,
tree::{CommandTree, builder::argument},
};
use CommandError::InvalidConsumption;
@ -18,14 +16,14 @@ const ARG_MESSAGE: &str = "action";
struct Executor;
#[async_trait]
impl CommandExecutor for Executor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
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::Msg(msg)) = args.get(ARG_MESSAGE) else {
return Err(InvalidConsumption(Some(ARG_MESSAGE.into())));
};
@ -39,6 +37,7 @@ impl CommandExecutor for Executor {
)
.await;
Ok(())
})
}
}

View File

@ -1,15 +1,16 @@
use async_trait::async_trait;
use pumpkin_data::world::{MSG_COMMAND_INCOMING, MSG_COMMAND_OUTGOING};
use pumpkin_util::text::TextComponent;
use crate::command::{
CommandError, CommandExecutor, CommandSender,
CommandError, CommandExecutor, CommandResult, CommandSender,
args::{
Arg, ConsumedArgs, FindArgDefaultName, message::MsgArgConsumer,
players::PlayersArgumentConsumer,
},
tree::CommandTree,
tree::builder::{argument, argument_default_name},
tree::{
CommandTree,
builder::{argument, argument_default_name},
},
};
use crate::entity::EntityBase;
use CommandError::InvalidConsumption;
@ -22,14 +23,14 @@ const ARG_MESSAGE: &str = "message";
struct Executor;
#[async_trait]
impl CommandExecutor for Executor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
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::Msg(msg)) = args.get(ARG_MESSAGE) else {
return Err(InvalidConsumption(Some(ARG_MESSAGE.into())));
};
@ -58,6 +59,7 @@ impl CommandExecutor for Executor {
}
Ok(())
})
}
}

View File

@ -1,3 +1,4 @@
use crate::command::CommandResult;
use crate::entity::EntityBase;
use crate::{
command::{
@ -9,7 +10,6 @@ use crate::{
data::{SaveJSONConfiguration, op_data::OPERATOR_CONFIG},
};
use CommandError::InvalidConsumption;
use async_trait::async_trait;
use pumpkin_config::{BASIC_CONFIG, op::Op};
use pumpkin_util::text::TextComponent;
@ -19,14 +19,14 @@ const ARG_TARGETS: &str = "targets";
struct Executor;
#[async_trait]
impl CommandExecutor for Executor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
server: &'a crate::server::Server,
args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let mut config = OPERATOR_CONFIG.write().await;
let Some(Arg::Players(targets)) = args.get(&ARG_TARGETS) else {
@ -79,6 +79,7 @@ impl CommandExecutor for Executor {
}
Ok(())
})
}
}

View File

@ -1,14 +1,12 @@
use crate::{
command::{
CommandError, CommandExecutor, CommandSender,
CommandError, CommandExecutor, CommandResult, CommandSender,
args::{Arg, ConsumedArgs, simple::SimpleArgConsumer},
tree::CommandTree,
tree::builder::argument,
tree::{CommandTree, builder::argument},
},
data::{SaveJSONConfiguration, banned_player_data::BANNED_PLAYER_LIST},
};
use CommandError::InvalidConsumption;
use async_trait::async_trait;
use pumpkin_util::text::TextComponent;
const NAMES: [&str; 1] = ["pardon"];
@ -18,14 +16,14 @@ const ARG_TARGET: &str = "player";
struct Executor;
#[async_trait]
impl CommandExecutor for Executor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
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(target)) = args.get(&ARG_TARGET) else {
return Err(InvalidConsumption(Some(ARG_TARGET.into())));
};
@ -55,6 +53,7 @@ impl CommandExecutor for Executor {
))
.await;
Ok(())
})
}
}

View File

@ -2,15 +2,13 @@ use std::{net::IpAddr, str::FromStr};
use crate::{
command::{
CommandError, CommandExecutor, CommandSender,
CommandError, CommandExecutor, CommandResult, CommandSender,
args::{Arg, ConsumedArgs, simple::SimpleArgConsumer},
tree::CommandTree,
tree::builder::argument,
tree::{CommandTree, builder::argument},
},
data::{SaveJSONConfiguration, banned_ip_data::BANNED_IP_LIST},
};
use CommandError::InvalidConsumption;
use async_trait::async_trait;
use pumpkin_util::text::TextComponent;
const NAMES: [&str; 1] = ["pardon-ip"];
@ -20,14 +18,14 @@ const ARG_TARGET: &str = "ip";
struct Executor;
#[async_trait]
impl CommandExecutor for Executor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
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(target)) = args.get(&ARG_TARGET) else {
return Err(InvalidConsumption(Some(ARG_TARGET.into())));
};
@ -59,6 +57,7 @@ impl CommandExecutor for Executor {
))
.await;
Ok(())
})
}
}

View File

@ -1,8 +1,7 @@
use async_trait::async_trait;
use pumpkin_util::{math::vector3::Vector3, text::TextComponent};
use crate::command::{
CommandError, CommandExecutor, CommandSender,
CommandError, CommandExecutor, CommandResult, CommandSender,
args::{
ConsumedArgs, FindArg, bounded_num::BoundedNumArgumentConsumer,
position_3d::Position3DArgumentConsumer, resource::particle::ParticleArgumentConsumer,
@ -22,14 +21,14 @@ const ARG_COUNT: &str = "count";
struct Executor;
#[async_trait]
impl CommandExecutor for Executor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
server: &'a crate::server::Server,
args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let particle = ParticleArgumentConsumer::find_arg(args, ARG_NAME)?;
let pos = Position3DArgumentConsumer::find_arg(args, ARG_POS);
let delta = Position3DArgumentConsumer::find_arg(args, ARG_DELTA);
@ -79,6 +78,7 @@ impl CommandExecutor for Executor {
.await;
Ok(())
})
}
}

View File

@ -1,17 +1,15 @@
use async_trait::async_trait;
use pumpkin_data::sound::SoundCategory;
use pumpkin_util::text::TextComponent;
use rand::{Rng, rng};
use crate::command::{
CommandError, CommandExecutor, CommandSender,
CommandExecutor, CommandResult, CommandSender,
args::{
Arg, ConsumedArgs, FindArg, bounded_num::BoundedNumArgumentConsumer,
players::PlayersArgumentConsumer, position_3d::Position3DArgumentConsumer,
sound::SoundArgumentConsumer, sound_category::SoundCategoryArgumentConsumer,
},
tree::CommandTree,
tree::builder::argument,
tree::{CommandTree, builder::argument},
};
use crate::entity::EntityBase;
@ -60,14 +58,14 @@ fn min_volume_consumer() -> BoundedNumArgumentConsumer<f32> {
struct Executor;
#[async_trait]
impl CommandExecutor for Executor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
_server: &'a crate::server::Server,
args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
// Get required sound argument
let sound = SoundArgumentConsumer::find_arg(args, ARG_SOUND)?;
@ -80,7 +78,8 @@ impl CommandExecutor for Executor {
});
// Get target players, defaults to sender if not specified
let targets = if let Ok(players) = PlayersArgumentConsumer::find_arg(args, ARG_TARGETS) {
let targets = if let Ok(players) = PlayersArgumentConsumer::find_arg(args, ARG_TARGETS)
{
players
} else if let Some(player) = sender.as_player() {
&[player]
@ -104,7 +103,8 @@ impl CommandExecutor for Executor {
};
// Get optional minimum volume (currently unused in implementation)
let min_volume = match BoundedNumArgumentConsumer::<f32>::find_arg(args, ARG_MIN_VOLUME) {
let min_volume = match BoundedNumArgumentConsumer::<f32>::find_arg(args, ARG_MIN_VOLUME)
{
Ok(Ok(v)) => v,
_ => 0.0, // Default minimum volume
};
@ -163,6 +163,7 @@ impl CommandExecutor for Executor {
}
Ok(())
})
}
}

View File

@ -1,6 +1,5 @@
use std::path::Path;
use async_trait::async_trait;
use pumpkin_util::{
PermissionLvl,
text::{TextComponent, color::NamedColor, hover::HoverEvent},
@ -9,7 +8,7 @@ use pumpkin_util::{
use crate::{
PLUGIN_MANAGER,
command::{
CommandError, CommandExecutor, CommandSender,
CommandExecutor, CommandResult, CommandSender,
args::{Arg, ConsumedArgs, simple::SimpleArgConsumer},
tree::{
CommandTree,
@ -28,14 +27,14 @@ const PLUGIN_NAME: &str = "plugin_name";
struct ListExecutor;
#[async_trait]
impl CommandExecutor for ListExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &crate::server::Server,
_args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
_server: &'a crate::server::Server,
_args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let plugins = PLUGIN_MANAGER.active_plugins().await;
let message_text = if plugins.is_empty() {
@ -67,19 +66,20 @@ impl CommandExecutor for ListExecutor {
sender.send_message(message).await;
Ok(())
})
}
}
struct LoadExecutor;
#[async_trait]
impl CommandExecutor for LoadExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
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(plugin_name)) = args.get(PLUGIN_NAME) else {
return Err(InvalidConsumption(Some(PLUGIN_NAME.into())));
};
@ -100,7 +100,9 @@ impl CommandExecutor for LoadExecutor {
Ok(()) => {
sender
.send_message(
TextComponent::text(format!("Plugin {plugin_name} loaded successfully"))
TextComponent::text(format!(
"Plugin {plugin_name} loaded successfully"
))
.color_named(NamedColor::Green),
)
.await;
@ -108,7 +110,9 @@ impl CommandExecutor for LoadExecutor {
Err(e) => {
sender
.send_message(
TextComponent::text(format!("Failed to load plugin {plugin_name}: {e}"))
TextComponent::text(format!(
"Failed to load plugin {plugin_name}: {e}"
))
.color_named(NamedColor::Red),
)
.await;
@ -116,19 +120,20 @@ impl CommandExecutor for LoadExecutor {
}
Ok(())
})
}
}
struct UnloadExecutor;
#[async_trait]
impl CommandExecutor for UnloadExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
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(plugin_name)) = args.get(PLUGIN_NAME) else {
return Err(InvalidConsumption(Some(PLUGIN_NAME.into())));
};
@ -149,7 +154,9 @@ impl CommandExecutor for UnloadExecutor {
Ok(()) => {
sender
.send_message(
TextComponent::text(format!("Plugin {plugin_name} unloaded successfully",))
TextComponent::text(format!(
"Plugin {plugin_name} unloaded successfully",
))
.color_named(NamedColor::Green),
)
.await;
@ -157,7 +164,9 @@ impl CommandExecutor for UnloadExecutor {
Err(e) => {
sender
.send_message(
TextComponent::text(format!("Failed to unload plugin {plugin_name}: {e}"))
TextComponent::text(format!(
"Failed to unload plugin {plugin_name}: {e}"
))
.color_named(NamedColor::Red),
)
.await;
@ -165,6 +174,7 @@ impl CommandExecutor for UnloadExecutor {
}
Ok(())
})
}
}

View File

@ -1,10 +1,9 @@
use async_trait::async_trait;
use pumpkin_util::text::{TextComponent, color::NamedColor, hover::HoverEvent};
use crate::{
PLUGIN_MANAGER,
command::{
CommandError, CommandExecutor, CommandSender, args::ConsumedArgs, tree::CommandTree,
CommandExecutor, CommandResult, CommandSender, args::ConsumedArgs, tree::CommandTree,
},
};
@ -14,14 +13,14 @@ const DESCRIPTION: &str = "List all available plugins.";
struct Executor;
#[async_trait]
impl CommandExecutor for Executor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &crate::server::Server,
_args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
_server: &'a crate::server::Server,
_args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let plugins = PLUGIN_MANAGER.active_plugins().await;
let message_text = if plugins.is_empty() {
@ -52,6 +51,7 @@ impl CommandExecutor for Executor {
sender.send_message(message).await;
Ok(())
})
}
}

View File

@ -1,10 +1,11 @@
use async_trait::async_trait;
use pumpkin_util::text::TextComponent;
use pumpkin_util::text::color::NamedColor;
use crate::command::CommandResult;
use crate::command::args::ConsumedArgs;
use crate::command::tree::CommandTree;
use crate::command::{CommandError, CommandExecutor, CommandSender};
use crate::command::{CommandExecutor, CommandSender};
use crate::{HEAP_PROFILER, stop_server};
const NAMES: [&str; 1] = ["mem_profile"];
@ -13,27 +14,29 @@ const DESCRIPTION: &str = "Stop the server and dump a memory profile.";
struct Executor;
#[async_trait]
impl CommandExecutor for Executor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &crate::server::Server,
_args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
_server: &'a crate::server::Server,
_args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
sender
.send_message(
TextComponent::translate("commands.stop.stopping", []).color_named(NamedColor::Red),
TextComponent::translate("commands.stop.stopping", [])
.color_named(NamedColor::Red),
)
.await;
let mut profiler = HEAP_PROFILER.lock().await;
let p = profiler.take().unwrap();
// Do the actual profiling
drop(p);
stop_server();
Ok(())
})
}
}

View File

@ -1,4 +1,3 @@
use async_trait::async_trait;
use pumpkin_data::packet::CURRENT_MC_PROTOCOL;
use pumpkin_util::text::click::ClickEvent;
use pumpkin_util::text::hover::HoverEvent;
@ -7,9 +6,8 @@ use pumpkin_util::translation::get_translation_text;
use pumpkin_world::CURRENT_MC_VERSION;
use std::borrow::Cow;
use crate::command::{
CommandError, CommandExecutor, CommandSender, args::ConsumedArgs, tree::CommandTree,
};
use crate::command::CommandResult;
use crate::command::{CommandExecutor, CommandSender, args::ConsumedArgs, tree::CommandTree};
const NAMES: [&str; 2] = ["pumpkin", "version"];
@ -19,15 +17,15 @@ struct Executor;
const CARGO_PKG_VERSION: &str = env!("CARGO_PKG_VERSION");
#[async_trait]
#[allow(clippy::too_many_lines)]
impl CommandExecutor for Executor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &crate::server::Server,
_args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
_server: &'a crate::server::Server,
_args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let locale = sender.get_locale().await;
sender
.send_message(
@ -129,7 +127,12 @@ impl CommandExecutor for Executor {
// Added docs. and a space for spacing
.add_child(TextComponent::text(" "))
.add_child(
TextComponent::custom("pumpkin", "commands.pumpkin.website", locale, vec![])
TextComponent::custom(
"pumpkin",
"commands.pumpkin.website",
locale,
vec![],
)
.click_event(ClickEvent::OpenUrl {
url: Cow::from("https://pumpkinmc.org/"),
})
@ -146,6 +149,7 @@ impl CommandExecutor for Executor {
)
.await;
Ok(())
})
}
}

View File

@ -1,12 +1,10 @@
use async_trait::async_trait;
use pumpkin_data::world::SAY_COMMAND;
use pumpkin_util::text::TextComponent;
use crate::command::{
CommandError, CommandExecutor, CommandSender,
CommandError, CommandExecutor, CommandResult, CommandSender,
args::{Arg, ConsumedArgs, message::MsgArgConsumer},
tree::CommandTree,
tree::builder::argument,
tree::{CommandTree, builder::argument},
};
use CommandError::InvalidConsumption;
@ -18,14 +16,14 @@ const ARG_MESSAGE: &str = "message";
struct Executor;
#[async_trait]
impl CommandExecutor for Executor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
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::Msg(msg)) = args.get(ARG_MESSAGE) else {
return Err(InvalidConsumption(Some(ARG_MESSAGE.into())));
};
@ -39,6 +37,7 @@ impl CommandExecutor for Executor {
)
.await;
Ok(())
})
}
}

View File

@ -1,7 +1,7 @@
use crate::command::CommandResult;
use crate::command::{
CommandError, CommandExecutor, CommandSender, args::ConsumedArgs, tree::CommandTree,
};
use async_trait::async_trait;
use pumpkin_util::text::click::ClickEvent;
use pumpkin_util::text::hover::HoverEvent;
use pumpkin_util::text::{TextComponent, color::NamedColor};
@ -13,14 +13,14 @@ const DESCRIPTION: &str = "Displays the world seed.";
struct Executor;
#[async_trait]
impl CommandExecutor for Executor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &crate::server::Server,
_args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
server: &'a crate::server::Server,
_args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let seed = match sender {
CommandSender::Player(player) => player.living_entity.entity.world.level.seed.0,
// TODO: Maybe ask player for world, or get the current world
@ -50,6 +50,7 @@ impl CommandExecutor for Executor {
))
.await;
Ok(())
})
}
}

View File

@ -1,4 +1,3 @@
use async_trait::async_trait;
use pumpkin_util::text::TextComponent;
use pumpkin_world::world::BlockFlags;
@ -7,7 +6,7 @@ use crate::command::args::position_block::BlockPosArgumentConsumer;
use crate::command::args::{ConsumedArgs, FindArg};
use crate::command::tree::CommandTree;
use crate::command::tree::builder::{argument, literal};
use crate::command::{CommandError, CommandExecutor, CommandSender};
use crate::command::{CommandError, CommandExecutor, CommandResult, CommandSender};
const NAMES: [&str; 1] = ["setblock"];
@ -30,14 +29,14 @@ enum Mode {
struct Executor(Mode);
#[async_trait]
impl CommandExecutor for Executor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
server: &'a crate::server::Server,
args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let block = BlockArgumentConsumer::find_arg(args, ARG_BLOCK)?;
let block_state_id = block.default_state.id;
let pos = BlockPosArgumentConsumer::find_arg(args, ARG_BLOCK_POS)?;
@ -111,6 +110,7 @@ impl CommandExecutor for Executor {
.await;
Ok(())
})
}
}

View File

@ -1,3 +1,4 @@
use crate::command::CommandResult;
use crate::command::dispatcher::CommandError::InvalidConsumption;
use crate::command::{
CommandExecutor, CommandSender,
@ -9,7 +10,6 @@ use crate::command::{
tree::{CommandTree, builder::argument},
};
use crate::server::Server;
use async_trait::async_trait;
use pumpkin_registry::VanillaDimensionType;
use pumpkin_util::{math::position::BlockPos, text::TextComponent};
@ -23,14 +23,14 @@ const ARG_ANGLE: &str = "angle";
struct NoArgsWorldSpawnExecutor;
#[async_trait]
impl CommandExecutor for NoArgsWorldSpawnExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &crate::server::Server,
_args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
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(block_pos) = sender.position() else {
let level_info_guard = server.level_info.read().await;
sender
@ -49,37 +49,39 @@ impl CommandExecutor for NoArgsWorldSpawnExecutor {
};
setworldspawn(sender, server, block_pos.to_block_pos(), 0.0).await
})
}
}
struct DefaultWorldSpawnExecutor;
#[async_trait]
impl CommandExecutor for DefaultWorldSpawnExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
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::BlockPos(block_pos)) = args.get(ARG_BLOCK_POS) else {
return Err(InvalidConsumption(Some(ARG_BLOCK_POS.into())));
};
setworldspawn(sender, server, *block_pos, 0.0).await
})
}
}
struct AngleWorldSpawnExecutor;
#[async_trait]
impl CommandExecutor for AngleWorldSpawnExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
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::BlockPos(block_pos)) = args.get(ARG_BLOCK_POS) else {
return Err(InvalidConsumption(Some(ARG_BLOCK_POS.into())));
};
@ -89,6 +91,7 @@ impl CommandExecutor for AngleWorldSpawnExecutor {
};
setworldspawn(sender, server, *block_pos, *yaw).await
})
}
}

View File

@ -1,10 +1,9 @@
use async_trait::async_trait;
use pumpkin_util::text::TextComponent;
use pumpkin_util::text::color::NamedColor;
use crate::command::args::ConsumedArgs;
use crate::command::tree::CommandTree;
use crate::command::{CommandError, CommandExecutor, CommandSender};
use crate::command::{CommandExecutor, CommandResult, CommandSender};
use crate::stop_server;
const NAMES: [&str; 1] = ["stop"];
@ -13,21 +12,23 @@ const DESCRIPTION: &str = "Stop the server.";
struct Executor;
#[async_trait]
impl CommandExecutor for Executor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &crate::server::Server,
_args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
_server: &'a crate::server::Server,
_args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
sender
.send_message(
TextComponent::translate("commands.stop.stopping", []).color_named(NamedColor::Red),
TextComponent::translate("commands.stop.stopping", [])
.color_named(NamedColor::Red),
)
.await;
stop_server();
Ok(())
})
}
}

View File

@ -1,13 +1,11 @@
use crate::command::{
CommandExecutor, CommandSender,
CommandExecutor, CommandResult, CommandSender,
args::{
ConsumedArgs, FindArg, players::PlayersArgumentConsumer, sound::SoundArgumentConsumer,
sound_category::SoundCategoryArgumentConsumer,
},
dispatcher::CommandError,
tree::{CommandTree, builder::argument},
};
use async_trait::async_trait;
use pumpkin_util::resource_location::ResourceLocation;
use pumpkin_util::text::TextComponent;
@ -20,14 +18,14 @@ const ARG_SOUND: &str = "sound";
pub struct Executor;
#[async_trait]
impl CommandExecutor for Executor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
_server: &'a crate::server::Server,
args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let targets = PlayersArgumentConsumer::find_arg(args, ARG_TARGETS)?;
let category = SoundCategoryArgumentConsumer::find_arg(args, ARG_SOURCE);
@ -68,6 +66,7 @@ impl CommandExecutor for Executor {
sender.send_message(text).await;
Ok(())
})
}
}

View File

@ -1,10 +1,9 @@
use async_trait::async_trait;
use pumpkin_util::{math::vector3::Vector3, text::TextComponent};
use uuid::Uuid;
use crate::{
command::{
CommandError, CommandExecutor, CommandSender,
CommandError, CommandExecutor, CommandResult, CommandSender,
args::{
ConsumedArgs, FindArg, position_3d::Position3DArgumentConsumer,
summonable_entities::SummonableEntitiesArgumentConsumer,
@ -23,14 +22,14 @@ const ARG_POS: &str = "pos";
struct Executor;
#[async_trait]
impl CommandExecutor for Executor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
server: &'a crate::server::Server,
args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let entity = SummonableEntitiesArgumentConsumer::find_arg(args, ARG_ENTITY)?;
let pos = Position3DArgumentConsumer::find_arg(args, ARG_POS);
let (world, pos) = match sender {
@ -69,6 +68,7 @@ impl CommandExecutor for Executor {
.await;
Ok(())
})
}
}

View File

@ -1,8 +1,8 @@
use async_trait::async_trait;
use pumpkin_util::math::vector3::Vector3;
use pumpkin_util::text::TextComponent;
use crate::command::CommandError;
use crate::command::CommandResult;
use crate::command::args::ConsumedArgs;
use crate::command::args::FindArg;
use crate::command::args::entities::EntitiesArgumentConsumer;
@ -53,14 +53,14 @@ fn yaw_pitch_facing_position(
struct EntitiesToEntityExecutor;
#[async_trait]
impl CommandExecutor for EntitiesToEntityExecutor {
async fn execute<'a>(
&self,
_sender: &mut CommandSender,
_server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
_sender: &'a CommandSender,
_server: &'a crate::server::Server,
args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let targets = EntitiesArgumentConsumer::find_arg(args, ARG_TARGETS)?;
let destination = EntityArgumentConsumer::find_arg(args, ARG_DESTINATION)?;
@ -82,19 +82,20 @@ impl CommandExecutor for EntitiesToEntityExecutor {
}
Ok(())
})
}
}
struct EntitiesToPosFacingPosExecutor;
#[async_trait]
impl CommandExecutor for EntitiesToPosFacingPosExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
server: &'a crate::server::Server,
args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let targets = EntitiesArgumentConsumer::find_arg(args, ARG_TARGETS)?;
let pos = Position3DArgumentConsumer::find_arg(args, ARG_LOCATION)?;
@ -121,19 +122,20 @@ impl CommandExecutor for EntitiesToPosFacingPosExecutor {
}
Ok(())
})
}
}
struct EntitiesToPosFacingEntityExecutor;
#[async_trait]
impl CommandExecutor for EntitiesToPosFacingEntityExecutor {
async fn execute<'a>(
&self,
_sender: &mut CommandSender,
_server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
_sender: &'a CommandSender,
_server: &'a crate::server::Server,
args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let targets = EntitiesArgumentConsumer::find_arg(args, ARG_TARGETS)?;
let pos = Position3DArgumentConsumer::find_arg(args, ARG_LOCATION)?;
@ -143,7 +145,8 @@ impl CommandExecutor for EntitiesToPosFacingEntityExecutor {
)));
}
let facing_entity = EntityArgumentConsumer::find_arg(args, ARG_FACING_ENTITY)?;
let (yaw, pitch) = yaw_pitch_facing_position(&pos, &facing_entity.get_entity().pos.load());
let (yaw, pitch) =
yaw_pitch_facing_position(&pos, &facing_entity.get_entity().pos.load());
for target in targets {
target
@ -158,19 +161,20 @@ impl CommandExecutor for EntitiesToPosFacingEntityExecutor {
}
Ok(())
})
}
}
struct EntitiesToPosWithRotationExecutor;
#[async_trait]
impl CommandExecutor for EntitiesToPosWithRotationExecutor {
async fn execute<'a>(
&self,
_sender: &mut CommandSender,
server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
_sender: &'a CommandSender,
server: &'a crate::server::Server,
args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let targets = EntitiesArgumentConsumer::find_arg(args, ARG_TARGETS)?;
let pos = Position3DArgumentConsumer::find_arg(args, ARG_LOCATION)?;
@ -191,19 +195,20 @@ impl CommandExecutor for EntitiesToPosWithRotationExecutor {
}
Ok(())
})
}
}
struct EntitiesToPosExecutor;
#[async_trait]
impl CommandExecutor for EntitiesToPosExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
server: &'a crate::server::Server,
args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let targets = EntitiesArgumentConsumer::find_arg(args, ARG_TARGETS)?;
let pos = Position3DArgumentConsumer::find_arg(args, ARG_LOCATION)?;
@ -229,19 +234,20 @@ impl CommandExecutor for EntitiesToPosExecutor {
}
Ok(())
})
}
}
struct SelfToEntityExecutor;
#[async_trait]
impl CommandExecutor for SelfToEntityExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
_server: &'a crate::server::Server,
args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let destination = EntityArgumentConsumer::find_arg(args, ARG_DESTINATION)?;
let pos = destination.get_entity().pos.load();
let world = destination.get_entity().world.clone();
@ -268,18 +274,19 @@ impl CommandExecutor for SelfToEntityExecutor {
}
Ok(())
})
}
}
struct SelfToPosExecutor;
#[async_trait]
impl CommandExecutor for SelfToPosExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
_server: &'a crate::server::Server,
args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
match sender {
CommandSender::Player(player) => {
let pos = Position3DArgumentConsumer::find_arg(args, ARG_LOCATION)?;
@ -303,6 +310,7 @@ impl CommandExecutor for SelfToPosExecutor {
}
Ok(())
})
}
}

View File

@ -1,13 +1,11 @@
use crate::command::{
CommandError, CommandExecutor, CommandSender,
CommandError, CommandExecutor, CommandResult, CommandSender,
args::{
Arg, ConsumedArgs, FindArg, players::PlayersArgumentConsumer,
textcomponent::TextComponentArgConsumer,
},
tree::CommandTree,
tree::builder::argument,
tree::{CommandTree, builder::argument},
};
use async_trait::async_trait;
const NAMES: [&str; 1] = ["tellraw"];
@ -19,14 +17,14 @@ const ARG_MESSAGE: &str = "message";
struct TellRawExecutor;
#[async_trait]
impl CommandExecutor for TellRawExecutor {
async fn execute<'a>(
&self,
_sender: &mut CommandSender,
_server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
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::Players(targets)) = args.get(&ARG_TARGETS) else {
return Err(CommandError::InvalidConsumption(Some(ARG_TARGETS.into())));
};
@ -36,6 +34,7 @@ impl CommandExecutor for TellRawExecutor {
target.send_system_message(&text).await;
}
Ok(())
})
}
}

View File

@ -1,4 +1,3 @@
use async_trait::async_trait;
use pumpkin_config::BASIC_CONFIG;
use pumpkin_util::text::{
TextComponent,
@ -7,7 +6,7 @@ use pumpkin_util::text::{
use std::sync::atomic::Ordering;
use crate::command::{
CommandExecutor, CommandSender,
CommandExecutor, CommandResult, CommandSender,
args::{
ConsumedArgs, FindArg, bounded_num::BoundedNumArgumentConsumer, time::TimeArgumentConsumer,
},
@ -199,14 +198,14 @@ impl TickExecutor {
}
}
#[async_trait]
impl CommandExecutor for TickExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
server: &'a crate::server::Server,
args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let manager = &server.tick_rate_manager;
match self.0 {
@ -244,7 +243,9 @@ impl CommandExecutor for TickExecutor {
.await;
Ok(())
}
SubCommand::StepDefault => self.handle_step_command(sender, server, manager, 1).await,
SubCommand::StepDefault => {
self.handle_step_command(sender, server, manager, 1).await
}
SubCommand::StepTimed => {
let ticks = TimeArgumentConsumer::find_arg(args, "time")?;
self.handle_step_command(sender, server, manager, ticks)
@ -264,7 +265,10 @@ impl CommandExecutor for TickExecutor {
.await;
} else {
sender
.send_message(TextComponent::translate("commands.tick.step.stop.fail", []))
.send_message(TextComponent::translate(
"commands.tick.step.stop.fail",
[],
))
.await;
}
Ok(())
@ -297,6 +301,7 @@ impl CommandExecutor for TickExecutor {
Ok(())
}
}
})
}
}

View File

@ -1,12 +1,10 @@
use async_trait::async_trait;
use pumpkin_util::text::TextComponent;
use pumpkin_util::text::color::{Color, NamedColor};
use crate::command::CommandResult;
use crate::command::args::{FindArg, time::TimeArgumentConsumer};
use crate::command::tree::builder::{argument, literal};
use crate::command::{
CommandError, CommandExecutor, CommandSender, ConsumedArgs, tree::CommandTree,
};
use crate::command::{CommandExecutor, CommandSender, ConsumedArgs, tree::CommandTree};
const NAMES: [&str; 1] = ["time"];
const DESCRIPTION: &str = "Query the world time.";
@ -46,14 +44,14 @@ enum QueryMode {
struct QueryExecutor(QueryMode);
#[async_trait]
impl CommandExecutor for QueryExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &crate::server::Server,
_args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
server: &'a crate::server::Server,
_args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let mode = self.0;
// TODO: Maybe ask player for world, or get the current world
let worlds = server.worlds.read().await;
@ -88,19 +86,20 @@ impl CommandExecutor for QueryExecutor {
sender.send_message(msg).await;
Ok(())
})
}
}
struct ChangeExecutor(Mode);
#[async_trait]
impl CommandExecutor for ChangeExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
server: &'a crate::server::Server,
args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let time_count = if let Mode::Set(Some(preset)) = &self.0 {
preset.to_ticks()
} else if let Ok(ticks) = TimeArgumentConsumer::find_arg(args, ARG_TIME) {
@ -147,6 +146,7 @@ impl CommandExecutor for ChangeExecutor {
sender.send_message(msg).await;
Ok(())
})
}
}

View File

@ -1,7 +1,7 @@
use async_trait::async_trait;
use pumpkin_protocol::java::client::play::CClearTitle;
use pumpkin_util::text::TextComponent;
use crate::command::CommandResult;
use crate::entity::EntityBase;
use crate::{
command::{
@ -27,14 +27,14 @@ const ARG_TITLE: &str = "title";
/// bool: Whether to reset or not
struct ClearOrResetExecutor(bool);
#[async_trait]
impl CommandExecutor for ClearOrResetExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
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::Players(targets)) = args.get(&ARG_TARGETS) else {
return Err(CommandError::InvalidConsumption(Some(ARG_TARGETS.into())));
};
@ -62,19 +62,20 @@ impl CommandExecutor for ClearOrResetExecutor {
.await;
Ok(())
})
}
}
struct TitleExecutor(TitleMode);
#[async_trait]
impl CommandExecutor for TitleExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
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::Players(targets)) = args.get(&ARG_TARGETS) else {
return Err(CommandError::InvalidConsumption(Some(ARG_TARGETS.into())));
};
@ -103,6 +104,7 @@ impl CommandExecutor for TitleExecutor {
.await;
Ok(())
})
}
}

View File

@ -1,18 +1,16 @@
use async_trait::async_trait;
use pumpkin_protocol::codec::var_int::VarInt;
use pumpkin_protocol::java::client::play::CTransfer;
use pumpkin_util::text::TextComponent;
use pumpkin_util::text::color::{Color, NamedColor};
use crate::command::CommandResult;
use crate::command::args::bounded_num::BoundedNumArgumentConsumer;
use crate::command::args::players::PlayersArgumentConsumer;
use crate::command::args::simple::SimpleArgConsumer;
use crate::command::args::{Arg, FindArgDefaultName};
use crate::command::dispatcher::CommandError::{InvalidConsumption, InvalidRequirement};
use crate::command::tree::builder::{argument, argument_default_name, require};
use crate::command::{
CommandError, CommandExecutor, CommandSender, args::ConsumedArgs, tree::CommandTree,
};
use crate::command::{CommandExecutor, CommandSender, args::ConsumedArgs, tree::CommandTree};
const NAMES: [&str; 1] = ["transfer"];
@ -31,14 +29,14 @@ fn port_consumer() -> BoundedNumArgumentConsumer<i32> {
struct TargetSelfExecutor;
#[async_trait]
impl CommandExecutor for TargetSelfExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
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(hostname)) = args.get(ARG_HOSTNAME) else {
return Err(InvalidConsumption(Some(ARG_HOSTNAME.into())));
};
@ -68,19 +66,20 @@ impl CommandExecutor for TargetSelfExecutor {
} else {
Err(InvalidRequirement)
}
})
}
}
struct TargetPlayerExecutor;
#[async_trait]
impl CommandExecutor for TargetPlayerExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
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(hostname)) = args.get(ARG_HOSTNAME) else {
return Err(InvalidConsumption(Some(ARG_HOSTNAME.into())));
};
@ -114,6 +113,7 @@ impl CommandExecutor for TargetPlayerExecutor {
}
Ok(())
})
}
}

View File

@ -1,11 +1,12 @@
use async_trait::async_trait;
use pumpkin_util::text::TextComponent;
use crate::command::{
CommandError, CommandExecutor, CommandSender,
CommandError, CommandExecutor, CommandResult, CommandSender,
args::{ConsumedArgs, FindArg, time::TimeArgumentConsumer},
tree::CommandTree,
tree::builder::{argument, literal},
tree::{
CommandTree,
builder::{argument, literal},
},
};
const NAMES: [&str; 1] = ["weather"];
@ -22,14 +23,14 @@ enum WeatherMode {
Thunder,
}
#[async_trait]
impl CommandExecutor for Executor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
server: &'a crate::server::Server,
args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let duration = TimeArgumentConsumer::find_arg(args, ARG_DURATION).unwrap_or(6000);
let world = {
let guard = server.worlds.read().await;
@ -69,6 +70,7 @@ impl CommandExecutor for Executor {
}
Ok(())
})
}
}

View File

@ -1,9 +1,9 @@
use std::sync::atomic::Ordering;
use async_trait::async_trait;
use pumpkin_config::{BASIC_CONFIG, whitelist::WhitelistEntry};
use pumpkin_util::text::TextComponent;
use crate::command::CommandResult;
use crate::entity::EntityBase;
use crate::{
command::{
@ -46,14 +46,14 @@ async fn kick_non_whitelisted_players(server: &Server) {
struct OnExecutor;
#[async_trait]
impl CommandExecutor for OnExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &Server,
_args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
server: &'a crate::server::Server,
_args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let previous = server.white_list.swap(true, Ordering::Relaxed);
if previous {
sender
@ -69,19 +69,20 @@ impl CommandExecutor for OnExecutor {
.await;
}
Ok(())
})
}
}
struct OffExecutor;
#[async_trait]
impl CommandExecutor for OffExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &Server,
_args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
server: &'a crate::server::Server,
_args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let previous = server.white_list.swap(false, Ordering::Relaxed);
if previous {
sender
@ -96,19 +97,20 @@ impl CommandExecutor for OffExecutor {
.await;
}
Ok(())
})
}
}
struct ListExecutor;
#[async_trait]
impl CommandExecutor for ListExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &Server,
_args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
_server: &'a crate::server::Server,
_args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
let whitelist = &WHITELIST_CONFIG.read().await.whitelist;
if whitelist.is_empty() {
sender
@ -134,38 +136,40 @@ impl CommandExecutor for ListExecutor {
.await;
Ok(())
})
}
}
struct ReloadExecutor;
#[async_trait]
impl CommandExecutor for ReloadExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &Server,
_args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
server: &'a crate::server::Server,
_args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
*WHITELIST_CONFIG.write().await = WhitelistConfig::load();
kick_non_whitelisted_players(server).await;
sender
.send_message(TextComponent::translate("commands.whitelist.reloaded", &[]))
.await;
Ok(())
})
}
}
pub struct AddExecutor;
#[async_trait]
impl CommandExecutor for AddExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
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::Players(targets)) = args.get(&ARG_TARGETS) else {
return Err(CommandError::InvalidConsumption(Some(ARG_TARGETS.into())));
};
@ -195,19 +199,20 @@ impl CommandExecutor for AddExecutor {
whitelist.save();
Ok(())
})
}
}
pub struct RemoveExecutor;
#[async_trait]
impl CommandExecutor for RemoveExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
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::Players(targets)) = args.get(&ARG_TARGETS) else {
return Err(CommandError::InvalidConsumption(Some(ARG_TARGETS.into())));
};
@ -245,6 +250,7 @@ impl CommandExecutor for RemoveExecutor {
kick_non_whitelisted_players(server).await;
Ok(())
})
}
}

View File

@ -1,4 +1,3 @@
use async_trait::async_trait;
use pumpkin_util::{
math::vector2::Vector2,
text::{
@ -7,17 +6,16 @@ use pumpkin_util::{
},
};
use crate::{
command::{
CommandError, CommandExecutor, CommandSender,
use crate::command::{
CommandExecutor, CommandResult, CommandSender,
args::{
ConsumedArgs, DefaultNameArgConsumer, FindArgDefaultName,
bounded_num::BoundedNumArgumentConsumer, position_2d::Position2DArgumentConsumer,
},
tree::CommandTree,
tree::builder::{argument_default_name, literal},
tree::{
CommandTree,
builder::{argument_default_name, literal},
},
server::Server,
};
const NAMES: [&str; 1] = ["worldborder"];
@ -50,14 +48,14 @@ fn warning_distance_consumer() -> BoundedNumArgumentConsumer<i32> {
struct GetExecutor;
#[async_trait]
impl CommandExecutor for GetExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &Server,
_args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
server: &'a crate::server::Server,
_args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
// TODO: Maybe ask player for world, or get the current world
let worlds = server.worlds.read().await;
let world = worlds
@ -73,19 +71,20 @@ impl CommandExecutor for GetExecutor {
))
.await;
Ok(())
})
}
}
struct SetExecutor;
#[async_trait]
impl CommandExecutor for SetExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
server: &'a crate::server::Server,
args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
// TODO: Maybe ask player for world, or get the current world
let worlds = server.worlds.read().await;
let world = worlds
@ -125,19 +124,20 @@ impl CommandExecutor for SetExecutor {
.await;
border.set_diameter(world, distance, None).await;
Ok(())
})
}
}
struct SetTimeExecutor;
#[async_trait]
impl CommandExecutor for SetTimeExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
server: &'a crate::server::Server,
args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
// TODO: Maybe ask player for world, or get the current world
let worlds = server.worlds.read().await;
let world = worlds
@ -210,19 +210,20 @@ impl CommandExecutor for SetTimeExecutor {
.set_diameter(world, distance, Some(i64::from(time) * 1000))
.await;
Ok(())
})
}
}
struct AddExecutor;
#[async_trait]
impl CommandExecutor for AddExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
server: &'a crate::server::Server,
args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
// TODO: Maybe ask player for world, or get the current world
let worlds = server.worlds.read().await;
let world = worlds
@ -264,19 +265,20 @@ impl CommandExecutor for AddExecutor {
.await;
border.set_diameter(world, distance, None).await;
Ok(())
})
}
}
struct AddTimeExecutor;
#[async_trait]
impl CommandExecutor for AddTimeExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
server: &'a crate::server::Server,
args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
// TODO: Maybe ask player for world, or get the current world
let worlds = server.worlds.read().await;
let world = worlds
@ -351,19 +353,20 @@ impl CommandExecutor for AddTimeExecutor {
.set_diameter(world, distance, Some(i64::from(time) * 1000))
.await;
Ok(())
})
}
}
struct CenterExecutor;
#[async_trait]
impl CommandExecutor for CenterExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
server: &'a crate::server::Server,
args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
// TODO: Maybe ask player for world, or get the current world
let worlds = server.worlds.read().await;
let world = worlds
@ -384,19 +387,20 @@ impl CommandExecutor for CenterExecutor {
.await;
border.set_center(world, x, y).await;
Ok(())
})
}
}
struct DamageAmountExecutor;
#[async_trait]
impl CommandExecutor for DamageAmountExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
server: &'a crate::server::Server,
args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
// TODO: Maybe ask player for world, or get the current world
let worlds = server.worlds.read().await;
let world = worlds
@ -404,7 +408,8 @@ impl CommandExecutor for DamageAmountExecutor {
.expect("There should always be at least one world");
let mut border = world.worldborder.lock().await;
let Ok(damage_per_block) = damage_per_block_consumer().find_arg_default_name(args)? else {
let Ok(damage_per_block) = damage_per_block_consumer().find_arg_default_name(args)?
else {
sender
.send_message(
TextComponent::text(format!(
@ -436,19 +441,20 @@ impl CommandExecutor for DamageAmountExecutor {
.await;
border.damage_per_block = damage_per_block;
Ok(())
})
}
}
struct DamageBufferExecutor;
#[async_trait]
impl CommandExecutor for DamageBufferExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
server: &'a crate::server::Server,
args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
// TODO: Maybe ask player for world, or get the current world
let worlds = server.worlds.read().await;
let world = worlds
@ -488,19 +494,20 @@ impl CommandExecutor for DamageBufferExecutor {
.await;
border.buffer = buffer;
Ok(())
})
}
}
struct WarningDistanceExecutor;
#[async_trait]
impl CommandExecutor for WarningDistanceExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
server: &'a crate::server::Server,
args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
// TODO: Maybe ask player for world, or get the current world
let worlds = server.worlds.read().await;
let world = worlds
@ -524,7 +531,10 @@ impl CommandExecutor for WarningDistanceExecutor {
if distance == border.warning_blocks {
sender
.send_message(
TextComponent::translate("commands.worldborder.warning.distance.failed", [])
TextComponent::translate(
"commands.worldborder.warning.distance.failed",
[],
)
.color(Color::Named(NamedColor::Red)),
)
.await;
@ -539,19 +549,20 @@ impl CommandExecutor for WarningDistanceExecutor {
.await;
border.set_warning_distance(world, distance).await;
Ok(())
})
}
}
struct WarningTimeExecutor;
#[async_trait]
impl CommandExecutor for WarningTimeExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
server: &'a crate::server::Server,
args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
// TODO: Maybe ask player for world, or get the current world
let worlds = server.worlds.read().await;
let world = worlds
@ -590,6 +601,7 @@ impl CommandExecutor for WarningTimeExecutor {
.await;
border.set_warning_delay(world, time).await;
Ok(())
})
}
}

View File

@ -64,7 +64,7 @@ pub struct CommandDispatcher {
impl CommandDispatcher {
pub async fn handle_command<'a>(
&'a self,
sender: &mut CommandSender,
sender: &CommandSender,
server: &'a Server,
cmd: &'a str,
) {
@ -242,7 +242,7 @@ impl CommandDispatcher {
/// Execute a command using its corresponding [`CommandTree`].
pub(crate) async fn dispatch<'a>(
&'a self,
src: &mut CommandSender,
src: &CommandSender,
server: &'a Server,
cmd: &'a str,
) -> Result<(), CommandError> {
@ -302,7 +302,7 @@ impl CommandDispatcher {
}
async fn try_is_fitting_path<'a>(
src: &mut CommandSender,
src: &'a CommandSender,
server: &'a Server,
path: &[usize],
tree: &'a CommandTree,
@ -357,7 +357,7 @@ impl CommandDispatcher {
}
async fn try_find_suggestions_on_path<'a>(
src: &CommandSender,
src: &'a CommandSender,
server: &'a Server,
path: &[usize],
tree: &'a CommandTree,

View File

@ -1,4 +1,5 @@
use std::fmt;
use std::pin::Pin;
use std::str::FromStr;
use std::sync::Arc;
@ -6,7 +7,6 @@ use crate::entity::player::Player;
use crate::server::Server;
use crate::world::World;
use args::ConsumedArgs;
use async_trait::async_trait;
use dispatcher::CommandError;
use pumpkin_util::math::vector3::Vector3;
@ -118,12 +118,13 @@ impl CommandSender {
}
}
#[async_trait]
pub trait CommandExecutor: Sync {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
server: &Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError>;
pub type CommandResult<'a> = Pin<Box<dyn Future<Output = Result<(), CommandError>> + Send + 'a>>;
pub trait CommandExecutor: Sync + Send {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
server: &'a Server,
args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a>;
}

View File

@ -39,7 +39,7 @@ impl CommandTree {
///
/// Also see [`NonLeafNodeBuilder::execute`].
#[must_use]
pub fn execute(mut self, executor: impl CommandExecutor + 'static + Send) -> Self {
pub fn execute(mut self, executor: impl CommandExecutor + 'static) -> Self {
let node = Node {
node_type: NodeType::ExecuteLeaf {
executor: Arc::new(executor),
@ -116,7 +116,7 @@ impl NonLeafNodeBuilder {
///
/// Also see [`CommandTree::execute`].
#[must_use]
pub fn execute(mut self, executor: impl CommandExecutor + 'static + Send) -> Self {
pub fn execute(mut self, executor: impl CommandExecutor + 'static) -> Self {
self.leaf_nodes.push(LeafNodeBuilder {
node_type: NodeType::ExecuteLeaf {
executor: Arc::new(executor),
@ -149,7 +149,7 @@ pub fn literal(string: impl Into<String>) -> NonLeafNodeBuilder {
/// reversed, so [`Vec::pop`] can be used to obtain args in ltr order.
pub fn argument(
name: impl Into<String>,
consumer: impl ArgumentConsumer + 'static + Send,
consumer: impl ArgumentConsumer + 'static,
) -> NonLeafNodeBuilder {
NonLeafNodeBuilder {
node_type: NodeType::Argument {

View File

@ -489,7 +489,7 @@ async fn setup_stdin_console(server: Arc<Server>) {
'after: {
let dispatcher = &server.command_dispatcher.read().await;
dispatcher
.handle_command(&mut command::CommandSender::Console, &server, command.as_str())
.handle_command(&command::CommandSender::Console, &server, command.as_str())
.await;
};
}}
@ -522,7 +522,7 @@ fn setup_console(rl: Readline, server: Arc<Server>) {
let dispatcher = server.command_dispatcher.read().await;
dispatcher
.handle_command(&mut command::CommandSender::Console, &server, &line)
.handle_command(&command::CommandSender::Console, &server, &line)
.await;
rl.add_history_entry(line).unwrap();
}

View File

@ -225,7 +225,7 @@ impl BedrockClient {
let dispatcher = server_clone.command_dispatcher.read().await;
dispatcher
.handle_command(
&mut CommandSender::Player(player_clone),
&CommandSender::Player(player_clone),
&server_clone,
&command_clone,
)

View File

@ -544,7 +544,7 @@ impl JavaClient {
server.spawn_task(async move {
server_clone.command_dispatcher.read().await
.handle_command(
&mut CommandSender::Player(player_clone),
&CommandSender::Player(player_clone),
&server_clone,
&command_clone,
)

View File

@ -131,7 +131,7 @@ impl RCONClient {
.read()
.await
.handle_command(
&mut crate::command::CommandSender::Rcon(output_clone),
&crate::command::CommandSender::Rcon(output_clone),
&server_clone,
&packet_body,
)