Skip to content

Commit

Permalink
Merge pull request #54 from Jupeyy/pr_exec_client
Browse files Browse the repository at this point in the history
Add basic `exec` & `echo` commands to the client
  • Loading branch information
Jupeyy authored Jan 9, 2025
2 parents 89fb1e4 + 95e0f27 commit 4e8ce51
Show file tree
Hide file tree
Showing 5 changed files with 201 additions and 62 deletions.
69 changes: 60 additions & 9 deletions game/client-console/src/console/local_console.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::{
collections::HashMap,
net::{SocketAddr, ToSocketAddrs},
ops::Range,
path::PathBuf,
rc::Rc,
};

Expand Down Expand Up @@ -46,6 +47,12 @@ pub enum LocalConsoleEvent {
// The bind was added to the player's profile
was_player_profile: bool,
},
Exec {
file_path: PathBuf,
},
Echo {
text: String,
},
/// Switch to an dummy or the main player
ChangeDummy {
dummy_index: Option<usize>,
Expand Down Expand Up @@ -84,13 +91,17 @@ impl super::console::ConsoleEvents<LocalConsoleEvent> for LocalConsoleEvents {
}
}

pub type LocalConsole = ConsoleRender<LocalConsoleEvent, ()>;
pub type LocalConsole = ConsoleRender<LocalConsoleEvent, Rc<RefCell<ParserCache>>>;

#[derive(Debug, Default)]
pub struct LocalConsoleBuilder {}

impl LocalConsoleBuilder {
fn register_commands(console_events: LocalConsoleEvents, list: &mut Vec<ConsoleEntry>) {
fn register_commands(
console_events: LocalConsoleEvents,
list: &mut Vec<ConsoleEntry>,
parser_cache: Rc<RefCell<ParserCache>>,
) {
list.push(ConsoleEntry::Cmd(ConsoleEntryCmd {
name: "push".into(),
usage: "push <var>".into(),
Expand Down Expand Up @@ -517,8 +528,7 @@ impl LocalConsoleBuilder {
}
// bind for player
let events = console_events.clone();
let cache_shared = Rc::new(RefCell::new(ParserCache::default()));
let cache = cache_shared.clone();
let cache = parser_cache.clone();
let keys_arg_cmd = keys_arg.clone();
list.push(ConsoleEntry::Cmd(ConsoleEntryCmd {
name: "bind".into(),
Expand Down Expand Up @@ -550,7 +560,7 @@ impl LocalConsoleBuilder {
let actions_map = gen_local_player_action_hash_map();
let actions_map_rev = gen_local_player_action_hash_map_rev();
let events = console_events.clone();
let cache = cache_shared.clone();
let cache = parser_cache.clone();
let keys_arg_cmd = keys_arg.clone();
list.push(ConsoleEntry::Cmd(ConsoleEntryCmd {
name: "bind_dummy".into(),
Expand Down Expand Up @@ -582,7 +592,7 @@ impl LocalConsoleBuilder {

let keys_arg_cmd = keys_arg.clone();
// unbind for player
let cache = cache_shared.clone();
let cache = parser_cache.clone();
let events = console_events.clone();
list.push(ConsoleEntry::Cmd(ConsoleEntryCmd {
name: "unbind".into(),
Expand All @@ -604,7 +614,7 @@ impl LocalConsoleBuilder {
allows_partial_cmds: false,
}));
let keys_arg_cmd = keys_arg.clone();
let cache = cache_shared.clone();
let cache = parser_cache.clone();
let events = console_events.clone();
list.push(ConsoleEntry::Cmd(ConsoleEntryCmd {
name: "unbind_dummy".into(),
Expand All @@ -627,6 +637,46 @@ impl LocalConsoleBuilder {
allows_partial_cmds: false,
}));

let console_events_cmd = console_events.clone();
list.push(ConsoleEntry::Cmd(ConsoleEntryCmd {
name: "exec".into(),
usage: "exec <file_path>".into(),
description: "Executes a file of command lines.".into(),
cmd: Rc::new(move |_, _, path| {
let Syn::Text(file_path_str) = &path[0].0 else {
panic!("Command parser returned a non requested command arg");
};
let file_path: PathBuf = file_path_str.into();
console_events_cmd.push(LocalConsoleEvent::Exec { file_path });
Ok("".into())
}),
args: vec![CommandArg {
ty: CommandArgType::Text,
user_ty: None,
}],
allows_partial_cmds: false,
}));

let console_events_cmd = console_events.clone();
list.push(ConsoleEntry::Cmd(ConsoleEntryCmd {
name: "echo".into(),
usage: "echo <text>".into(),
description: "Echos text to the console and a client component.".into(),
cmd: Rc::new(move |_, _, path| {
let Syn::Text(text) = &path[0].0 else {
panic!("Command parser returned a non requested command arg");
};

console_events_cmd.push(LocalConsoleEvent::Echo { text: text.clone() });
Ok(format!("Echo: {text}"))
}),
args: vec![CommandArg {
ty: CommandArgType::Text,
user_ty: None,
}],
allows_partial_cmds: false,
}));

let console_events_cmd = console_events.clone();
list.push(ConsoleEntry::Cmd(ConsoleEntryCmd {
name: "connect".into(),
Expand Down Expand Up @@ -754,13 +804,14 @@ impl LocalConsoleBuilder {
"".into(),
Default::default(),
);
Self::register_commands(console_events.clone(), &mut entries);
let parser_cache = Rc::new(RefCell::new(ParserCache::default()));
Self::register_commands(console_events.clone(), &mut entries, parser_cache.clone());
ConsoleRender::new(
creator,
entries,
Box::new(console_events),
Color32::from_rgba_unmultiplied(0, 0, 0, 150),
(),
parser_cache,
)
}
}
51 changes: 25 additions & 26 deletions game/client-ui/src/console/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -498,14 +498,14 @@ pub fn try_apply_config_val(
})
}

/// Returns `false` if the command was considered partially or fully failed.
pub fn run_command(
cmd: CommandTypeRef<'_>,
entries: &[ConsoleEntry],
config_engine: &mut ConfigEngine,
config_game: &mut ConfigGame,
msgs: &mut String,
can_change_config: bool,
) {
) -> anyhow::Result<String, String> {
if let Some(entry_cmd) = entries
.iter()
.filter_map(|e| match e {
Expand All @@ -528,14 +528,8 @@ pub fn run_command(
{
let cmd = cmd.unwrap_full_or_partial_cmd_ref();
match (entry_cmd.cmd)(config_engine, config_game, &cmd.args) {
Ok(msg) => {
if !msg.is_empty() {
msgs.push_str(&format!("{msg}\n"));
}
}
Err(err) => {
msgs.push_str(&format!("Parsing error: {}\n", err));
}
Ok(msg) => Ok(msg),
Err(err) => Err(format!("Parsing error: {}\n", err)),
}
} else {
let Some((args, cmd_text)) = (match cmd {
Expand All @@ -548,7 +542,7 @@ pub fn run_command(
}
}
}) else {
return;
return Err(format!("Invalid argument: {:?}", cmd));
};

let set_val = syn_vec_to_config_val(&args);
Expand All @@ -557,10 +551,6 @@ pub fn run_command(
match try_apply_config_val(cmd_text, &args, config_engine, config_game) {
Ok(cur_val) => {
if set_val.is_some() {
msgs.push_str(&format!(
"Updated value for \"{}\": {}\n",
cmd_text, cur_val
));
if let Some(var) = entries
.iter()
.filter_map(|cmd| {
Expand All @@ -574,37 +564,46 @@ pub fn run_command(
{
(var.on_set)(cmd_text);
}
Ok(format!("Updated value for \"{}\": {}\n", cmd_text, cur_val))
} else {
msgs.push_str(&format!(
"Current value for \"{}\": {}\n",
cmd_text, cur_val
));
Ok(format!("Current value for \"{}\": {}\n", cmd_text, cur_val))
}
}
Err(err) => {
msgs.push_str(&err);
}
Err(err) => Err(err),
}
} else {
Err(format!("Failed to apply command: {:?}", cmd))
}
}
}

/// Returns `false` if at least one command failed.
pub fn run_commands(
cmds: &CommandsTyped,
entries: &[ConsoleEntry],
config_engine: &mut ConfigEngine,
config_game: &mut ConfigGame,
msgs: &mut String,
can_change_config: bool,
) {
) -> bool {
let mut res = true;
for cmd in cmds {
run_command(
let msg = match run_command(
cmd.as_ref(),
entries,
config_engine,
config_game,
msgs,
can_change_config,
);
) {
Ok(msg) => msg,
Err(msg) => {
res = false;
msg
}
};
if !msg.is_empty() {
msgs.push_str(&format!("{msg}\n"));
}
}
res
}
2 changes: 1 addition & 1 deletion game/game-server/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,7 @@ impl Server {
) -> ReponsesAndCmds {
let mut remaining_cmds = Vec::default();
let mut responses = Vec::default();
for line in lines {
for line in lines.into_iter().filter(|l| !l.is_empty()) {
let cmds =
command_parser::parser::parse(&line, &rcon_chain.parser, &mut Default::default());

Expand Down
Loading

0 comments on commit 4e8ce51

Please sign in to comment.