use samp_sdk::amx::Amx;
use samp_sdk::error::{AmxError, AmxResult};
use samp_sdk::exports::{
Export, Exports, GetNativeByIndex, MakeAddr, StrSize, Swap16, Swap32, Swap64,
};
use samp_sdk::raw::types::AMX_NATIVE_INFO;
#[cfg(not(feature = "samp-only"))]
use crate::runtime::Runtime;
#[cfg(not(feature = "samp-only"))]
fn extended_table() -> AmxResult<usize> {
let rt = Runtime::get();
if rt.omp_has_amx_exports() {
Ok(rt.amx_exports())
} else {
Err(AmxError::NotFound)
}
}
#[cfg(feature = "samp-only")]
fn extended_table() -> AmxResult<usize> {
Err(AmxError::NotFound)
}
#[must_use]
pub fn extended_table_available() -> bool {
extended_table().is_ok()
}
pub trait AmxOmpExt {
fn native_by_index(&self, index: i32) -> AmxResult<AMX_NATIVE_INFO>;
fn make_addr(&self, phys_addr: *mut i32) -> AmxResult<i32>;
unsafe fn str_size(&self, cstr: *const i32) -> AmxResult<usize>;
fn swap16(&self, value: &mut u16) -> AmxResult<()>;
fn swap32(&self, value: &mut u32) -> AmxResult<()>;
fn swap64(&self, value: &mut u64) -> AmxResult<()>;
}
impl AmxOmpExt for Amx {
fn native_by_index(&self, index: i32) -> AmxResult<AMX_NATIVE_INFO> {
let table = extended_table()?;
let amx = self.amx().ok_or(AmxError::NotFound)?;
let get = GetNativeByIndex::try_from_table(table).ok_or(AmxError::NotFound)?;
let mut info = AMX_NATIVE_INFO {
name: std::ptr::null_mut(),
func: dummy_native,
};
let code = get(amx.as_ptr(), index, &raw mut info);
if code > 0 {
return Err(AmxError::from(code));
}
Ok(info)
}
fn make_addr(&self, phys_addr: *mut i32) -> AmxResult<i32> {
let table = extended_table()?;
let amx = self.amx().ok_or(AmxError::NotFound)?;
let make = MakeAddr::try_from_table(table).ok_or(AmxError::NotFound)?;
let mut address = 0;
let code = make(amx.as_ptr(), phys_addr, &raw mut address);
if code > 0 {
return Err(AmxError::from(code));
}
Ok(address)
}
unsafe fn str_size(&self, cstr: *const i32) -> AmxResult<usize> {
let table = extended_table()?;
let size = StrSize::try_from_table(table).ok_or(AmxError::NotFound)?;
let mut length = 0;
let code = size(cstr, &raw mut length);
if code > 0 {
return Err(AmxError::from(code));
}
Ok(usize::try_from(length).unwrap_or(0))
}
fn swap16(&self, value: &mut u16) -> AmxResult<()> {
let table = extended_table()?;
let swap = Swap16::try_from_table(table).ok_or(AmxError::NotFound)?;
let code = swap(&raw mut *value);
if code > 0 {
return Err(AmxError::from(code));
}
Ok(())
}
fn swap32(&self, value: &mut u32) -> AmxResult<()> {
let table = extended_table()?;
let swap = Swap32::try_from_table(table).ok_or(AmxError::NotFound)?;
let code = swap(&raw mut *value);
if code > 0 {
return Err(AmxError::from(code));
}
Ok(())
}
fn swap64(&self, value: &mut u64) -> AmxResult<()> {
let table = extended_table()?;
let swap = Swap64::try_from_table(table).ok_or(AmxError::NotFound)?;
let code = swap(&raw mut *value);
if code > 0 {
return Err(AmxError::from(code));
}
Ok(())
}
}
extern "C" fn dummy_native(_amx: *mut samp_sdk::raw::types::AMX, _params: *mut i32) -> i32 {
0
}
#[must_use]
pub fn extended_indices() -> [Exports; 8] {
[
Exports::PushStringLen,
Exports::SetStringLen,
Exports::Swap16,
Exports::Swap32,
Exports::Swap64,
Exports::GetNativeByIndex,
Exports::MakeAddr,
Exports::StrSize,
]
}