macroquest_macros/
lib.rs

1use proc_macro::TokenStream;
2use quote::{format_ident, quote, ToTokens};
3use syn::{parse_macro_input, ItemStruct};
4
5#[proc_macro_attribute]
6pub fn plugin(_args: TokenStream, stream: TokenStream) -> TokenStream {
7    let input = parse_macro_input!(stream as ItemStruct);
8    let mut output = proc_macro2::TokenStream::new();
9
10    let plugin_t = format_ident!("{}", input.ident);
11    let plugin = format_ident!("__{}", input.ident.to_string().to_uppercase());
12
13    let eq_version_str = include_str!(concat!(env!("OUT_DIR"), "/eq_version.txt")).as_bytes();
14
15    let implementation = quote! {
16        #[no_mangle]
17        pub static IsBuiltForNext: bool = true;
18
19        #[no_mangle]
20        pub static EverQuestVersion: [u8; 21] = [#(#eq_version_str),*,0];
21
22
23        static #plugin: ::macroquest::PluginHandler<#plugin_t> = ::macroquest::PluginHandler::new();
24
25        #[no_mangle]
26        extern "system" fn DllMain(
27            _: ::macroquest::windows::HINSTANCE,
28            call_reason: u32,
29            _: *mut (),
30        ) -> bool {
31            use ::macroquest::windows::{DLL_PROCESS_ATTACH, DLL_PROCESS_DETACH};
32
33            match call_reason {
34                DLL_PROCESS_ATTACH => #plugin.replace(Some(#plugin_t::new())),
35                DLL_PROCESS_DETACH => #plugin.replace(None),
36                _ => {}
37            }
38
39            true
40        }
41
42        #[no_mangle]
43        pub fn InitializePlugin() {
44            #plugin.initialize()
45        }
46
47        #[no_mangle]
48        pub fn ShutdownPlugin() {
49            #plugin.shutdown()
50        }
51
52        #[no_mangle]
53        pub fn OnCleanUI() {
54            #plugin.on_clean_ui()
55        }
56
57        #[no_mangle]
58        pub fn OnReloadUI() {
59            #plugin.on_reload_ui()
60        }
61
62        #[no_mangle]
63        pub fn OnDrawHUD() {
64            #plugin.on_draw_hud()
65        }
66
67        #[no_mangle]
68        pub fn SetGameState(state: i32) {
69            #plugin.on_set_game_state(state)
70        }
71
72        #[no_mangle]
73        pub fn OnPulse() {
74            #plugin.on_pulse()
75        }
76
77        #[no_mangle]
78        pub unsafe fn OnWriteChatColor(
79            line_ptr: *const ::std::os::raw::c_char,
80            color: i32,
81            _filter: i32,  // Per brainiac, filter appears to be unused
82        ) {
83            #plugin.on_write_chat_color(line_ptr, color)
84        }
85
86        #[no_mangle]
87        pub unsafe fn OnIncomingChat(
88            line_ptr: *const ::std::os::raw::c_char,
89            color: u32,
90        ) -> bool {
91            #plugin.on_incoming_chat(line_ptr, color as i32)
92        }
93
94        #[no_mangle]
95        pub unsafe fn OnAddSpawn(spawn: *const ::macroquest::ffi::eqlib::PlayerClient) {
96            #plugin.on_add_spawn(spawn)
97        }
98
99        #[no_mangle]
100        pub unsafe fn OnRemoveSpawn(spawn: *const ::macroquest::ffi::eqlib::PlayerClient) {
101            #plugin.on_remove_spawn(spawn)
102        }
103
104        #[no_mangle]
105        pub unsafe fn OnAddGroundItem(item: *const ::macroquest::ffi::eqlib::EQGroundItem) {
106            #plugin.on_add_ground_item(item)
107        }
108
109        #[no_mangle]
110        pub unsafe fn OnRemoveGroundItem(item: *const ::macroquest::ffi::eqlib::EQGroundItem) {
111            #plugin.on_remove_ground_item(item)
112        }
113
114        #[no_mangle]
115        pub fn OnBeginZone() {
116            #plugin.on_begin_zone()
117        }
118
119        #[no_mangle]
120        pub fn OnEndZone() {
121            #plugin.on_end_zone()
122        }
123
124        #[no_mangle]
125        pub fn OnZoned() {
126            #plugin.on_zoned()
127        }
128
129        #[no_mangle]
130        pub fn OnUpdateImGui() {
131            #plugin.on_update_imgui()
132        }
133
134        #[no_mangle]
135        pub unsafe fn OnMacroStart(name_ptr: *const ::std::os::raw::c_char) {
136            #plugin.on_macro_start(name_ptr)
137        }
138
139        #[no_mangle]
140        pub unsafe fn OnMacroStop(name_ptr: *const ::std::os::raw::c_char) {
141            #plugin.on_macro_stop(name_ptr)
142        }
143
144        #[no_mangle]
145        pub unsafe fn OnLoadPlugin(name_ptr: *const ::std::os::raw::c_char) {
146            #plugin.on_plugin_load(name_ptr)
147        }
148
149        #[no_mangle]
150        pub unsafe fn OnUnloadPlugin(name_ptr: *const ::std::os::raw::c_char) {
151            #plugin.on_plugin_unload(name_ptr)
152        }
153    };
154
155    input.to_tokens(&mut output);
156    implementation.to_tokens(&mut output);
157
158    TokenStream::from(output)
159}
160
161// fn eq_version() -> String {
162//     use std::ffi::CStr;
163//     use std::os::raw::c_char;
164
165//     #[link(name = "MQ2Main")]
166//     extern "C" {
167//         static gszVersion: [c_char; 32];
168//         static gszTime: [c_char; 32];
169//     }
170
171//     let date = unsafe { CStr::from_ptr(gszVersion.as_ptr()) };
172//     let time = unsafe { CStr::from_ptr(gszTime.as_ptr()) };
173
174//     format!("{} {}", date.to_str().unwrap(), time.to_str().unwrap())
175// }