use crate::raw::types::AMX;
use super::events::PawnEventHandler;
use super::types::UID;
pub const NUM_AMX_FUNCS: usize = 52;
pub const PAWN_COMPONENT_UID: UID = 0x7890_6cd9_f19c_36a6;
#[repr(C)]
pub struct ServerComponentList {
vtable: *const ServerComponentListVTable,
}
#[cfg(not(target_env = "msvc"))]
type QueryComponentFn = unsafe extern "C" fn(*mut ServerComponentList, UID) -> *mut ServerComponent;
#[cfg(target_env = "msvc")]
type QueryComponentFn =
unsafe extern "thiscall" fn(*mut ServerComponentList, UID) -> *mut ServerComponent;
#[cfg(not(target_env = "msvc"))]
const COMPONENT_LIST_PREFIX_SLOTS: usize = 6;
#[cfg(target_env = "msvc")]
const COMPONENT_LIST_PREFIX_SLOTS: usize = 5;
#[repr(C)]
struct ServerComponentListVTable {
_prefix: [*const (); COMPONENT_LIST_PREFIX_SLOTS],
query_component: QueryComponentFn,
}
#[repr(C)]
pub struct ServerComponent {
vtable: *const (),
}
pub unsafe fn query_component(list: *mut ServerComponentList, uid: UID) -> *mut ServerComponent {
unsafe { ((*(*list).vtable).query_component)(list, uid) }
}
#[repr(C)]
pub struct ServerPawnComponent {
vtable: *const ServerPawnComponentVTable,
_uid_vtable: *const (),
}
#[cfg(not(target_env = "msvc"))]
type GetEventDispatcherFn =
unsafe extern "C" fn(*mut ServerPawnComponent) -> *mut IEventDispatcherPawn;
#[cfg(target_env = "msvc")]
type GetEventDispatcherFn =
unsafe extern "thiscall" fn(*mut ServerPawnComponent) -> *mut IEventDispatcherPawn;
#[cfg(not(target_env = "msvc"))]
type GetAmxFunctionsFn =
unsafe extern "C" fn(*const ServerPawnComponent) -> *const AmxFunctionTable;
#[cfg(target_env = "msvc")]
type GetAmxFunctionsFn =
unsafe extern "thiscall" fn(*const ServerPawnComponent) -> *const AmxFunctionTable;
#[cfg(not(target_env = "msvc"))]
const PAWN_COMPONENT_PREFIX_SLOTS: usize = 18;
#[cfg(target_env = "msvc")]
const PAWN_COMPONENT_PREFIX_SLOTS: usize = 16;
#[repr(C)]
struct ServerPawnComponentVTable {
_prefix: [*const (); PAWN_COMPONENT_PREFIX_SLOTS],
get_event_dispatcher: GetEventDispatcherFn,
get_amx_functions: GetAmxFunctionsFn,
_get_script_const: *const (),
_get_script_mut: *const (),
_main_script: *const (),
_side_scripts: *const (),
}
pub type AmxFunctionTable = [*mut (); NUM_AMX_FUNCS];
#[repr(C)]
pub struct IPawnScript {
vtable: *const IPawnScriptVTable,
}
#[cfg(not(target_env = "msvc"))]
type GetAmxFn = unsafe extern "C" fn(*mut IPawnScript) -> *mut AMX;
#[cfg(target_env = "msvc")]
type GetAmxFn = unsafe extern "thiscall" fn(*mut IPawnScript) -> *mut AMX;
#[repr(C)]
struct IPawnScriptVTable {
_prefix: [*const (); 57],
get_amx: GetAmxFn,
}
pub unsafe fn get_amx_from_script(script: *mut IPawnScript) -> *mut AMX {
unsafe { ((*(*script).vtable).get_amx)(script) }
}
#[repr(C)]
pub struct IEventDispatcherPawn {
vtable: *const IEventDispatcherPawnVTable,
}
#[cfg(not(target_env = "msvc"))]
type AddEventHandlerFn =
unsafe extern "C" fn(*mut IEventDispatcherPawn, *mut PawnEventHandler, i8) -> bool;
#[cfg(target_env = "msvc")]
type AddEventHandlerFn =
unsafe extern "thiscall" fn(*mut IEventDispatcherPawn, *mut PawnEventHandler, i8) -> bool;
#[cfg(not(target_env = "msvc"))]
type RemoveEventHandlerFn =
unsafe extern "C" fn(*mut IEventDispatcherPawn, *mut PawnEventHandler) -> bool;
#[cfg(target_env = "msvc")]
type RemoveEventHandlerFn =
unsafe extern "thiscall" fn(*mut IEventDispatcherPawn, *mut PawnEventHandler) -> bool;
#[repr(C)]
struct IEventDispatcherPawnVTable {
add_event_handler: AddEventHandlerFn,
remove_event_handler: RemoveEventHandlerFn,
_has_event_handler: *const (),
_count: *const (),
}
pub unsafe fn add_pawn_event_handler(
dispatcher: *mut IEventDispatcherPawn,
handler: *mut PawnEventHandler,
) {
unsafe { ((*(*dispatcher).vtable).add_event_handler)(dispatcher, handler, 0) };
}
pub unsafe fn remove_pawn_event_handler(
dispatcher: *mut IEventDispatcherPawn,
handler: *mut PawnEventHandler,
) {
unsafe { ((*(*dispatcher).vtable).remove_event_handler)(dispatcher, handler) };
}
pub unsafe fn get_pawn_event_dispatcher(pawn: *mut ServerComponent) -> *mut IEventDispatcherPawn {
let pawn = pawn.cast::<ServerPawnComponent>();
unsafe { ((*(*pawn).vtable).get_event_dispatcher)(pawn) }
}
pub unsafe fn get_amx_functions(pawn: *mut ServerComponent) -> usize {
let pawn = pawn as *const ServerPawnComponent;
let table_ptr = unsafe { ((*(*pawn).vtable).get_amx_functions)(pawn) };
table_ptr as usize
}
use super::component_api::OmpComponentHandle;
use std::ptr::NonNull;
#[derive(Debug, Clone, Copy)]
pub struct PawnComponent {
ptr: NonNull<ServerComponent>,
}
impl OmpComponentHandle for PawnComponent {
const UID: UID = PAWN_COMPONENT_UID;
unsafe fn from_raw(ptr: NonNull<ServerComponent>) -> Self {
Self { ptr }
}
fn as_raw(&self) -> NonNull<ServerComponent> {
self.ptr
}
}
impl PawnComponent {
#[must_use]
pub fn name(&self) -> Option<String> {
super::component_api::component_name(self)
}
#[must_use]
pub fn version(&self) -> Option<super::types::SemanticVersion> {
super::component_api::component_version(self)
}
#[must_use]
pub fn event_dispatcher(&self) -> *mut IEventDispatcherPawn {
unsafe { get_pawn_event_dispatcher(self.ptr.as_ptr()) }
}
#[must_use]
pub fn amx_functions(&self) -> usize {
unsafe { get_amx_functions(self.ptr.as_ptr()) }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn pawn_component_uid_is_nonzero() {
assert_ne!(PAWN_COMPONENT_UID, 0);
}
#[test]
fn pawn_component_uid_matches_known_value() {
assert_eq!(PAWN_COMPONENT_UID, 0x7890_6cd9_f19c_36a6);
}
#[test]
fn num_amx_funcs_is_52() {
assert_eq!(NUM_AMX_FUNCS, 52);
}
#[test]
fn pawn_component_uid_via_trait_matches_constant() {
assert_eq!(
<PawnComponent as OmpComponentHandle>::UID,
PAWN_COMPONENT_UID
);
}
#[test]
fn pawn_component_is_copy() {
fn assert_copy<T: Copy>() {}
assert_copy::<PawnComponent>();
}
#[test]
fn pawn_component_size_is_one_pointer() {
assert_eq!(
std::mem::size_of::<PawnComponent>(),
std::mem::size_of::<*const ()>()
);
}
}