Skip to content

Commit

Permalink
Sync commands (#7)
Browse files Browse the repository at this point in the history
* prototype synced commands

* clean up synced cmds

* uh where last changes?
  • Loading branch information
catornot authored Nov 28, 2023
1 parent 27b3899 commit afc92a3
Show file tree
Hide file tree
Showing 4 changed files with 168 additions and 147 deletions.
45 changes: 45 additions & 0 deletions src/console.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use std::sync::mpsc::Receiver;

use crate::rcon::MAX_CONTENT_SIZE;

pub struct ConsoleAccess {
console_recv: Receiver<String>,
cmd_buffer: Vec<String>,
}

impl ConsoleAccess {
pub fn new(recv: Receiver<String>) -> Self {
Self {
console_recv: recv,
cmd_buffer: Vec::new(),
}
}

pub fn next_line(&self) -> Option<String> {
self.console_recv.try_recv().ok()
}

pub fn next_line_catpure(&mut self) -> Option<String> {
if let Some(line) = self.next_line() {
let line_size = line.len();
let mut buffer_size = 0;

for bline in self.cmd_buffer.drain(..).rev().collect::<Vec<String>>() {
buffer_size += bline.len();
if buffer_size + line_size > MAX_CONTENT_SIZE {
break;
}

self.cmd_buffer.insert(0, bline);
}
self.cmd_buffer.push(line.clone());

return Some(line);
}
None
}

pub fn get_last_console_output(&self) -> &[String] {
&self.cmd_buffer
}
}
4 changes: 2 additions & 2 deletions src/console_hook.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ static_detour! {
pub fn hook_write_console() {
unsafe {
if !std::env::args().any(|arg| arg == "-dedicated") {
log::info!("this isn't a dedicated server; not hooking WriteConsoleA");
log::warn!("this isn't a dedicated server; not hooking WriteConsoleA");
return;
}

Expand All @@ -42,7 +42,7 @@ pub fn hook_write_console() {

pub fn hook_console_print(addr: isize) -> Option<()> {
unsafe {
if PLUGIN.wait().console_recv.try_lock().is_some() {
if PLUGIN.wait().server.is_none() {
log::warn!("rcon not running -> no Print hook");
return None;
}
Expand Down
101 changes: 29 additions & 72 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,118 +1,75 @@
use bindings::{CmdSource, EngineFunctions, ENGINE_FUNCTIONS};
use bindings::{EngineFunctions, ENGINE_FUNCTIONS};
use console_hook::{hook_console_print, hook_write_console};
use parking_lot::Mutex;
use rcon::{RconServer, RconTask};
use rrplug::{
bindings::class_types::client::CClient, mid::engine::WhichDll, prelude::*, to_c_string,
};
use rcon::RconServer;
use rrplug::{mid::engine::WhichDll, prelude::*};
use std::{
collections::HashMap,
env,
ffi::c_void,
sync::mpsc::{self, Receiver, Sender},
sync::mpsc::{self, Sender},
};

pub mod bindings;
pub mod console;
pub mod console_hook;
pub mod rcon;

const VALID_RCON_ARGS: [&str; 2] = ["rcon_ip_port", "rcon_password"];

#[derive(Debug)]
pub struct RconPlugin {
rcon_tasks: Mutex<Receiver<RconTask>>,
rcon_send_tasks: Mutex<Sender<RconTask>>, // mutex is not needed but it must sync so clone on each thread
console_sender: Mutex<Sender<String>>,
console_recv: Mutex<Receiver<String>>,
server: Option<Mutex<RconServer>>,
}

impl Plugin for RconPlugin {
fn new(_: &PluginData) -> Self {
let (sender, recv) = mpsc::channel();
let (console_sender, console_recv) = mpsc::channel();

let args = env::args()
let rcon_args = env::args()
.zip(env::args().skip(1))
.filter(|(cmd, _)| VALID_RCON_ARGS.contains(&&cmd[..]))
.fold(HashMap::new(), |mut hash_map, (cmd, arg)| {
_ = hash_map.insert(cmd, arg);
hash_map
});

std::thread::spawn(move || _ = run_rcon(args));
let mut server = None;

'start_server: {
let (Some(bind_ip), Some(password)) = (
rcon_args.get(VALID_RCON_ARGS[0]),
rcon_args.get(VALID_RCON_ARGS[1]),
) else {
log::error!("the rcon args that were provided are invalid!");
break 'start_server;
};

server = RconServer::try_new(&bind_ip, password, console_recv)
.map_err(|err| log::info!("failed to connect to socket : {err:?}"))
.map(|s| {
hook_write_console();
s
})
.ok();
}

Self {
rcon_tasks: Mutex::new(recv),
rcon_send_tasks: Mutex::new(sender),
console_sender: Mutex::new(console_sender),
console_recv: Mutex::new(console_recv),
server: server.map(|s| s.into()),
}
}

fn on_dll_load(&self, engine: Option<&EngineData>, dll_ptr: &DLLPointer) {
fn on_dll_load(&self, _: Option<&EngineData>, dll_ptr: &DLLPointer) {
unsafe { EngineFunctions::try_init(dll_ptr, &ENGINE_FUNCTIONS) };

if let WhichDll::Client = dll_ptr.which_dll() {
let addr = dll_ptr.get_dll_ptr() as isize;
std::thread::spawn(move || _ = hook_console_print(addr));
}

let engine = if let Some(engine) = engine {
engine
} else {
return;
};
}

fn runframe(&self) {
// can be moved somewhere else

let funcs = ENGINE_FUNCTIONS.wait();

if let Ok(task) = self.rcon_tasks.lock().try_recv() {
match task {
RconTask::Runcommand(cmd) => unsafe {
log::info!("executing command : {cmd}");

let cmd = to_c_string!(cmd);
(funcs.cbuf_add_text_type)(
(funcs.cbuf_get_current_player)(),
cmd.as_ptr(),
CmdSource::Code,
);
},
}
}
}
}

fn run_rcon(rcon_args: HashMap<String, String>) -> Option<std::convert::Infallible> {
let mut server = match RconServer::try_new(
rcon_args.get(VALID_RCON_ARGS[0])?,
rcon_args.get(VALID_RCON_ARGS[1])?.to_string(),
) {
Ok(sv) => sv,
Err(err) => {
log::info!("failed to connect to socket : {err:?}");
return None;
}
};

hook_write_console();

let rcon = PLUGIN.wait();

let rcon_send_tasks = rcon.rcon_send_tasks.lock();
let console_recv = rcon.console_recv.lock();

loop {
let new_console_line = console_recv.try_recv().ok();

if let Some(tasks) = server.run(new_console_line) {
tasks
.into_iter()
.for_each(|task| rcon_send_tasks.send(task).expect("failed to send tasks"))
}
_ = self.server.as_ref().map(|s| s.lock().run());
}
}

Expand Down
Loading

0 comments on commit afc92a3

Please sign in to comment.