feat: add swing command

This commit is contained in:
Alexander Medvedev 2026-09-19 13:49:52 +02:00
parent c31eb83616
commit 8813176fdd
5 changed files with 264 additions and 72 deletions

183
Cargo.lock generated
View File

@ -263,9 +263,9 @@ dependencies = [
[[package]] [[package]]
name = "async-compression" name = "async-compression"
version = "0.4.46" version = "0.4.47"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f10dafd0c8d2e51ae9a748805777613ed0bbe17bf586b76c8311f45c020a32f" checksum = "ef217a77a86a6e3dab9a5b3c81dc445b603fe743a90c1cb10a2f2144628d8cfa"
dependencies = [ dependencies = [
"compression-codecs", "compression-codecs",
"compression-core", "compression-core",
@ -746,9 +746,9 @@ dependencies = [
[[package]] [[package]]
name = "compression-codecs" name = "compression-codecs"
version = "0.4.41" version = "0.4.42"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58a6d0db8759036a783bc7c3f7a07f8cef3bf9470eb1db3bc86e8bcd1c5d0fe8" checksum = "257c7085cbb71be72d8fb97edff08b03d86d5d9f2222b9cc34a6bec87093bc10"
dependencies = [ dependencies = [
"compression-core", "compression-core",
"flate2", "flate2",
@ -1345,12 +1345,6 @@ version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
[[package]]
name = "diff"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
[[package]] [[package]]
name = "digest" name = "digest"
version = "0.10.7" version = "0.10.7"
@ -3167,24 +3161,14 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]]
name = "pretty_assertions"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d"
dependencies = [
"diff",
"yansi",
]
[[package]] [[package]]
name = "prettyplease" name = "prettyplease"
version = "0.2.37" version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" checksum = "2bfe0f4c752e450fc2faf62654f1c134747922825d5b04ca717b8874f41a40c0"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"syn 2.0.119", "syn 3.0.5",
] ]
[[package]] [[package]]
@ -3391,8 +3375,8 @@ dependencies = [
"tracing-serde-structured", "tracing-serde-structured",
"tracing-subscriber", "tracing-subscriber",
"uuid", "uuid",
"wasm-encoder", "wasm-encoder 0.259.0",
"wasmparser", "wasmparser 0.259.0",
"wasmtime", "wasmtime",
"wasmtime-wasi", "wasmtime-wasi",
"wasmtime-wasi-http", "wasmtime-wasi-http",
@ -3588,7 +3572,7 @@ dependencies = [
"thiserror 2.0.20", "thiserror 2.0.20",
"tokio", "tokio",
"tracing", "tracing",
"wasm-encoder", "wasm-encoder 0.259.0",
"wasmtime", "wasmtime",
] ]
@ -4728,9 +4712,9 @@ dependencies = [
[[package]] [[package]]
name = "smallvec" name = "smallvec"
version = "1.16.0" version = "1.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9be42f50aa861c555654aa3a37f52f4b1074bacf4e48fe0ef7fa584e80f1f0f" checksum = "ba467056f1b547ed52077911161fc86985becbc60e8e1857c8a144dab0def891"
dependencies = [ dependencies = [
"serde", "serde",
] ]
@ -5464,7 +5448,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e974fe6821a8cf64575d51ea2194e2c8f77e7b66e9afe7419ce8a97f9ee0d251" checksum = "e974fe6821a8cf64575d51ea2194e2c8f77e7b66e9afe7419ce8a97f9ee0d251"
dependencies = [ dependencies = [
"leb128fmt", "leb128fmt",
"wasmparser", "wasmparser 0.258.0",
]
[[package]]
name = "wasm-encoder"
version = "0.259.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1d0246511d901aacf25d2dc9111f0054947de5e093fe662099e709ff7530dc3"
dependencies = [
"leb128fmt",
"wasmparser 0.259.0",
] ]
[[package]] [[package]]
@ -5475,8 +5469,20 @@ checksum = "18a11585adb92fe9b55ad1d760e8d8fb5d87e0d2e303cb8eed57f078d54293a2"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"indexmap", "indexmap",
"wasm-encoder", "wasm-encoder 0.258.0",
"wasmparser", "wasmparser 0.258.0",
]
[[package]]
name = "wasm-metadata"
version = "0.259.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e7bf119eb01f4a246864c10bd87c8f26c566350abb25aa4d5273c415bbab338"
dependencies = [
"anyhow",
"indexmap",
"wasm-encoder 0.259.0",
"wasmparser 0.259.0",
] ]
[[package]] [[package]]
@ -5492,6 +5498,18 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "wasmparser"
version = "0.259.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f7c12eac7bb587801590f6a67ff0bc84d0748513864b71108e4b311cc3df694"
dependencies = [
"bitflags 2.13.2",
"hashbrown 0.17.1",
"indexmap",
"semver",
]
[[package]] [[package]]
name = "wasmprinter" name = "wasmprinter"
version = "0.258.0" version = "0.258.0"
@ -5500,7 +5518,7 @@ checksum = "3a65e30fb2cd3cc5cb7761a6064787b2abf017e6566d8d0dedf2bb7f55ad5383"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"termcolor", "termcolor",
"wasmparser", "wasmparser 0.258.0",
] ]
[[package]] [[package]]
@ -5530,7 +5548,7 @@ dependencies = [
"serde_derive", "serde_derive",
"smallvec", "smallvec",
"target-lexicon", "target-lexicon",
"wasmparser", "wasmparser 0.258.0",
"wasmtime-environ", "wasmtime-environ",
"wasmtime-internal-cache", "wasmtime-internal-cache",
"wasmtime-internal-component-macro", "wasmtime-internal-component-macro",
@ -5568,8 +5586,8 @@ dependencies = [
"sha2 0.10.9", "sha2 0.10.9",
"smallvec", "smallvec",
"target-lexicon", "target-lexicon",
"wasm-encoder", "wasm-encoder 0.258.0",
"wasmparser", "wasmparser 0.258.0",
"wasmprinter", "wasmprinter",
"wasmtime-internal-component-util", "wasmtime-internal-component-util",
"wasmtime-internal-core", "wasmtime-internal-core",
@ -5605,7 +5623,7 @@ dependencies = [
"syn 2.0.119", "syn 2.0.119",
"wasmtime-internal-component-util", "wasmtime-internal-component-util",
"wasmtime-internal-wit-bindgen", "wasmtime-internal-wit-bindgen",
"wit-parser", "wit-parser 0.258.0",
] ]
[[package]] [[package]]
@ -5641,7 +5659,7 @@ dependencies = [
"smallvec", "smallvec",
"target-lexicon", "target-lexicon",
"thiserror 2.0.20", "thiserror 2.0.20",
"wasmparser", "wasmparser 0.258.0",
"wasmtime-environ", "wasmtime-environ",
"wasmtime-internal-core", "wasmtime-internal-core",
"wasmtime-internal-unwinder", "wasmtime-internal-unwinder",
@ -5710,8 +5728,8 @@ dependencies = [
"bitflags 2.13.2", "bitflags 2.13.2",
"heck", "heck",
"indexmap", "indexmap",
"wit-component", "wit-component 0.258.0",
"wit-parser", "wit-parser 0.258.0",
] ]
[[package]] [[package]]
@ -6143,51 +6161,51 @@ dependencies = [
[[package]] [[package]]
name = "wit-bindgen" name = "wit-bindgen"
version = "0.61.1" version = "0.62.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e473fd0095479f9689ac7d2a52c427cc96bb2b973ace50238dfcc1ab1cd52d93" checksum = "53cb4b5556c3a791e86838ea287782bdafa704d55b0e68b5b81a3a16b9ea5f4b"
dependencies = [ dependencies = [
"wit-bindgen-rust-macro", "wit-bindgen-rust-macro",
] ]
[[package]] [[package]]
name = "wit-bindgen-core" name = "wit-bindgen-core"
version = "0.61.1" version = "0.62.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87445680dfe6d6b5369e884bd63c03a3335268e855365b2fc3f7bcdce96a630e" checksum = "72ad22a37ecbc0e1fdca34d2b670ba41368cb0920735643e00fdf39a16ee5431"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"heck", "heck",
"wit-parser", "wit-parser 0.259.0",
] ]
[[package]] [[package]]
name = "wit-bindgen-rust" name = "wit-bindgen-rust"
version = "0.61.1" version = "0.62.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72f2fe494de0d898216caf0fd0ae76af75753fcb3ff4f465b46131537cf24cf8" checksum = "84ba5213d4332c260a0d4e69e34b0f7e4b85ddae10b6ebfbac00d9c185ba628a"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"heck", "heck",
"indexmap", "indexmap",
"prettyplease", "prettyplease",
"syn 2.0.119", "syn 3.0.5",
"wasm-metadata", "wasm-metadata 0.259.0",
"wit-bindgen-core", "wit-bindgen-core",
"wit-component", "wit-component 0.259.0",
] ]
[[package]] [[package]]
name = "wit-bindgen-rust-macro" name = "wit-bindgen-rust-macro"
version = "0.61.1" version = "0.62.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59283a01aec94f60f92ada22ffe182a5cea8acfce43be3be688de8d52df55312" checksum = "8f19d63da8e478a370ef8192d90ccb517965b7747d6b46cd2d831dd0ef4d2541"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"prettyplease", "prettyplease",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.119", "syn 3.0.5",
"wit-bindgen-core", "wit-bindgen-core",
"wit-bindgen-rust", "wit-bindgen-rust",
] ]
@ -6205,23 +6223,41 @@ dependencies = [
"serde", "serde",
"serde_derive", "serde_derive",
"serde_json", "serde_json",
"wasm-encoder", "wasm-encoder 0.258.0",
"wasm-metadata", "wasm-metadata 0.258.0",
"wasmparser", "wasmparser 0.258.0",
"wit-parser", "wit-parser 0.258.0",
]
[[package]]
name = "wit-component"
version = "0.259.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "092f783dee3253265fcde131475055f8c275ac0176a9c0396db1dc7b5544bfb4"
dependencies = [
"anyhow",
"bitflags 2.13.2",
"indexmap",
"log",
"serde",
"serde_derive",
"serde_json",
"wasm-encoder 0.259.0",
"wasm-metadata 0.259.0",
"wasmparser 0.259.0",
"wit-parser 0.259.0",
] ]
[[package]] [[package]]
name = "wit-encoder" name = "wit-encoder"
version = "0.258.0" version = "0.259.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c51673292067471f5ab553537dc49a13e9a1fda20904c936daed0b240c12b220" checksum = "f74e1bfe03fe729d239842840846eef48b7ab72ce81140f09ec4dbe98675b629"
dependencies = [ dependencies = [
"id-arena", "id-arena",
"pretty_assertions",
"semver", "semver",
"serde", "serde",
"wit-parser", "wit-parser 0.259.0",
] ]
[[package]] [[package]]
@ -6240,7 +6276,26 @@ dependencies = [
"serde_derive", "serde_derive",
"serde_json", "serde_json",
"unicode-ident", "unicode-ident",
"wasmparser", "wasmparser 0.258.0",
]
[[package]]
name = "wit-parser"
version = "0.259.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6390f4f02493ce678d509c859cf1698e38929fb75c8012a6ee2f7d6b6cb66cd7"
dependencies = [
"anyhow",
"hashbrown 0.17.1",
"id-arena",
"indexmap",
"log",
"semver",
"serde",
"serde_derive",
"serde_json",
"unicode-ident",
"wasmparser 0.259.0",
] ]
[[package]] [[package]]
@ -6314,12 +6369,6 @@ version = "0.8.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aee1b19627c7c60102ab80d3a9cbe18de90bfe03bfa6c3715447681f0e8c8af6" checksum = "aee1b19627c7c60102ab80d3a9cbe18de90bfe03bfa6c3715447681f0e8c8af6"
[[package]]
name = "yansi"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
[[package]] [[package]]
name = "yasna" name = "yasna"
version = "0.6.0" version = "0.6.0"

View File

@ -150,7 +150,7 @@ serde_json = { version = "1.0", default-features = false, features = ["std"] }
tempfile = { version = "3.27.0", default-features = false } tempfile = { version = "3.27.0", default-features = false }
proc-macro-error2 = { version = "2", default-features = false } proc-macro-error2 = { version = "2", default-features = false }
aes = { version = "0.9", default-features = false } aes = { version = "0.9", default-features = false }
async-compression = { version = "0.4.46", default-features = false } async-compression = { version = "0.4.47", default-features = false }
base64 = { version = "0.23.1", default-features = false, features = ["std"] } base64 = { version = "0.23.1", default-features = false, features = ["std"] }
bitflags = { version = "2.13.2", default-features = false, features = ["std"] } bitflags = { version = "2.13.2", default-features = false, features = ["std"] }
cesu8 = { version = "1.1", default-features = false } cesu8 = { version = "1.1", default-features = false }
@ -235,12 +235,12 @@ hyper = { version = "^1.11", default-features = false }
axum = { version = "0.8.9", default-features = false, features = ["http1", "tokio"] } axum = { version = "0.8.9", default-features = false, features = ["http1", "tokio"] }
webrtc = { version = "0.20.5" } webrtc = { version = "0.20.5" }
async-trait = "0.1" async-trait = "0.1"
wit-bindgen = { version = "0.61", default-features = false, features = ["macros"] } wit-bindgen = { version = "0.62", default-features = false, features = ["macros"] }
postcard = { version = "1.1", default-features = false, features = ["alloc"] } postcard = { version = "1.1", default-features = false, features = ["alloc"] }
tracing-serde-structured = { version = "0.4", default-features = false } tracing-serde-structured = { version = "0.4", default-features = false }
wasmparser = { version = "0.258", default-features = false } wasmparser = { version = "0.259", default-features = false }
wasm-encoder = { version = "0.258", default-features = false, features = ["component-model", "std"] } wasm-encoder = { version = "0.259", default-features = false, features = ["component-model", "std"] }
webpki-root-certs = { version = "1.0.9", default-features = false } webpki-root-certs = { version = "1.0.9", default-features = false }
# ring-only: must match the provider the rest of the tree (wasmtime-wasi-http, rtc) uses # ring-only: must match the provider the rest of the tree (wasmtime-wasi-http, rtc) uses
rustls = { version = "0.23", default-features = false, features = ["ring", "std", "tls12", "logging"] } rustls = { version = "0.23", default-features = false, features = ["ring", "std", "tls12", "logging"] }

View File

@ -76,6 +76,7 @@ mod stop;
mod stopsound; mod stopsound;
mod stopwatch; mod stopwatch;
mod summon; mod summon;
mod swing;
mod tag; mod tag;
mod team; mod team;
mod teammsg; mod teammsg;
@ -172,6 +173,7 @@ pub fn default_dispatcher(
enchant::register(&mut dispatcher, registry); enchant::register(&mut dispatcher, registry);
effect::register(&mut dispatcher, registry); effect::register(&mut dispatcher, registry);
summon::register(&mut dispatcher, registry); summon::register(&mut dispatcher, registry);
swing::register(&mut dispatcher, registry);
damage::register(&mut dispatcher, registry); damage::register(&mut dispatcher, registry);
rotate::register(&mut dispatcher, registry); rotate::register(&mut dispatcher, registry);
tellraw::register(&mut dispatcher, registry); tellraw::register(&mut dispatcher, registry);

View File

@ -0,0 +1,141 @@
use std::sync::Arc;
use crate::command::argument_builder::{ArgumentBuilder, argument, command, literal};
use crate::command::argument_types::entity::EntityArgumentType;
use crate::command::context::command_context::CommandContext;
use crate::command::context::command_source::CommandSource;
use crate::command::errors::error_types::CommandErrorType;
use crate::command::node::dispatcher::CommandDispatcher;
use crate::command::node::{CommandExecutor, CommandExecutorResult};
use crate::entity::EntityBase;
use pumpkin_data::translation;
use pumpkin_util::PermissionLvl;
use pumpkin_util::permission::{Permission, PermissionDefault, PermissionRegistry};
use pumpkin_util::text::TextComponent;
const DESCRIPTION: &str = "Causes entities to swing their arm.";
const PERMISSION: &str = "minecraft:command.swing";
const ARG_TARGETS: &str = "targets";
const ERROR_NO_LIVING_ENTITY: CommandErrorType<0> = CommandErrorType::new(
translation::java::COMMANDS_SWING_FAILED_NOTLIVING,
translation::java::COMMANDS_SWING_FAILED_NOTLIVING,
);
#[derive(Clone, Copy)]
enum HandType {
MainHand,
OffHand,
}
fn perform_swing(
source: &CommandSource,
targets: &[Arc<dyn EntityBase>],
hand: HandType,
) -> CommandExecutorResult {
let mut living_count = 0;
let mut first_living = None;
for target in targets {
if let Some(living) = target.get_living_entity() {
match hand {
HandType::MainHand => living.swing_hand(),
HandType::OffHand => living.swing_off_hand(),
}
if first_living.is_none() {
first_living = Some(target);
}
living_count += 1;
}
}
if living_count == 0 {
return Err(ERROR_NO_LIVING_ENTITY.create_without_context());
}
let msg = if living_count == 1 {
let target = first_living.unwrap_or(&targets[0]);
TextComponent::translate_cross(
translation::java::COMMANDS_SWING_SUCCESS_SINGLE,
translation::java::COMMANDS_SWING_SUCCESS_SINGLE,
[target.get_display_name()],
)
} else {
TextComponent::translate_cross(
translation::java::COMMANDS_SWING_SUCCESS_MULTIPLE,
translation::java::COMMANDS_SWING_SUCCESS_MULTIPLE,
[TextComponent::text(living_count.to_string())],
)
};
source.send_feedback(msg, true);
Ok(living_count)
}
struct TargetsExecutor(HandType);
impl CommandExecutor for TargetsExecutor {
fn execute(&self, context: &CommandContext) -> CommandExecutorResult {
let targets = EntityArgumentType::get_entities(context, ARG_TARGETS)?;
perform_swing(context.source.as_ref(), &targets, self.0)
}
}
struct SelfExecutor;
impl CommandExecutor for SelfExecutor {
fn execute(&self, context: &CommandContext) -> CommandExecutorResult {
let target = context.source.entity_or_err()?;
perform_swing(context.source.as_ref(), &[target], HandType::MainHand)
}
}
pub fn register(dispatcher: &mut CommandDispatcher, registry: &PermissionRegistry) {
registry.register_permission_or_panic(Permission::new(
PERMISSION,
DESCRIPTION,
PermissionDefault::Op(PermissionLvl::Two),
));
dispatcher.register(
command("swing", DESCRIPTION)
.requires(PERMISSION)
.then(
argument(ARG_TARGETS, EntityArgumentType::Entities)
.executes(TargetsExecutor(HandType::MainHand))
.then(literal("mainhand").executes(TargetsExecutor(HandType::MainHand)))
.then(literal("offhand").executes(TargetsExecutor(HandType::OffHand))),
)
.executes(SelfExecutor),
);
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::Arc;
#[test]
fn parse_swing() {
let mut dispatcher = CommandDispatcher::new();
let registry = PermissionRegistry::default();
register(&mut dispatcher, &registry);
let source = Arc::new(CommandSource::dummy());
let result = dispatcher.parse_input("swing", &source);
assert!(result.errors.is_empty());
let result = dispatcher.parse_input("swing @e", &source);
assert!(result.errors.is_empty());
let result = dispatcher.parse_input("swing @e mainhand", &source);
assert!(result.errors.is_empty());
let result = dispatcher.parse_input("swing @e offhand", &source);
assert!(result.errors.is_empty());
}
}

View File

@ -15,7 +15,7 @@ serde = { version = "1.0", features = ["derive"] }
serde_repr = { version = "0.1" } serde_repr = { version = "0.1" }
serde_json = { version = "1.0", features = ["preserve_order"] } serde_json = { version = "1.0", features = ["preserve_order"] }
wit-encoder = "0.258" wit-encoder = "0.259"
semver = "1.0" semver = "1.0"
rayon = "1.12.0" rayon = "1.12.0"