Skip to main content

steel_core/command/builtins/
stopsound.rs

1use std::sync::Arc;
2
3use steel_protocol::packets::game::{CStopSound, SoundSource};
4use steel_utils::{Identifier, translations};
5use text_components::TextComponent;
6
7use super::super::{
8    brigadier::{CommandNodeBuilder, CommandSyntaxError},
9    execution::{
10        CommandSource, SteelArgumentType, SteelCommandContext, SteelCommandRuntime, argument,
11        literal,
12    },
13    registration::CommandRegistration,
14};
15
16use crate::player::Player;
17
18pub(super) fn registration() -> CommandRegistration<CommandSource> {
19    CommandRegistration::new(Identifier::vanilla_static("stopsound"), |_| command())
20}
21
22fn command() -> CommandNodeBuilder<CommandSource, SteelCommandRuntime> {
23    let mut targets =
24        argument("targets", SteelArgumentType::players()).executes(stop_all_for_targets);
25
26    for source in SoundSource::VALUES {
27        targets = targets.then(source_command(source));
28    }
29
30    targets = targets.then(
31        literal("*")
32            .then(argument("sound", SteelArgumentType::sound()).executes(stop_sound_any_source)),
33    );
34
35    literal("stopsound").then(targets)
36}
37
38fn source_command(source: SoundSource) -> CommandNodeBuilder<CommandSource, SteelCommandRuntime> {
39    literal(source.name())
40        .executes(move |context| stop_all_for_targets_with_source(context, source))
41        .then(
42            argument("sound", SteelArgumentType::sound())
43                .executes(move |context| stop_sound(context, source)),
44        )
45}
46
47fn stop_all_for_targets(
48    context: &SteelCommandContext<CommandSource>,
49) -> Result<i32, CommandSyntaxError> {
50    let targets = context.players("targets")?;
51
52    execute(None, None, &targets);
53
54    context.source().send_success(
55        &TextComponent::from(&translations::COMMANDS_STOPSOUND_SUCCESS_SOURCELESS_ANY),
56        true,
57    );
58
59    target_count(&targets)
60}
61
62fn stop_all_for_targets_with_source(
63    context: &SteelCommandContext<CommandSource>,
64    source: SoundSource,
65) -> Result<i32, CommandSyntaxError> {
66    let targets = context.players("targets")?;
67
68    execute(Some(source), None, &targets);
69
70    let message = translations::COMMANDS_STOPSOUND_SUCCESS_SOURCE_ANY
71        .message([TextComponent::plain(source.name())])
72        .component();
73
74    context.source().send_success(&message, true);
75
76    target_count(&targets)
77}
78
79fn stop_sound_any_source(
80    context: &SteelCommandContext<CommandSource>,
81) -> Result<i32, CommandSyntaxError> {
82    let targets = context.players("targets")?;
83    let sound = context.identifier("sound")?.clone();
84
85    execute(None, Some(&sound), &targets);
86
87    let message = translations::COMMANDS_STOPSOUND_SUCCESS_SOURCELESS_SOUND
88        .message([TextComponent::plain(sound.to_string())])
89        .component();
90
91    context.source().send_success(&message, true);
92
93    target_count(&targets)
94}
95
96fn stop_sound(
97    context: &SteelCommandContext<CommandSource>,
98    source: SoundSource,
99) -> Result<i32, CommandSyntaxError> {
100    let targets = context.players("targets")?;
101    let sound = context.identifier("sound")?.clone();
102
103    execute(Some(source), Some(&sound), &targets);
104
105    let message = translations::COMMANDS_STOPSOUND_SUCCESS_SOURCE_SOUND
106        .message([
107            TextComponent::plain(sound.to_string()),
108            TextComponent::plain(source.name()),
109        ])
110        .component();
111
112    context.source().send_success(&message, true);
113
114    target_count(&targets)
115}
116
117fn execute(source: Option<SoundSource>, sound: Option<&Identifier>, targets: &[Arc<Player>]) {
118    for target in targets {
119        target.send_packet(CStopSound::new(source, sound.cloned()));
120    }
121}
122
123fn target_count(targets: &[Arc<Player>]) -> Result<i32, CommandSyntaxError> {
124    i32::try_from(targets.len()).map_err(|_| {
125        CommandSyntaxError::dynamic("Target player count exceeds the command result range")
126    })
127}