1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
//! Contains a plugin interface. use std::ptr::NonNull; 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(); } /// Enables process_tick function for a plugin. /// /// # Example /// ```rust,compile_fail /// use samp::initialize_plugin; /// use samp::prelude::*; /// /// struct MyPlugin; /// /// impl SampPlugin for MyPlugin {} /// /// initialize_plugin!({ /// samp::plugin::enable_process_tick(); /// return MyPlugin; /// }); /// ``` pub fn enable_process_tick() { let runtime = Runtime::get(); runtime.enable_process_tick(); } /// Get a fern [`Dispatch`] and disable auto installing logger. /// /// # Example /// ```rust,compile_fail /// use samp::initialize_plugin; /// use samp::prelude::*; /// /// use std::fs::OpenOptions; /// /// struct MyPlugin; /// /// impl SampPlugin for MyPlugin {} /// /// initialize_plugin!({ /// samp::plugin::enable_process_tick(); /// /// // get a default samp logger (uses samp logprintf). /// let samp_logger = samp::plugin::logger() /// .level(log::LevelFilter::Warn); // logging only warn and error messages /// /// let log_file = fern::log_file("myplugin.log").expect("Something wrong!"); /// /// // log trace and debug messages in an another file /// let trace_level = fern::Dispatch::new() /// .level(log::LevelFilter::Trace) // write ALL types of logs /// .chain(log_file); /// /// let _ = fern::Dispatch::new() /// .format(|callback, message, record| { /// // all messages will be formated like /// // [MyPlugin][ERROR]: something (error!("something")) /// // [MyPlugin][INFO]: some info (info!("some info")) /// callback.finish(format_args!("[MyPlugin][{}]: {}", record.level(), message)) /// }) /// .chain(samp_logger) /// .chain(trace_level) /// .apply(); /// /// return MyPlugin; /// }); /// ``` /// /// [`Dispatch`]: https://docs.rs/fern/0.5.7/fern/struct.Dispatch.html 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(); rt.log(record.args()); })) } #[doc(hidden)] pub fn get<T: SampPlugin + 'static>() -> NonNull<T> { Runtime::plugin_cast() } /// An interface that should be implemented by any plugin. /// /// All methods are optional 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 process_tick(&mut self) {} } #[doc(hidden)] pub fn convert_return_value<T: AmxCell<'static>>(value: T) -> i32 { value.as_cell() }