142 lines
4.4 KiB
Rust
142 lines
4.4 KiB
Rust
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, ®istry);
|
|
|
|
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());
|
|
}
|
|
}
|