diff --git a/plugin/derive/src/lib.rs b/plugin/derive/src/lib.rs index d275848d87..9687432875 100644 --- a/plugin/derive/src/lib.rs +++ b/plugin/derive/src/lib.rs @@ -2,7 +2,22 @@ extern crate proc_macro; use proc_macro::TokenStream; use quote::quote; -use syn::{parse_macro_input, ItemFn}; +use syn::{parse_macro_input, ItemFn, ItemStruct}; + +#[proc_macro_attribute] +pub fn global_state(_args: TokenStream, item: TokenStream) -> TokenStream { + let parsed = parse_macro_input!(item as ItemStruct); + let name = &parsed.ident; + let out: proc_macro2::TokenStream = quote! { + #parsed + type PLUGIN_STATE_TYPE = #name; + + static mut PLUGIN_STATE: Option = None; + + static PLUGIN_STATE_GUARD: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false); + }; + out.into() +} #[proc_macro_attribute] pub fn event_handler(_args: TokenStream, item: TokenStream) -> TokenStream { @@ -13,20 +28,48 @@ pub fn event_handler(_args: TokenStream, item: TokenStream) -> TokenStream { let fn_args = sig.inputs; // comma separated args let fn_return = sig.output; // comma separated args - let out: proc_macro2::TokenStream = quote! { - #[allow(clippy::unnecessary_wraps)] - #[no_mangle] - pub fn #fn_name(intern__ptr: i64, intern__len: i64) -> i64 { - let input = ::veloren_plugin_rt::read_input(intern__ptr as _,intern__len as _).unwrap(); - #[inline] - fn inner(#fn_args) #fn_return { - #fn_body + let out: proc_macro2::TokenStream = if fn_args.len() == 1 { + quote! { + #[allow(clippy::unnecessary_wraps)] + #[no_mangle] + pub fn #fn_name(intern__ptr: i64, intern__len: i64) -> i64 { + let input = ::veloren_plugin_rt::read_input(intern__ptr as _,intern__len as _).unwrap(); + #[inline] + fn inner(#fn_args) #fn_return { + #fn_body + } + // Artificially force the event handler to be type-correct + fn force_event(event: E, inner: fn(E) -> E::Response) -> E::Response { + inner(event) + } + ::veloren_plugin_rt::write_output(&force_event(input, inner)) } - // Artificially force the event handler to be type-correct - fn force_event(event: E, inner: fn(E) -> E::Response) -> E::Response { - inner(event) + } + } else { + quote! { + #[allow(clippy::unnecessary_wraps)] + #[no_mangle] + pub fn #fn_name(intern__ptr: i64, intern__len: i64) -> i64 { + let input = ::veloren_plugin_rt::read_input(intern__ptr as _,intern__len as _).unwrap(); + #[inline] + fn inner(#fn_args) #fn_return { + #fn_body + } + // Artificially force the event handler to be type-correct + fn force_event(event: E, inner: fn(E, &mut PLUGIN_STATE_TYPE) -> E::Response) -> E::Response { + //let mut plugin_state = PLUGIN_STATE.lock().unwrap(); + unsafe { + assert_eq!(PLUGIN_STATE_GUARD.swap(true, std::sync::atomic::Ordering::Acquire), false); + if PLUGIN_STATE.is_none() { + PLUGIN_STATE = Some(PLUGIN_STATE_TYPE::default()); + } + let out = inner(event, PLUGIN_STATE.as_mut().unwrap()); + PLUGIN_STATE_GUARD.store(false, std::sync::atomic::Ordering::Release); + out + } + } + ::veloren_plugin_rt::write_output(&force_event(input, inner)) } - ::veloren_plugin_rt::write_output(&force_event(input, inner)) } }; out.into() diff --git a/plugin/rt/examples/hello.rs b/plugin/rt/examples/hello.rs index f9009b6525..aa8f0c1b71 100644 --- a/plugin/rt/examples/hello.rs +++ b/plugin/rt/examples/hello.rs @@ -1,5 +1,3 @@ -use std::sync::atomic::{AtomicBool, Ordering}; - use veloren_plugin_rt::{ api::{event::*, Action, GameMode}, *, @@ -31,11 +29,16 @@ pub fn on_command_testplugin(command: ChatCommandEvent) -> Result, S )]) } -static COUNTER: AtomicBool = AtomicBool::new(false); +#[global_state] +#[derive(Default)] +struct State { + counter: bool, +} #[event_handler] -pub fn on_join(input: PlayerJoinEvent) -> PlayerJoinResult { - if COUNTER.swap(!COUNTER.load(Ordering::SeqCst), Ordering::SeqCst) { +pub fn on_join(input: PlayerJoinEvent, state: &mut State) -> PlayerJoinResult { + state.counter = !state.counter; + if !state.counter { PlayerJoinResult::Kick(format!("You are a cheater {:?}", input)) } else { PlayerJoinResult::None