steel_core/command/
mod.rs1mod api;
4pub(crate) mod brigadier;
5mod builtins;
6pub(crate) mod execution;
7mod protocol;
8mod queue;
9mod registration;
10pub mod sender;
11pub(crate) mod storage;
12
13pub use api::{
14 CommandArgument, CommandArgumentParser, CommandContext, CommandError, CommandNode,
15 CommandParserSource, CommandReader, CommandReaderCursor, CommandRegistration,
16 CommandRegistrationError, CommandRegistry, CommandSource, CommandSuggestionContext,
17 CommandSuggestions, SuspendedCommand, SuspendedCommandPoll, argument, literal,
18};
19pub use execution::CommandSuspensionOrder;
20
21pub(crate) use builtins::{
22 create_registered_dispatcher, gamemode::handle_client_request, player_can_change_difficulty,
23};
24pub(crate) use protocol::{command_suggestions_packet, command_tree_packet};
25pub use queue::CommandQueueFull;
26pub(crate) use queue::{
27 COMMAND_REQUESTS_PER_TICK, COMMAND_RESUMPTIONS_PER_TICK, CommandRequest, CommandRequestQueue,
28 PendingCommandExecutionQueue,
29};
30
31use steel_utils::entity_events::EntityStatus;
32
33use self::{
34 brigadier::CommandDispatcher as BrigadierCommandDispatcher,
35 execution::{CommandSource as InternalCommandSource, SteelCommandRuntime},
36};
37use crate::command::brigadier::CommandSyntaxError;
38use crate::{player::Player, world::World};
39
40pub(crate) type CommandDispatcher =
41 BrigadierCommandDispatcher<InternalCommandSource, SteelCommandRuntime>;
42
43#[derive(Clone, Debug, PartialEq, Eq)]
45pub struct CommandCompletion {
46 replacement_start: usize,
47 replacement_length: usize,
48 text: String,
49}
50
51impl CommandCompletion {
52 pub(crate) const fn new(
53 replacement_start: usize,
54 replacement_length: usize,
55 text: String,
56 ) -> Self {
57 Self {
58 replacement_start,
59 replacement_length,
60 text,
61 }
62 }
63
64 #[must_use]
66 pub const fn replacement_start(&self) -> usize {
67 self.replacement_start
68 }
69
70 #[must_use]
72 pub const fn replacement_length(&self) -> usize {
73 self.replacement_length
74 }
75
76 #[must_use]
78 pub fn text(&self) -> &str {
79 &self.text
80 }
81}
82
83pub(crate) fn client_permission_event(player: &Player, world: &World) -> EntityStatus {
86 client_permission_event_for_capabilities(
87 builtins::gamemode::player_can_use_client_switcher(player, world),
88 builtins::player_can_change_difficulty(player, world),
89 )
90}
91
92const fn client_permission_event_for_capabilities(
93 can_change_game_mode: bool,
94 can_change_difficulty: bool,
95) -> EntityStatus {
96 if can_change_game_mode || can_change_difficulty {
97 EntityStatus::PermissionLevelGamemasters
98 } else {
99 EntityStatus::PermissionLevelAll
100 }
101}
102
103pub(crate) fn missing_argument(name: &str) -> CommandSyntaxError {
105 CommandSyntaxError::dynamic(format!(
106 "Parsed value for {name} is missing from the command context"
107 ))
108}
109
110pub(crate) fn incorrectly_typed_argument(name: &str) -> CommandSyntaxError {
113 CommandSyntaxError::dynamic(format!(
114 "Parsed value for {name} does not match the expected type"
115 ))
116}
117
118#[cfg(test)]
119mod tests {
120 use super::client_permission_event_for_capabilities;
121 use steel_utils::entity_events::EntityStatus;
122
123 #[test]
124 fn gamemaster_projection_enables_either_supported_client_capability() {
125 assert_eq!(
126 client_permission_event_for_capabilities(true, false),
127 EntityStatus::PermissionLevelGamemasters
128 );
129 assert_eq!(
130 client_permission_event_for_capabilities(false, true),
131 EntityStatus::PermissionLevelGamemasters
132 );
133 assert_eq!(
134 client_permission_event_for_capabilities(false, false),
135 EntityStatus::PermissionLevelAll
136 );
137 }
138}