Refactor call event
This commit is contained in:
parent
dfbdab7e95
commit
605858e14f
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 {
|
||||
17
proto/patchbukkit/bridge.proto
Normal file
17
proto/patchbukkit/bridge.proto
Normal file
@ -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);
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
@ -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<Abilities> {
|
||||
let ctx = CALLBACK_CONTEXT.get()?;
|
||||
|
||||
@ -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<CallEventResponse> {
|
||||
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)
|
||||
}
|
||||
|
||||
@ -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<()> {
|
||||
|
||||
@ -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()?,
|
||||
|
||||
@ -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"));
|
||||
|
||||
Loading…
Reference in New Issue
Block a user