use parking_lot::Mutex;
use std::{cell::UnsafeCell, marker::PhantomData};
pub mod concommands;
pub mod convars;
use crate::{
bindings::cvar::{
command::{CCommand, ConCommand},
convar::COMMAND_COMPLETION_ITEM_LENGTH,
RawCVar,
},
errors::RegisterError,
mid::engine::{
concommands::{RegisterConCommands, REGISTER_CONCOMNMADS},
convars::{CvarGlobals, CVAR_GLOBALS},
},
};
#[cfg(doc)]
use convars::ConVarStruct;
use super::UnsafeHandle;
#[doc(hidden)]
pub static CALLED_DLLS: Mutex<Vec<String>> = Mutex::new(Vec::new());
#[derive(Debug, Clone, Copy)]
pub struct EngineToken(PhantomData<*mut UnsafeCell<()>>);
impl EngineToken {
pub const unsafe fn new_unchecked() -> Self {
Self(PhantomData)
}
}
pub struct EngineGlobal<T>(UnsafeHandle<T>);
impl<T> EngineGlobal<T> {
pub const fn new(data: T) -> Self {
Self(UnsafeHandle { inner: data })
}
pub const fn get(&self, _: EngineToken) -> &T {
self.0.get()
}
pub fn get_mut(&mut self) -> &mut T {
self.0.get_mut()
}
pub fn take(self) -> T {
self.0.take()
}
}
impl<T: Copy> EngineGlobal<T> {
pub const fn copy(&self, _: EngineToken) -> T {
self.0.copy()
}
}
pub struct EngineData {
pub(crate) concommands: &'static RegisterConCommands,
pub(crate) convar: &'static CvarGlobals,
pub(crate) cvar: &'static RawCVar,
}
unsafe impl Send for EngineData {}
unsafe impl Sync for EngineData {}
impl EngineData {
pub unsafe fn new(cvar: &'static RawCVar) -> Self {
Self {
concommands: REGISTER_CONCOMNMADS.wait(),
convar: CVAR_GLOBALS.wait(),
cvar,
}
}
pub fn register_concommand(
&self,
name: impl AsRef<str>,
callback: unsafe extern "C" fn(arg1: *const CCommand),
help_string: impl AsRef<str>,
flags: i32,
_: EngineToken,
) -> Result<*mut ConCommand, RegisterError> {
let name = name.as_ref();
log::info!("Registering ConCommand {}", name);
self.concommands
.mid_register_concommand(name, callback, help_string.as_ref(), flags)
}
pub fn register_concommand_with_completion(
&self,
name: impl AsRef<str>,
callback: unsafe extern "C" fn(arg1: *const CCommand),
help_string: impl AsRef<str>,
flags: i32,
completion_callback: unsafe extern "C" fn(
arg1: *const ::std::os::raw::c_char,
arg2: *mut [::std::os::raw::c_char; COMMAND_COMPLETION_ITEM_LENGTH as usize],
) -> ::std::os::raw::c_int,
_: EngineToken,
) -> Result<*mut ConCommand, RegisterError> {
let name = name.as_ref();
log::info!("Registering ConCommand {} with completion", name);
self.concommands.mid_register_concommand_with_completion(
name,
callback,
help_string.as_ref(),
flags,
completion_callback,
)
}
pub fn register_convar(
&self,
name: impl Into<String>,
default_value: impl Into<String>,
help_string: &'static str,
flags: i32,
token: EngineToken,
) -> Result<(), RegisterError> {
use self::convars::{ConVarRegister, ConVarStruct};
ConVarStruct::try_new(
&ConVarRegister::new(name, default_value, flags, help_string),
token,
)
.map(|_| ())
}
}
#[cfg(doctest)]
#[allow(unused)]
mod doctest {
use super::*;
const fn test_engine_token() {}
}