diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/bridge/NativePatchBukkit.java b/java/patchbukkit/src/main/java/org/patchbukkit/bridge/NativePatchBukkit.java index 7d04918..107cbd7 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/bridge/NativePatchBukkit.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/bridge/NativePatchBukkit.java @@ -15,7 +15,6 @@ public class NativePatchBukkit { private static final Linker LINKER = Linker.nativeLinker(); private static MethodHandle sendMessageNative; - private static MethodHandle registerEventNative; private static MethodHandle callEventNative; private static MethodHandle getLocationNative; private static MethodHandle getWorldNative; @@ -184,7 +183,6 @@ public class NativePatchBukkit { */ public static void initCallbacks( long sendMessageAddr, - long registerEventAddr, long callEventAddr, long getLocationAddr, long freeStringAddr, @@ -199,17 +197,6 @@ public class NativePatchBukkit { FunctionDescriptor.ofVoid(ValueLayout.ADDRESS, ValueLayout.ADDRESS) ); - // void rust_register_event(const char* event_type, const char* plugin_name, int32_t priority, bool blocking) - registerEventNative = LINKER.downcallHandle( - MemorySegment.ofAddress(registerEventAddr), - FunctionDescriptor.ofVoid( - ValueLayout.ADDRESS, // event_type string - ValueLayout.ADDRESS, // plugin_name string - ValueLayout.JAVA_INT, // priority ordinal - ValueLayout.JAVA_BOOLEAN // blocking - ) - ); - // bool rust_call_event(const char* event_type, const char* event_data_json) // Returns true if Pumpkin handled it, false if unknown event type callEventNative = LINKER.downcallHandle( @@ -294,28 +281,6 @@ public class NativePatchBukkit { } } - /** - * Register an event listener with Pumpkin's event system. - * - * Called by PatchBukkitEventManager when a plugin registers for an event. - * Rust will create a PatchBukkitEventHandler that listens for the corresponding - * Pumpkin event and dispatches back to Java when it fires. - * - * @param eventType Fully qualified Bukkit event class name (e.g. "org.bukkit.event.player.PlayerJoinEvent") - * @param pluginName Name of the plugin registering this listener - * @param priority Bukkit EventPriority ordinal (0=LOWEST through 5=MONITOR), clamped to 0-4 for Pumpkin - * @param blocking Whether the handler should block - */ - public static void registerEvent(String eventType, String pluginName, int priority, boolean blocking) { - try (Arena arena = Arena.ofConfined()) { - MemorySegment eventTypeStr = arena.allocateFrom(eventType); - MemorySegment pluginNameStr = arena.allocateFrom(pluginName); - registerEventNative.invokeExact(eventTypeStr, pluginNameStr, priority, blocking); - } catch (Throwable t) { - throw new RuntimeException("Failed to register event: " + eventType + " for plugin " + pluginName, t); - } - } - /** * Get a player's location by UUID. * diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java index a2d4a2b..5cb49c1 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -19,6 +19,8 @@ import com.google.common.collect.Sets; import co.aikar.timings.TimedEventExecutor; import org.jetbrains.annotations.NotNull; +import patchbukkit.bridge.NativeBridgeFfi; +import patchbukkit.common.RegisterEventRequest; import java.lang.reflect.Method; import java.util.Arrays; @@ -128,12 +130,8 @@ public class PatchBukkitEventManager { for (RegisteredListener rl : entry.getValue()) { int priorityOrdinal = Math.min(rl.getPriority().ordinal(), 4); - NativePatchBukkit.registerEvent( - entry.getKey().getName(), - plugin.getName(), - priorityOrdinal, - true - ); + var request = RegisterEventRequest.newBuilder().setEventType(entry.getKey().getName()).setPluginName(plugin.getName()).setPriority(priorityOrdinal).setBlocking(true).build(); + NativeBridgeFfi.registerEvent(request); } } } @@ -151,7 +149,8 @@ public class PatchBukkitEventManager { this.getEventListeners(event).register(new RegisteredListener(listener, executor, priority, plugin, ignoreCancelled)); int priorityOrdinal = Math.min(priority.ordinal(), 4); - NativePatchBukkit.registerEvent(event.getName(), plugin.getName(), priorityOrdinal, true); // We default to having all events blocking. + var request = RegisterEventRequest.newBuilder().setEventType(event.getName()).setPluginName(plugin.getName()).setPriority(priorityOrdinal).setBlocking(true).build(); + NativeBridgeFfi.registerEvent(request); } diff --git a/java/protoc-gen-ffi/bin/main/org/patchbukkit/protocgen/FfiGenerator.class b/java/protoc-gen-ffi/bin/main/org/patchbukkit/protocgen/FfiGenerator.class new file mode 100644 index 0000000..5015927 Binary files /dev/null and b/java/protoc-gen-ffi/bin/main/org/patchbukkit/protocgen/FfiGenerator.class differ diff --git a/proto/patchbukkit/bridge/native.proto b/proto/patchbukkit/bridge/native.proto index 0a0af57..734bfe2 100644 --- a/proto/patchbukkit/bridge/native.proto +++ b/proto/patchbukkit/bridge/native.proto @@ -1,11 +1,14 @@ syntax = "proto3"; package patchbukkit.bridge; +import "google/protobuf/empty.proto"; import "google/protobuf/wrappers.proto"; import "patchbukkit/common/abilities.proto"; +import "patchbukkit/common/events.proto"; import "patchbukkit/common/types.proto"; service NativeBridge { rpc GetAbilities(patchbukkit.common.UUID) returns (patchbukkit.common.Abilities); rpc SetAbilities(patchbukkit.common.SetAbilitiesRequest) returns (google.protobuf.BoolValue); + rpc RegisterEvent(patchbukkit.common.RegisterEventRequest) returns (google.protobuf.Empty); } diff --git a/proto/patchbukkit/common/events.proto b/proto/patchbukkit/common/events.proto new file mode 100644 index 0000000..41d31ef --- /dev/null +++ b/proto/patchbukkit/common/events.proto @@ -0,0 +1,15 @@ +syntax = "proto3"; + +package patchbukkit.common; + +import "patchbukkit/common/types.proto"; + +option java_multiple_files = true; +option java_package = "patchbukkit.common"; + +message RegisterEventRequest { + string event_type = 1; + string plugin_name = 2; + int32 priority = 3; + bool blocking = 4; +} diff --git a/rust/build/protobufs.rs b/rust/build/protobufs.rs index 78e78d7..fc60f32 100644 --- a/rust/build/protobufs.rs +++ b/rust/build/protobufs.rs @@ -162,7 +162,6 @@ pub fn setup_protobufs(base: PathBuf) { config.service_generator(Box::new(generator)); config.compile_protos(&paths, &[proto_path]).unwrap(); - // Generate the shared initialization file let out_dir = std::env::var("OUT_DIR").unwrap(); let init_path = PathBuf::from(&out_dir).join("ffi_init.rs"); diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index d34fe35..c19190b 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -7,22 +7,11 @@ use pumpkin_util::text::TextComponent; use crate::events::handler::PatchBukkitEventHandler; use crate::java::native_callbacks::{CALLBACK_CONTEXT, utils::get_string}; +use crate::proto::patchbukkit::common::RegisterEventRequest; -pub extern "C" fn rust_register_event( - event_type_ptr: *const c_char, - plugin_name_ptr: *const c_char, - priority: i32, - blocking: bool, -) { - let event_type = get_string(event_type_ptr); - let plugin_name = get_string(plugin_name_ptr); - - let Some(ctx) = CALLBACK_CONTEXT.get() else { - log::error!("CallbackContext not initialized when registering event"); - return; - }; - - let pumpkin_priority = match priority { +pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> Option<()> { + let ctx = CALLBACK_CONTEXT.get()?; + let pumpkin_priority = match request.priority { 0 => EventPriority::Lowest, 1 => EventPriority::Low, 2 => EventPriority::Normal, @@ -31,16 +20,19 @@ pub extern "C" fn rust_register_event( }; log::info!( - "Plugin '{plugin_name}' registering listener for '{event_type}' (priority={priority:?}, blocking={blocking})" + "Plugin '{}' registering listener for '{}' (priority={:?}, blocking={})", + request.plugin_name, + request.event_type, + request.priority, + request.blocking ); let command_tx = ctx.command_tx.clone(); let context = ctx.plugin_context.clone(); - let event_type_owned = event_type; tokio::task::block_in_place(|| { ctx.runtime.block_on(async { - match event_type_owned.as_str() { + match request.event_type.as_str() { "org.bukkit.event.player.PlayerJoinEvent" => { context .register_event::< @@ -48,22 +40,25 @@ pub extern "C" fn rust_register_event( PatchBukkitEventHandler, >( Arc::new(PatchBukkitEventHandler::new( - plugin_name.clone(), + request.plugin_name.clone(), command_tx.clone(), )), pumpkin_priority, - blocking, + request.blocking, ) .await; } _ => { log::warn!( - "Unsupported Bukkit event type '{event_type_owned}' from plugin '{plugin_name}'" + "Unsupported Bukkit event type '{}' from plugin '{}'", + request.event_type, request.plugin_name ); } } }); }); + + Some(()) } pub extern "C" fn rust_call_event( diff --git a/rust/src/java/native_callbacks/mod.rs b/rust/src/java/native_callbacks/mod.rs index f5d3b4e..7d6fbdd 100644 --- a/rust/src/java/native_callbacks/mod.rs +++ b/rust/src/java/native_callbacks/mod.rs @@ -11,6 +11,8 @@ mod abilities; pub use abilities::*; pub mod events; +pub use events::*; + pub mod location; pub mod memory; pub mod message; @@ -66,7 +68,6 @@ pub extern "C" fn rust_free_bytes(ptr: *mut u8, len: u32) { pub fn initialize_callbacks(jvm: &Jvm) -> Result<()> { let send_message_addr = message::rust_send_message as *const () as i64; - let register_event_addr = events::rust_register_event as *const () as i64; let call_event_addr = events::rust_call_event as *const () as i64; let get_location_addr = location::rust_get_location as *const () as i64; let free_string_addr = memory::rust_free_string as *const () as i64; @@ -81,7 +82,6 @@ pub fn initialize_callbacks(jvm: &Jvm) -> Result<()> { "initCallbacks", &[ InvocationArg::try_from(send_message_addr)?.into_primitive()?, - InvocationArg::try_from(register_event_addr)?.into_primitive()?, InvocationArg::try_from(call_event_addr)?.into_primitive()?, InvocationArg::try_from(get_location_addr)?.into_primitive()?, InvocationArg::try_from(free_string_addr)?.into_primitive()?,