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()
}