use std::ffi::CStr;
use std::os::raw::c_char;
use crate::eq::{ChatColor, GameState, GroundItem, Spawn};
use crate::ffi;
#[allow(unused_variables)]
pub trait Plugin {
fn new() -> Self;
fn initialize(&mut self) {}
fn shutdown(&mut self) {}
fn on_clean_ui(&mut self) {}
fn on_reload_ui(&mut self) {}
fn on_draw_hud(&mut self) {}
fn on_set_game_state(&mut self, state: GameState) {}
fn on_pulse(&mut self) {}
fn on_write_chat_color(&mut self, line: &str, color: ChatColor) {}
fn on_incoming_chat(&mut self, line: &str, color: ChatColor) -> bool {
false
}
fn on_add_spawn(&mut self, spawn: &Spawn) {}
fn on_remove_spawn(&mut self, spawn: &Spawn) {}
fn on_add_ground_item(&mut self, item: &GroundItem) {}
fn on_remove_ground_item(&mut self, item: &GroundItem) {}
fn on_begin_zone(&mut self) {}
fn on_end_zone(&mut self) {}
fn on_zoned(&mut self) {}
fn on_update_imgui(&mut self) {}
fn on_macro_start(&mut self, name: &str) {}
fn on_macro_stop(&mut self, name: &str) {}
fn on_plugin_load(&mut self, name: &str) {}
fn on_plugin_unload(&mut self, name: &str) {}
}
#[doc(hidden)]
pub struct PluginHandler<T: Plugin> {
data: parking_lot::Mutex<Option<T>>,
}
#[allow(clippy::missing_safety_doc)]
impl<T: Plugin> PluginHandler<T> {
pub const fn new() -> PluginHandler<T> {
PluginHandler {
data: parking_lot::Mutex::new(None),
}
}
pub fn replace(&self, new: Option<T>) {
let mut plugin = self.data.lock();
*plugin = new;
}
simple_hook!(initialize);
simple_hook!(shutdown);
simple_hook!(on_clean_ui);
simple_hook!(on_reload_ui);
simple_hook!(on_draw_hud);
simple_hook!(on_pulse);
simple_hook!(on_begin_zone);
simple_hook!(on_end_zone);
simple_hook!(on_zoned);
simple_hook!(on_update_imgui);
str_hook!(on_macro_start);
str_hook!(on_macro_stop);
str_hook!(on_plugin_load);
str_hook!(on_plugin_unload);
pub fn on_set_game_state<S: Into<GameState>>(&self, state: S) {
hook!(self, on_set_game_state, state.into())
}
pub unsafe fn on_write_chat_color<C: Into<ChatColor>>(&self, ptr: *const c_char, color: C) {
let value = CStr::from_ptr(ptr);
match value.to_str() {
Ok(s) => hook!(self, on_write_chat_color, s, color.into()),
Err(_) => todo!("figure out error handling"),
}
}
pub unsafe fn on_incoming_chat<C: Into<ChatColor>>(
&self,
ptr: *const c_char,
color: C,
) -> bool {
let value = CStr::from_ptr(ptr);
match value.to_str() {
Ok(s) => hook!(self, on_incoming_chat, s, color.into()),
Err(_) => todo!("figure out error handling"),
}
}
pub unsafe fn on_add_spawn(&self, ptr: *const ffi::eqlib::PlayerClient) {
match ptr.as_ref() {
Some(ffi_item) => {
let item = Spawn(ffi_item);
hook!(self, on_add_spawn, &item)
}
None => todo!("figure out error handling"),
}
}
pub unsafe fn on_remove_spawn(&self, ptr: *const ffi::eqlib::PlayerClient) {
match ptr.as_ref() {
Some(ffi_item) => {
let item = Spawn(ffi_item);
hook!(self, on_remove_spawn, &item)
}
None => todo!("figure out error handling"),
}
}
pub unsafe fn on_add_ground_item(&self, ptr: *const ffi::eqlib::EQGroundItem) {
match ptr.as_ref() {
Some(ffi_item) => {
let item = GroundItem(ffi_item);
hook!(self, on_add_ground_item, &item)
}
None => todo!("figure out error handling"),
}
}
pub unsafe fn on_remove_ground_item(&self, ptr: *const ffi::eqlib::EQGroundItem) {
match ptr.as_ref() {
Some(ffi_item) => {
let item = GroundItem(ffi_item);
hook!(self, on_remove_ground_item, &item)
}
None => todo!("figure out error handling"),
}
}
}
mod macros {
macro_rules! hook {
($handler:ident, $hook:ident, $($param:expr),*) => {{
let mut lock = $handler.data.lock();
let plugin: &mut T = lock.as_mut().expect("no plugin");
plugin.$hook($($param),*)
}};
}
macro_rules! simple_hook {
($hook:ident) => {
pub fn $hook(&self) {
let mut lock = self.data.lock();
let plugin: &mut T = lock.as_mut().expect("no plugin");
plugin.$hook()
}
};
}
macro_rules! str_hook {
($hook:ident) => {
#[allow(clippy::missing_safety_doc)]
pub unsafe fn $hook(&self, ptr: *const c_char) {
let value = CStr::from_ptr(ptr);
match value.to_str() {
Ok(s) => {
let mut lock = self.data.lock();
let plugin: &mut T = lock.as_mut().expect("no plugin");
plugin.$hook(s)
}
Err(_) => todo!("figure out error handling"),
}
}
};
}
pub(super) use {hook, simple_hook, str_hook};
}
use macros::{hook, simple_hook, str_hook};