From 605858e14fafbdc0e2e15256dead3181d70a9317 Mon Sep 17 00:00:00 2001 From: Bjorn Beishline <75190918+BjornTheProgrammer@users.noreply.github.com> Date: Tue, 3 Feb 2026 16:54:07 -0700 Subject: [PATCH] Refactor call event --- .../patchbukkit/bridge/NativePatchBukkit.java | 34 ---------- .../patchbukkit/entity/PatchBukkitPlayer.java | 4 +- .../events/PatchBukkitEventManager.java | 22 +++++- .../patchbukkit/{common => }/abilities.proto | 10 ++- proto/patchbukkit/bridge.proto | 17 +++++ proto/patchbukkit/bridge/native.proto | 16 ----- proto/patchbukkit/common/events.proto | 15 ---- proto/patchbukkit/events/event.proto | 17 +++-- proto/patchbukkit/events/player_events.proto | 2 +- proto/patchbukkit/{common => }/message.proto | 4 +- rust/src/java/native_callbacks/abilities.rs | 5 +- rust/src/java/native_callbacks/events.rs | 68 +++++++++---------- rust/src/java/native_callbacks/message.rs | 5 +- rust/src/java/native_callbacks/mod.rs | 2 - rust/src/proto/mod.rs | 8 +++ 15 files changed, 106 insertions(+), 123 deletions(-) rename proto/patchbukkit/{common => }/abilities.proto (69%) create mode 100644 proto/patchbukkit/bridge.proto delete mode 100644 proto/patchbukkit/bridge/native.proto delete mode 100644 proto/patchbukkit/common/events.proto rename proto/patchbukkit/{common => }/message.proto (71%) 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 66e5919..999dd8c 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/bridge/NativePatchBukkit.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/bridge/NativePatchBukkit.java @@ -14,7 +14,6 @@ public class NativePatchBukkit { private static final Linker LINKER = Linker.nativeLinker(); - private static MethodHandle callEventNative; private static MethodHandle getLocationNative; private static MethodHandle getWorldNative; private static MethodHandle freeStringNative; @@ -181,7 +180,6 @@ public class NativePatchBukkit { * Called from Rust during initialization to register native function pointers. */ public static void initCallbacks( - long callEventAddr, long getLocationAddr, long freeStringAddr, long getWorldAddr, @@ -189,18 +187,6 @@ public class NativePatchBukkit { long playerEntityPlaySoundAddr, long playerPlaySoundAddr ) { - // 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( - MemorySegment.ofAddress(callEventAddr), - FunctionDescriptor.of( - ValueLayout.JAVA_BOOLEAN, // return: was handled by Pumpkin - ValueLayout.ADDRESS, // event_type string - ValueLayout.ADDRESS // event_data_json string - ) - ); - - // bool rust_get_location(const char* uuid, Vec3FFI* out) getLocationNative = LINKER.downcallHandle( MemorySegment.ofAddress(getLocationAddr), @@ -426,24 +412,4 @@ public class NativePatchBukkit { throw new RuntimeException("Failed to call native playerPlaySound", t); } } - - public static boolean callEvent(Event event) { - try (Arena arena = Arena.ofConfined()) { - // Serialize event data to JSON for Rust - String eventDataJson = PatchBukkitEventSerializer.serialize(event); - - MemorySegment eventTypeStr = arena.allocateFrom(event.getEventName()); - MemorySegment eventDataStr = arena.allocateFrom(eventDataJson); - - boolean handled = (boolean) callEventNative.invokeExact(eventTypeStr, eventDataStr); - - // If Pumpkin handled it and event is Cancellable, we need to read back - // the cancelled state. This is handled by Rust calling back to update - // the event object directly. - - return handled; - } catch (Throwable t) { - throw new RuntimeException("Failed to call event: " + event.getEventName(), t); - } - } } diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitPlayer.java b/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitPlayer.java index 8a080d1..571608c 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitPlayer.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitPlayer.java @@ -80,8 +80,8 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.util.TriState; import net.md_5.bungee.api.chat.BaseComponent; import patchbukkit.bridge.NativeBridgeFfi; -import patchbukkit.common.SendMessageRequest; -import patchbukkit.common.SetAbilitiesRequest; +import patchbukkit.message.SendMessageRequest; +import patchbukkit.abilities.SetAbilitiesRequest; @SuppressWarnings({ "deprecation", "removal" }) public class PatchBukkitPlayer 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 5cb49c1..f744a29 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -12,6 +12,7 @@ import org.bukkit.plugin.EventExecutor; import org.bukkit.plugin.IllegalPluginAccessException; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.RegisteredListener; +import org.patchbukkit.bridge.BridgeUtils; import org.patchbukkit.bridge.NativePatchBukkit; import com.google.common.collect.Sets; @@ -20,7 +21,9 @@ import co.aikar.timings.TimedEventExecutor; import org.jetbrains.annotations.NotNull; import patchbukkit.bridge.NativeBridgeFfi; -import patchbukkit.common.RegisterEventRequest; +import patchbukkit.events.CallEventRequest; +import patchbukkit.events.PlayerJoinEvent; +import patchbukkit.events.RegisterEventRequest; import java.lang.reflect.Method; import java.util.Arrays; @@ -45,7 +48,22 @@ public class PatchBukkitEventManager { throw new IllegalStateException(event.getEventName() + " may only be triggered synchronously."); } - boolean handledByPumpkin = NativePatchBukkit.callEvent(event); + var request = CallEventRequest.newBuilder(); + switch (event.getEventName()) { + case "org.bukkit.event.player.PlayerJoinEvent": + var castedEvent = (org.bukkit.event.player.PlayerJoinEvent) event; + request.setPlayerJoin( + PlayerJoinEvent.newBuilder() + .setJoinMessage(castedEvent.joinMessage().toString()) + .setPlayerUuid(BridgeUtils.convertUuid(castedEvent.getPlayer().getUniqueId())) + ); + break; + } + var response = NativeBridgeFfi.callEvent(request.build()); + + boolean handledByPumpkin; + if (response == null) handledByPumpkin = false; + else handledByPumpkin = response.getHandled(); if (!handledByPumpkin) { // Pumpkin doesn't know this event type, dispatch Java-only diff --git a/proto/patchbukkit/common/abilities.proto b/proto/patchbukkit/abilities.proto similarity index 69% rename from proto/patchbukkit/common/abilities.proto rename to proto/patchbukkit/abilities.proto index 7dd9220..2c5b830 100644 --- a/proto/patchbukkit/common/abilities.proto +++ b/proto/patchbukkit/abilities.proto @@ -1,15 +1,19 @@ syntax = "proto3"; -package patchbukkit.common; +package patchbukkit.abilities; import "patchbukkit/common/types.proto"; option java_multiple_files = true; -option java_package = "patchbukkit.common"; +option java_package = "patchbukkit.abilities"; message SetAbilitiesRequest { patchbukkit.common.UUID uuid = 1; - patchbukkit.common.Abilities abilities = 2; + Abilities abilities = 2; +} + +message SetAbilitiesResponse { + bool success = 1; } message Abilities { diff --git a/proto/patchbukkit/bridge.proto b/proto/patchbukkit/bridge.proto new file mode 100644 index 0000000..7c75ff9 --- /dev/null +++ b/proto/patchbukkit/bridge.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; +package patchbukkit.bridge; + +import "google/protobuf/empty.proto"; +import "google/protobuf/wrappers.proto"; +import "patchbukkit/abilities.proto"; +import "patchbukkit/common/types.proto"; +import "patchbukkit/events/event.proto"; +import "patchbukkit/message.proto"; + +service NativeBridge { + rpc GetAbilities(patchbukkit.common.UUID) returns (patchbukkit.abilities.Abilities); + rpc SetAbilities(patchbukkit.abilities.SetAbilitiesRequest) returns (patchbukkit.abilities.SetAbilitiesResponse); + rpc RegisterEvent(patchbukkit.events.RegisterEventRequest) returns (google.protobuf.Empty); + rpc CallEvent(patchbukkit.events.CallEventRequest) returns (patchbukkit.events.CallEventResponse); + rpc SendMessage(patchbukkit.message.SendMessageRequest) returns (google.protobuf.Empty); +} diff --git a/proto/patchbukkit/bridge/native.proto b/proto/patchbukkit/bridge/native.proto deleted file mode 100644 index 2750804..0000000 --- a/proto/patchbukkit/bridge/native.proto +++ /dev/null @@ -1,16 +0,0 @@ -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/message.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); - rpc SendMessage(patchbukkit.common.SendMessageRequest) returns (google.protobuf.Empty); -} diff --git a/proto/patchbukkit/common/events.proto b/proto/patchbukkit/common/events.proto deleted file mode 100644 index 41d31ef..0000000 --- a/proto/patchbukkit/common/events.proto +++ /dev/null @@ -1,15 +0,0 @@ -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/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index da51626..d6110e5 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -2,16 +2,25 @@ syntax = "proto3"; package patchbukkit.events; +import "patchbukkit/common/types.proto"; import "patchbukkit/events/player_events.proto"; option java_multiple_files = true; option java_package = "patchbukkit.events"; -message Event { - string event_id = 1; - bool cancellable = 2; +message RegisterEventRequest { + string event_type = 1; + string plugin_name = 2; + int32 priority = 3; + bool blocking = 4; +} +message CallEventRequest { oneof event_data { - PlayerJoinEvent player_join = 10; + PlayerJoinEvent player_join = 1; } } + +message CallEventResponse { + bool handled = 1; +} diff --git a/proto/patchbukkit/events/player_events.proto b/proto/patchbukkit/events/player_events.proto index bf5cca8..cd92e96 100644 --- a/proto/patchbukkit/events/player_events.proto +++ b/proto/patchbukkit/events/player_events.proto @@ -7,6 +7,6 @@ option java_multiple_files = true; option java_package = "patchbukkit.events"; message PlayerJoinEvent { - patchbukkit.common.UUID player = 1; + patchbukkit.common.UUID player_uuid = 1; string join_message = 2; } diff --git a/proto/patchbukkit/common/message.proto b/proto/patchbukkit/message.proto similarity index 71% rename from proto/patchbukkit/common/message.proto rename to proto/patchbukkit/message.proto index c5b8e1f..79a64ee 100644 --- a/proto/patchbukkit/common/message.proto +++ b/proto/patchbukkit/message.proto @@ -1,11 +1,11 @@ syntax = "proto3"; -package patchbukkit.common; +package patchbukkit.message; import "patchbukkit/common/types.proto"; option java_multiple_files = true; -option java_package = "patchbukkit.common"; +option java_package = "patchbukkit.message"; message SendMessageRequest { patchbukkit.common.UUID uuid = 1; diff --git a/rust/src/java/native_callbacks/abilities.rs b/rust/src/java/native_callbacks/abilities.rs index 4f42396..6bdbdf0 100644 --- a/rust/src/java/native_callbacks/abilities.rs +++ b/rust/src/java/native_callbacks/abilities.rs @@ -1,5 +1,8 @@ use crate::java::native_callbacks::CALLBACK_CONTEXT; -use crate::proto::patchbukkit::common::{Abilities, SetAbilitiesRequest, Uuid}; +use crate::proto::patchbukkit::{ + abilities::{Abilities, SetAbilitiesRequest}, + common::Uuid, +}; pub fn ffi_native_bridge_get_abilities_impl(request: Uuid) -> Option { let ctx = CALLBACK_CONTEXT.get()?; diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index c19190b..db5fdc5 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -1,4 +1,3 @@ -use std::ffi::c_char; use std::sync::Arc; use pumpkin::plugin::EventPriority; @@ -6,8 +5,11 @@ use pumpkin::plugin::player::player_join::PlayerJoinEvent; 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; +use crate::java::native_callbacks::CALLBACK_CONTEXT; +use crate::proto::patchbukkit::events::call_event_request::EventData; +use crate::proto::patchbukkit::events::{ + CallEventRequest, CallEventResponse, RegisterEventRequest, +}; pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> Option<()> { let ctx = CALLBACK_CONTEXT.get()?; @@ -61,44 +63,32 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O Some(()) } -pub extern "C" fn rust_call_event( - event_type_ptr: *const c_char, - event_data_ptr: *const c_char, -) -> bool { - let event_type = get_string(event_type_ptr); - let event_data_json = get_string(event_data_ptr); - - let Some(ctx) = CALLBACK_CONTEXT.get() else { - log::error!("CallbackContext not initialized when calling event"); - return false; - }; - - log::debug!("Java calling event '{event_type}' with data: {event_data_json}"); - - let event_data: serde_json::Value = match serde_json::from_str(&event_data_json) { - Ok(v) => v, - Err(e) => { - log::error!("Failed to parse event data JSON: {e}"); - return false; - } - }; +pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let ctx = CALLBACK_CONTEXT.get()?; + let event_data = request.event_data?; + log::debug!("Java calling event {:?}", event_data); let context = ctx.plugin_context.clone(); tokio::task::block_in_place(|| { ctx.runtime.block_on(async { - if event_type.as_str() == "org.bukkit.event.player.PlayerJoinEvent" { - let player_uuid_str = event_data["playerUuid"].as_str().unwrap_or(""); - let join_message_str = event_data["joinMessage"].as_str().unwrap_or(""); - if let Ok(uuid) = uuid::Uuid::parse_str(player_uuid_str) - && let Some(player) = context.server.get_player_by_uuid(uuid) - { - let pumpkin_event = PlayerJoinEvent::new( - player, - TextComponent::from_legacy_string(join_message_str), - ); - context.server.plugin_manager.fire(pumpkin_event).await; - return true; + match event_data { + EventData::PlayerJoin(player_join_event_data) => { + if let Ok(uuid) = + uuid::Uuid::parse_str(&player_join_event_data.player_uuid?.value) + { + if let Some(player) = context.server.get_player_by_uuid(uuid) { + let pumpkin_event = PlayerJoinEvent::new( + player, + TextComponent::from_legacy_string( + &player_join_event_data.join_message, + ), + ); + context.server.plugin_manager.fire(pumpkin_event).await; + return Some(true); + } + } + Some(false) } false } else { @@ -106,5 +96,9 @@ pub extern "C" fn rust_call_event( false } }) - }) + }); + + let mut response = CallEventResponse::default(); + response.handled = handled?; + Some(response) } diff --git a/rust/src/java/native_callbacks/message.rs b/rust/src/java/native_callbacks/message.rs index 2a119f9..8f477ac 100644 --- a/rust/src/java/native_callbacks/message.rs +++ b/rust/src/java/native_callbacks/message.rs @@ -1,10 +1,7 @@ -use std::ffi::c_char; - use pumpkin_util::text::TextComponent; use crate::{ - java::native_callbacks::{CALLBACK_CONTEXT, utils::get_string}, - proto::patchbukkit::common::SendMessageRequest, + java::native_callbacks::CALLBACK_CONTEXT, proto::patchbukkit::message::SendMessageRequest, }; pub fn ffi_native_bridge_send_message_impl(request: SendMessageRequest) -> Option<()> { diff --git a/rust/src/java/native_callbacks/mod.rs b/rust/src/java/native_callbacks/mod.rs index 10e2621..03b62c0 100644 --- a/rust/src/java/native_callbacks/mod.rs +++ b/rust/src/java/native_callbacks/mod.rs @@ -79,7 +79,6 @@ pub extern "C" fn rust_free_bytes(ptr: *mut u8, len: u32) { } pub fn initialize_callbacks(jvm: &Jvm) -> Result<()> { - 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; let get_world_addr = world::rust_get_world as *const () as i64; @@ -92,7 +91,6 @@ pub fn initialize_callbacks(jvm: &Jvm) -> Result<()> { "org.patchbukkit.bridge.NativePatchBukkit", "initCallbacks", &[ - InvocationArg::try_from(call_event_addr)?.into_primitive()?, InvocationArg::try_from(get_location_addr)?.into_primitive()?, InvocationArg::try_from(free_string_addr)?.into_primitive()?, InvocationArg::try_from(get_world_addr)?.into_primitive()?, diff --git a/rust/src/proto/mod.rs b/rust/src/proto/mod.rs index ffc0cb1..caf231c 100644 --- a/rust/src/proto/mod.rs +++ b/rust/src/proto/mod.rs @@ -10,6 +10,14 @@ pub mod patchbukkit { pub mod events { include!(concat!(env!("OUT_DIR"), "/patchbukkit.events.rs")); } + + pub mod abilities { + include!(concat!(env!("OUT_DIR"), "/patchbukkit.abilities.rs")); + } + + pub mod message { + include!(concat!(env!("OUT_DIR"), "/patchbukkit.message.rs")); + } } include!(concat!(env!("OUT_DIR"), "/ffi_init.rs"));