JaneDoe-ZS/nap_gameserver/src/commands/mod.rs
xeon 9af61cd33f simple CLI command system
Implement CLI command system
command for changing player's frontend avatar
2024-07-22 19:47:04 +03:00

83 lines
2.4 KiB
Rust

use std::io::Write;
use std::sync::Arc;
use rustyline_async::{Readline, ReadlineEvent, SharedWriter};
use crate::ServerState;
mod player;
pub struct CommandManager {
state: Arc<ServerState>,
}
macro_rules! commands {
($($category:ident::$action:ident $usage:tt $desc:tt;)*) => {
async fn exec(state: &ServerState, cmd: &str) -> String {
let input = cmd.split(" ").collect::<Vec<&str>>();
if input.len() == 1 && *input.get(0).unwrap() == "help" {
return Self::help_message();
}
let (Some(category), Some(action)) = (input.get(0), input.get(1)) else {
return String::new();
};
let args = &input[2..];
match match (*category, *action) {
$(
(stringify!($category), stringify!($action)) => {
$category::$action(args, state).await
}
)*,
_ => {
::tracing::info!("unknown command");
return Self::help_message();
}
} {
Ok(s) => s,
Err(err) => format!("failed to execute command: {err}"),
}
}
fn help_message() -> String {
concat!("available commands:\n",
$(stringify!($category), " ", stringify!($action), " ", $usage, " - ", $desc, "\n",)*
"help - shows this message"
).to_string()
}
};
}
impl CommandManager {
pub fn new(state: Arc<ServerState>) -> Self {
Self { state }
}
pub async fn run(&self, mut rl: Readline, mut out: SharedWriter) {
loop {
match rl.readline().await {
Ok(ReadlineEvent::Line(line)) => {
let str = Self::exec(&self.state, &line).await;
writeln!(&mut out, "{str}").unwrap();
rl.add_history_entry(line);
}
Ok(ReadlineEvent::Eof) | Ok(ReadlineEvent::Interrupted) => {
rl.flush().unwrap();
drop(rl);
// TODO: maybe disconnect and save all players
std::process::exit(0);
}
_ => continue,
}
}
}
commands! {
player::avatar "[player_uid] [avatar_id]" "changes player avatar for main city";
}
}