#[cfg(target_os = "linux")]
#[path = "linux.rs"]
mod platform;
#[cfg(target_os = "windows")]
#[path = "windows.rs"]
mod platform;
use super::WeaponError;
use crate::Server;
use std::ffi::{CStr, c_char, c_void};
use std::ptr::NonNull;
struct Targets {
spawn: usize,
singleton: usize,
schema: usize,
schema_offset: usize,
definition: usize,
}
pub(super) unsafe fn spawn(
server: Server<'_>,
definition: u16,
origin: sys::Vector,
classname: Option<&CStr>,
) -> Result<NonNull<sys::CBaseEntity>, WeaponError> {
let targets = unsafe { platform::resolve(server.game_server_factory().as_raw() as usize) }
.ok_or(WeaponError::NativeUnavailable)?;
type Schema = unsafe extern "C" fn() -> *mut c_void;
type Definition = unsafe extern "C" fn(*mut c_void, i32) -> *mut c_void;
type Spawn = unsafe extern "C" fn(
*mut c_void,
i32,
*const sys::Vector,
*const sys::QAngle,
i32,
i32,
*const c_char,
) -> *mut sys::CBaseEntity;
let get_schema: Schema = unsafe { std::mem::transmute(targets.schema) };
let get_definition: Definition = unsafe { std::mem::transmute(targets.definition) };
let generate: Spawn = unsafe { std::mem::transmute(targets.spawn) };
let schema = unsafe { get_schema() };
if schema.is_null() {
return Err(WeaponError::NativeUnavailable);
}
let schema = unsafe { schema.byte_add(targets.schema_offset) };
let fallback = unsafe { get_definition(schema, -1) };
let item = unsafe { get_definition(schema, i32::from(definition)) };
if item.is_null() || item == fallback {
return Err(WeaponError::CreationFailed);
}
let angles = sys::QAngle {
x: 0.0,
y: 0.0,
z: 0.0,
};
let entity = unsafe {
generate(
targets.singleton as *mut c_void,
i32::from(definition),
&origin,
&angles,
1,
6,
classname.map_or(std::ptr::null(), CStr::as_ptr),
)
};
NonNull::new(entity).ok_or(WeaponError::CreationFailed)
}