1use std::fmt::
20{
21 Display,
22 Formatter,
23 Result,
24};
25
26use crate::network::MessageCode;
27
28#[cfg(feature = "client")]
29use std::net::TcpStream;
30
31#[cfg(feature = "client")]
32use crate::
33{
34 options,
35 network::{ self, MessagePacket },
36};
37
38#[derive(Clone, PartialEq)]
40pub enum Command
41{
42 Exit, Voice, Channel, Help, List, PrivateMessage, UsernameColor, MessageColor, Invalid, }
52
53pub struct CommandArg {
56 pub name: &'static str,
57 pub required: bool,
58}
59
60pub struct CommandInfo {
62 pub command: Command,
63 pub triggers: &'static [&'static str],
64 pub args: &'static [CommandArg],
65 pub description: &'static str,
66}
67
68pub const COMMAND_LIST: &[CommandInfo] =
69&[
70 CommandInfo
71 {
72 command: Command::Help,
73 triggers: &[ "HELP", "H", "COMMANDS", "USAGE", "GUIDE" ],
74 args: &[],
75 description: "Prints all available commands",
76 },
77
78 CommandInfo
79 {
80 command: Command::Voice,
81 triggers: &[ "VOICE", "VOIP", "CALL" ],
82 args: &[],
83 description: "Toggles voice chat",
84 },
85
86 CommandInfo
87 {
88 command: Command::Channel,
89 triggers: &[ "CHANNEL", "SWITCH", "CHECKOUT", "AREA" ],
90 args: &[CommandArg { name: "NAME", required: false }],
91 description: "Switches to channel/lobby if NAME is omitted",
92 },
93
94 CommandInfo
95 {
96 command: Command::List,
97 triggers: &[ "LIST", "USERS", "CLIENTS", "CHANNELS", "IDS", "ID" ],
98 args: &[],
99 description: "Shows connected users and their IDs",
100 },
101
102 CommandInfo
103 {
104 command: Command::PrivateMessage,
105 triggers: &[ "PM", "DM", "MSG", "TELL" ],
106 args:
107 &[
108 CommandArg { name: "ID", required: true },
109 CommandArg { name: "MESSAGE", required: true },
110 ],
111 description: "Sends private message",
112 },
113
114 CommandInfo
115 {
116 command: Command::UsernameColor,
117 triggers: &[ "UCOLOR", "USERNAME" ],
118 args: &[CommandArg { name: "COLOR", required: true }],
119 description: "Sets color of username",
120 },
121
122 CommandInfo
123 {
124 command: Command::MessageColor,
125 triggers: &[ "COLOR", "MESSAGE" ],
126 args: &[CommandArg { name: "COLOR", required: true }],
127 description: "Sets color of message",
128 },
129
130 CommandInfo
131 {
132 command: Command::Exit,
133 triggers: &[ "EXIT", "LEAVE", "QUIT", "DISCONNECT" ],
134 args: &[],
135 description: "Disconnects from the server",
136 },
137];
138
139pub const COMMAND_PREFIX: &str = "/"; impl Command
144{
145 pub fn to_code(&self) -> Option<MessageCode>
147 {
148 match self
149 {
150 Command::Exit => Some(MessageCode::Disconnect),
151 Command::Voice => Some(MessageCode::Voice),
152 Command::Channel => Some(MessageCode::Channel),
153 Command::List => Some(MessageCode::List),
154 Command::PrivateMessage => Some(MessageCode::PrivateMessage),
155
156 _ => None,
157 }
158 }
159}
160
161impl Display for Command
162{
163 fn fmt(&self, f: &mut Formatter<'_>) -> Result
165 {
166 let name = COMMAND_LIST.iter()
167 .find(|info| info.command == *self)
168 .map(|info| info.triggers[0].to_lowercase())
169 .unwrap_or(String::new()); write!(f, "{}{}", COMMAND_PREFIX, name)
172 }
173}
174
175pub fn get_command(input: &str) -> (Option<Command>, Option<String>) {
177 if !input.starts_with(COMMAND_PREFIX) { return (None, None); }
179
180 let no_prefix = &input[COMMAND_PREFIX.len()..]; let (command, parameters) = match no_prefix.split_once(' ') {
184 Some((command, parameters)) => (command.to_ascii_uppercase(), Some(parameters.trim().to_string())),
185 None => (no_prefix.to_ascii_uppercase(), None)
186 };
187
188 for info in COMMAND_LIST
190 {
191 if info.triggers.contains(&command.as_str())
192 {
193 return (Some(info.command.clone()), parameters);
194 }
195 }
196
197 (Some(Command::Invalid), None)
198}
199
200#[cfg(feature = "client")]
201pub fn send_command_code(stream: &mut TcpStream, command: &Command, parameters: &Option<String>) -> bool {
203 if let Some(code) = command.to_code()
205 {
206 network::send(stream, MessagePacket
207 {
208 text: parameters.clone(),
209 code: Some(code),
210 ..Default::default()
211 }, options::get_keys().as_ref());
212 true
213 } else { false }
214}