use std::ffi::{c_char, c_int, c_void};
use std::mem::{offset_of, size_of};
pub type LevelInitCallback = unsafe extern "C" fn(context: *mut c_void, map: *const c_char);
pub type LevelShutdownCallback = unsafe extern "C" fn(context: *mut c_void);
const _: () = {
let slot = size_of::<*const ()>();
assert!(size_of::<PluginCallbacks>() == 6 * slot);
assert!(size_of::<PluginMetadata>() == 8 * slot);
assert!(offset_of!(PluginStatus, generation) == 0);
assert!(offset_of!(PluginStatus, id) == 8);
assert!(offset_of!(PluginStatus, loaded) == 12);
assert!(offset_of!(PluginStatus, paused) == 13);
assert!(size_of::<PluginStatus>() == 16);
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(transparent)]
pub struct HookStatus(pub c_int);
impl HookStatus {
pub const ALREADY_INSTALLED: Self = Self(2);
pub const INSTALLED: Self = Self(0);
pub const INVALID_ARGUMENT: Self = Self(3);
pub const NOT_BOUND: Self = Self(1);
pub const REFUSED: Self = Self(4);
pub const UNSUPPORTED: Self = Self(-1);
}
#[derive(Debug)]
#[repr(C)]
pub struct PluginCallbacks {
pub load: unsafe extern "C" fn(*mut c_void, *mut c_void, *mut c_char, usize, bool) -> bool,
pub all_plugins_loaded: unsafe extern "C" fn(*mut c_void),
pub query_running: unsafe extern "C" fn(*mut c_void, *mut c_char, usize) -> bool,
pub unload: unsafe extern "C" fn(*mut c_void, *mut c_char, usize) -> bool,
pub pause: unsafe extern "C" fn(*mut c_void, *mut c_char, usize) -> bool,
pub unpause: unsafe extern "C" fn(*mut c_void, *mut c_char, usize) -> bool,
}
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub struct PluginMetadata {
pub author: *const c_char,
pub name: *const c_char,
pub description: *const c_char,
pub url: *const c_char,
pub license: *const c_char,
pub version: *const c_char,
pub date: *const c_char,
pub log_tag: *const c_char,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(C)]
pub struct PluginStatus {
pub generation: u64,
pub id: c_int,
pub loaded: bool,
pub paused: bool,
}
impl PluginStatus {
pub const UNLOADED: Self = Self {
generation: 0,
id: 0,
loaded: false,
paused: false,
};
}
unsafe extern "C" {
fn cpp_metamod_listen_levels_dev(
init: Option<LevelInitCallback>,
shutdown: Option<LevelShutdownCallback>,
context: *mut c_void,
) -> c_int;
fn cpp_metamod_listen_levels_stable(
init: Option<LevelInitCallback>,
shutdown: Option<LevelShutdownCallback>,
context: *mut c_void,
) -> c_int;
fn cpp_metamod_plugin_dev(
callbacks: *const PluginCallbacks,
metadata: PluginMetadata,
) -> *mut c_void;
fn cpp_metamod_plugin_dev_instance() -> *mut c_void;
fn cpp_metamod_plugin_dev_is_loaded() -> bool;
fn cpp_metamod_plugin_dev_status() -> PluginStatus;
fn cpp_metamod_plugin_stable(
callbacks: *const PluginCallbacks,
metadata: PluginMetadata,
) -> *mut c_void;
fn cpp_metamod_plugin_stable_instance() -> *mut c_void;
fn cpp_metamod_plugin_stable_is_loaded() -> bool;
fn cpp_metamod_plugin_stable_status() -> PluginStatus;
}
pub unsafe fn cpp_metamod_listen_levels(
api_version: c_int,
init: Option<LevelInitCallback>,
shutdown: Option<LevelShutdownCallback>,
context: *mut c_void,
) -> HookStatus {
HookStatus(match api_version {
16 => unsafe { cpp_metamod_listen_levels_stable(init, shutdown, context) },
18 => unsafe { cpp_metamod_listen_levels_dev(init, shutdown, context) },
_ => return HookStatus::UNSUPPORTED,
})
}
pub unsafe fn cpp_metamod_plugin(
api_version: c_int,
callbacks: *const PluginCallbacks,
metadata: PluginMetadata,
) -> *mut c_void {
match api_version {
16 => unsafe { cpp_metamod_plugin_stable(callbacks, metadata) },
18 => unsafe { cpp_metamod_plugin_dev(callbacks, metadata) },
_ => std::ptr::null_mut(),
}
}
pub fn cpp_metamod_plugin_for_version(api_version: c_int) -> *mut c_void {
match api_version {
16 => unsafe { cpp_metamod_plugin_stable_instance() },
18 => unsafe { cpp_metamod_plugin_dev_instance() },
_ => std::ptr::null_mut(),
}
}
pub fn cpp_metamod_plugin_is_loaded(api_version: c_int) -> bool {
match api_version {
16 => unsafe { cpp_metamod_plugin_stable_is_loaded() },
18 => unsafe { cpp_metamod_plugin_dev_is_loaded() },
_ => false,
}
}
pub fn cpp_metamod_plugin_status(api_version: c_int) -> PluginStatus {
match api_version {
16 => unsafe { cpp_metamod_plugin_stable_status() },
18 => unsafe { cpp_metamod_plugin_dev_status() },
_ => PluginStatus::UNLOADED,
}
}