use std::ptr::NonNull;
use std::time::Duration;
use samp_sdk::amx::Amx;
use samp_sdk::cell::AmxCell;
use crate::runtime::Runtime;
#[doc(hidden)]
pub fn initialize<F, T>(constructor: F)
where
F: FnOnce() -> T + 'static,
T: SampPlugin + 'static,
{
let rt = Runtime::initialize();
let plugin = constructor();
rt.set_plugin(plugin);
rt.post_initialize();
}
#[derive(Debug, Clone, Copy)]
pub struct TickConfig {
pub sa_mp: bool,
pub omp: bool,
pub omp_interval: Duration,
}
impl Default for TickConfig {
fn default() -> Self {
Self {
sa_mp: true,
omp: true,
omp_interval: Duration::from_millis(5),
}
}
}
impl TickConfig {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn sa_mp(mut self, enabled: bool) -> Self {
self.sa_mp = enabled;
self
}
#[must_use]
pub fn omp(mut self, enabled: bool) -> Self {
self.omp = enabled;
self
}
#[must_use]
pub fn omp_interval(mut self, interval: Duration) -> Self {
self.omp_interval = interval;
self
}
#[must_use]
pub fn sa_mp_only() -> Self {
Self::default().omp(false)
}
#[must_use]
pub fn omp_only(interval: Duration) -> Self {
Self::default().sa_mp(false).omp_interval(interval)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TickSource {
SaMp,
OmpTimer,
}
#[derive(Debug, Clone, Copy)]
pub struct TickContext {
pub elapsed: Duration,
pub source: TickSource,
}
pub fn enable_tick() {
enable_tick_with(TickConfig::default());
}
pub fn enable_tick_with(config: TickConfig) {
Runtime::get().set_tick_config(config);
}
pub fn enable_debug_hook(amx: &Amx) {
amx.install_debug_hook(debug_hook_trampoline);
}
pub fn disable_debug_hook(amx: &Amx) {
amx.remove_debug_hook();
}
extern "C" fn debug_hook_trampoline(amx: *mut samp_sdk::raw::types::AMX) -> i32 {
let _ = std::panic::catch_unwind(|| {
let Some(rt) = Runtime::try_get() else { return };
let wrapped = Amx::new(amx, rt.amx_exports());
Runtime::plugin().on_debug_break(&wrapped);
});
0 }
pub fn logger() -> fern::Dispatch {
let rt = Runtime::get();
rt.disable_default_logger();
fern::Dispatch::new().chain(fern::Output::call(|record| {
let rt = Runtime::get();
#[cfg(not(feature = "samp-only"))]
{
let level = match record.level() {
log::Level::Error => samp_sdk::omp::LogLevel::Error,
log::Level::Warn => samp_sdk::omp::LogLevel::Warning,
log::Level::Info => samp_sdk::omp::LogLevel::Message,
log::Level::Debug | log::Level::Trace => samp_sdk::omp::LogLevel::Debug,
};
rt.log_level(level, record.args());
}
#[cfg(feature = "samp-only")]
rt.log(record.args());
}))
}
#[doc(hidden)]
#[must_use]
pub fn get<T: SampPlugin + 'static>() -> NonNull<T> {
Runtime::plugin_cast()
}
#[cfg(not(feature = "samp-only"))]
#[must_use]
pub fn omp_core() -> Option<*mut samp_sdk::omp::component::ICore> {
crate::runtime::Runtime::get().omp_core()
}
#[cfg(not(feature = "samp-only"))]
#[must_use]
pub fn omp_query_component(
uid: samp_sdk::omp::types::UID,
) -> Option<*mut samp_sdk::omp::server::ServerComponent> {
crate::runtime::Runtime::get().omp_query_component(uid)
}
#[cfg(not(feature = "samp-only"))]
#[must_use]
pub fn omp_query<T>() -> Option<T>
where
T: samp_sdk::omp::OmpComponentHandle,
{
let raw = omp_query_component(T::UID)?;
let nonnull_ptr = std::ptr::NonNull::new(raw)?;
Some(unsafe { T::from_raw(nonnull_ptr) })
}
pub trait SampPlugin {
fn on_load(&mut self) {}
fn on_unload(&mut self) {}
fn on_amx_load(&mut self, amx: &Amx) {
let _ = amx;
}
fn on_amx_unload(&mut self, amx: &Amx) {
let _ = amx;
}
fn on_debug_break(&mut self, amx: &Amx) {
let _ = amx;
}
fn on_tick(&mut self, ctx: TickContext) {
let _ = ctx;
}
#[cfg(not(feature = "samp-only"))]
fn on_omp_ready(&mut self) {}
#[cfg(not(feature = "samp-only"))]
fn on_component_free(&mut self) {}
}
#[doc(hidden)]
pub fn convert_return_value<T: AmxCell<'static>>(value: T) -> i32 {
value.as_cell()
}