steel_core/command/builtins/
kill.rs1use std::slice;
4
5use steel_utils::{Identifier, translations};
6use text_components::TextComponent;
7
8use super::super::{
9 brigadier::{CommandNodeBuilder, CommandSyntaxError},
10 execution::{
11 CommandSource, SteelArgumentType, SteelCommandContext, SteelCommandRuntime, argument,
12 literal,
13 },
14 registration::CommandRegistration,
15};
16use crate::entity::SharedEntity;
17
18pub(super) fn registration() -> CommandRegistration<CommandSource> {
19 CommandRegistration::new(Identifier::vanilla_static("kill"), |_| command())
20}
21
22fn command() -> CommandNodeBuilder<CommandSource, SteelCommandRuntime> {
23 literal("kill")
24 .executes(kill_self)
25 .then(argument("targets", SteelArgumentType::entities()).executes(kill_targets))
26}
27
28fn kill_self(context: &SteelCommandContext<CommandSource>) -> Result<i32, CommandSyntaxError> {
29 let Some(entity) = context.source().entity() else {
30 return Err(CommandSyntaxError::dynamic(TextComponent::from(
31 &translations::PERMISSIONS_REQUIRES_ENTITY,
32 )));
33 };
34 kill_entities(context, slice::from_ref(entity))
35}
36
37fn kill_targets(context: &SteelCommandContext<CommandSource>) -> Result<i32, CommandSyntaxError> {
38 let targets = context.entities("targets")?;
39 kill_entities(context, &targets)
40}
41
42fn kill_entities(
43 context: &SteelCommandContext<CommandSource>,
44 targets: &[SharedEntity],
45) -> Result<i32, CommandSyntaxError> {
46 let Ok(result) = i32::try_from(targets.len()) else {
47 return Err(CommandSyntaxError::dynamic(
48 "Target count exceeds the command result range",
49 ));
50 };
51 for target in targets {
52 target.kill(context.source().world());
53 }
54
55 let message = if let [target] = targets {
56 translations::COMMANDS_KILL_SUCCESS_SINGLE
57 .message([TextComponent::plain(target.plain_text_name())])
58 .component()
59 } else {
60 translations::COMMANDS_KILL_SUCCESS_MULTIPLE
61 .message([TextComponent::plain(targets.len().to_string())])
62 .component()
63 };
64 context.source().send_success(&message, true);
65 Ok(result)
66}
67
68#[cfg(test)]
69mod tests {
70 use steel_registry::init_vanilla_registry;
71
72 use super::super::create_dispatcher;
73 use crate::command::execution::SteelArgumentType;
74
75 #[test]
76 fn kill_graph_supports_self_and_multiple_entity_targets() {
77 init_vanilla_registry();
78 let Ok(dispatcher) = create_dispatcher() else {
79 panic!("built-in commands should register");
80 };
81 let Some(kill) = dispatcher.children(dispatcher.root()).and_then(|children| {
82 children.iter().copied().find(|child| {
83 dispatcher
84 .node(*child)
85 .is_some_and(|node| node.name() == "kill")
86 })
87 }) else {
88 panic!("kill root should exist");
89 };
90 let Some(kill_node) = dispatcher.node(kill) else {
91 panic!("kill root node should exist");
92 };
93 assert!(kill_node.is_executable());
94
95 let Some(targets) = dispatcher
96 .children(kill)
97 .and_then(|children| children.first())
98 else {
99 panic!("kill targets should exist");
100 };
101 assert!(matches!(
102 dispatcher.node(*targets),
103 Some(node)
104 if node.is_executable()
105 && node.argument_type() == Some(&SteelArgumentType::entities())
106 ));
107 }
108}