From ab9e2f4f82cc54c9c7c9e234dff6c9dde9f3e4c5 Mon Sep 17 00:00:00 2001 From: yunuservices Date: Wed, 4 Feb 2026 20:12:44 +0300 Subject: [PATCH 01/56] Add core player event bridge --- .../org/patchbukkit/bridge/BridgeUtils.java | 43 ++++ .../events/PatchBukkitEventFactory.java | 101 ++++++++++ .../events/PatchBukkitEventManager.java | 49 +++++ proto/patchbukkit/events/event.proto | 4 + proto/patchbukkit/events/player_events.proto | 22 +++ rust/src/events/handler.rs | 185 +++++++++++++++++- rust/src/java/native_callbacks/events.rs | 128 ++++++++++++ 7 files changed, 530 insertions(+), 2 deletions(-) diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/bridge/BridgeUtils.java b/java/patchbukkit/src/main/java/org/patchbukkit/bridge/BridgeUtils.java index 083a548..bf3b8b8 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/bridge/BridgeUtils.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/bridge/BridgeUtils.java @@ -1,5 +1,8 @@ package org.patchbukkit.bridge; +import org.bukkit.Location; +import org.patchbukkit.world.PatchBukkitWorld; + import java.util.UUID; public class BridgeUtils { @@ -10,4 +13,44 @@ public static UUID convertUuid(patchbukkit.common.UUID uuid) { public static patchbukkit.common.UUID convertUuid(UUID uuid) { return patchbukkit.common.UUID.newBuilder().setValue(uuid.toString()).build(); } + + public static Location convertLocation(patchbukkit.common.Location location) { + if (location == null || location.getWorld() == null || location.getWorld().getUuid() == null) { + return null; + } + + var world = PatchBukkitWorld.getOrCreate(convertUuid(location.getWorld().getUuid())); + var position = location.getPosition(); + if (position == null) { + return null; + } + + return new Location( + world, + position.getX(), + position.getY(), + position.getZ(), + location.getYaw(), + location.getPitch() + ); + } + + public static patchbukkit.common.Location convertLocation(Location location) { + if (location == null || location.getWorld() == null) { + return null; + } + + return patchbukkit.common.Location.newBuilder() + .setWorld(patchbukkit.common.World.newBuilder() + .setUuid(convertUuid(location.getWorld().getUID())) + .build()) + .setPosition(patchbukkit.common.Vec3.newBuilder() + .setX(location.getX()) + .setY(location.getY()) + .setZ(location.getZ()) + .build()) + .setYaw(location.getYaw()) + .setPitch(location.getPitch()) + .build(); + } } diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index 14c24f1..e2ec102 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -5,14 +5,24 @@ import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; import org.bukkit.Bukkit; +import org.bukkit.Location; import org.bukkit.entity.Player; +import org.bukkit.event.player.AsyncPlayerChatEvent; +import org.bukkit.event.player.PlayerCommandPreprocessEvent; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.event.player.PlayerQuitEvent; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.patchbukkit.bridge.BridgeUtils; import patchbukkit.common.UUID; import patchbukkit.events.Event; import patchbukkit.events.FireEventResponse; +import patchbukkit.events.PlayerChatEvent; +import patchbukkit.events.PlayerCommandEvent; import patchbukkit.events.PlayerJoinEvent; +import patchbukkit.events.PlayerLeaveEvent; +import java.util.HashSet; import java.util.logging.Logger; public class PatchBukkitEventFactory { @@ -42,6 +52,51 @@ public static org.bukkit.event.Event createEvent(@NotNull Event event) { Component joinMessage = GsonComponentSerializer.gson().deserialize(joinEvent.getJoinMessage()); yield new org.bukkit.event.player.PlayerJoinEvent(player, joinMessage); } + case PLAYER_LEAVE -> { + PlayerLeaveEvent leaveEvent = event.getPlayerLeave(); + Player player = getPlayer(leaveEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + + Component leaveMessage = GsonComponentSerializer.gson().deserialize(leaveEvent.getLeaveMessage()); + yield new PlayerQuitEvent(player, leaveMessage); + } + case PLAYER_MOVE -> { + patchbukkit.events.PlayerMoveEvent moveEvent = event.getPlayerMove(); + Player player = getPlayer(moveEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + + Location from = BridgeUtils.convertLocation(moveEvent.getFrom()); + Location to = BridgeUtils.convertLocation(moveEvent.getTo()); + if (from == null || to == null) yield null; + + yield new PlayerMoveEvent(player, from, to); + } + case PLAYER_CHAT -> { + PlayerChatEvent chatEvent = event.getPlayerChat(); + Player player = getPlayer(chatEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + + var recipients = new HashSet(); + if (chatEvent.getRecipientsList().isEmpty()) { + recipients.addAll(Bukkit.getOnlinePlayers()); + } else { + for (UUID recipient : chatEvent.getRecipientsList()) { + Player recipientPlayer = getPlayer(recipient.getValue()); + if (recipientPlayer != null) { + recipients.add(recipientPlayer); + } + } + } + + yield new AsyncPlayerChatEvent(false, player, chatEvent.getMessage(), recipients); + } + case PLAYER_COMMAND -> { + PlayerCommandEvent commandEvent = event.getPlayerCommand(); + Player player = getPlayer(commandEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + + yield new PlayerCommandPreprocessEvent(player, commandEvent.getCommand()); + } case DATA_NOT_SET -> { LOGGER.warning("EventFactory: Received Event with no data"); yield null; @@ -69,6 +124,52 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .setJoinMessage(joinMessage) .build() ); + } else if (event instanceof PlayerQuitEvent quitEvent) { + String quitMessage = GsonComponentSerializer.gson().serialize(quitEvent.quitMessage()); + + eventBuilder.setPlayerLeave( + PlayerLeaveEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(quitEvent.getPlayer().getUniqueId().toString()) + .build()) + .setLeaveMessage(quitMessage) + .build() + ); + } else if (event instanceof PlayerMoveEvent moveEvent) { + eventBuilder.setPlayerMove( + patchbukkit.events.PlayerMoveEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(moveEvent.getPlayer().getUniqueId().toString()) + .build()) + .setFrom(BridgeUtils.convertLocation(moveEvent.getFrom())) + .setTo(BridgeUtils.convertLocation(moveEvent.getTo())) + .build() + ); + } else if (event instanceof AsyncPlayerChatEvent chatEvent) { + var playerEventBuilder = patchbukkit.events.PlayerChatEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(chatEvent.getPlayer().getUniqueId().toString()) + .build()) + .setMessage(chatEvent.getMessage()); + + for (Player recipient : chatEvent.getRecipients()) { + playerEventBuilder.addRecipients( + UUID.newBuilder() + .setValue(recipient.getUniqueId().toString()) + .build() + ); + } + + eventBuilder.setPlayerChat(playerEventBuilder.build()); + } else if (event instanceof PlayerCommandPreprocessEvent commandEvent) { + eventBuilder.setPlayerCommand( + PlayerCommandEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(commandEvent.getPlayer().getUniqueId().toString()) + .build()) + .setCommand(commandEvent.getMessage()) + .build() + ); } builder.setData(eventBuilder.build()); 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 ba94bfa..da4f084 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -21,7 +21,11 @@ import org.jetbrains.annotations.NotNull; import patchbukkit.bridge.NativeBridgeFfi; import patchbukkit.events.CallEventRequest; +import patchbukkit.events.PlayerChatEvent; +import patchbukkit.events.PlayerCommandEvent; import patchbukkit.events.PlayerJoinEvent; +import patchbukkit.events.PlayerLeaveEvent; +import patchbukkit.events.PlayerMoveEvent; import patchbukkit.events.RegisterEventRequest; import java.lang.reflect.Method; @@ -59,6 +63,51 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.player.PlayerQuitEvent": + var quitEvent = (org.bukkit.event.player.PlayerQuitEvent) event; + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerLeave( + PlayerLeaveEvent.newBuilder() + .setLeaveMessage(quitEvent.quitMessage().toString()) + .setPlayerUuid(BridgeUtils.convertUuid(quitEvent.getPlayer().getUniqueId())).build() + ).build() + ); + break; + case "org.bukkit.event.player.PlayerMoveEvent": + var moveEvent = (org.bukkit.event.player.PlayerMoveEvent) event; + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerMove( + PlayerMoveEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(moveEvent.getPlayer().getUniqueId())) + .setFrom(BridgeUtils.convertLocation(moveEvent.getFrom())) + .setTo(BridgeUtils.convertLocation(moveEvent.getTo())) + .build() + ).build() + ); + break; + case "org.bukkit.event.player.AsyncPlayerChatEvent": + var chatEvent = (org.bukkit.event.player.AsyncPlayerChatEvent) event; + var chatBuilder = PlayerChatEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(chatEvent.getPlayer().getUniqueId())) + .setMessage(chatEvent.getMessage()); + for (var recipient : chatEvent.getRecipients()) { + chatBuilder.addRecipients(BridgeUtils.convertUuid(recipient.getUniqueId())); + } + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerChat(chatBuilder.build()).build() + ); + break; + case "org.bukkit.event.player.PlayerCommandPreprocessEvent": + var commandEvent = (org.bukkit.event.player.PlayerCommandPreprocessEvent) event; + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerCommand( + PlayerCommandEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(commandEvent.getPlayer().getUniqueId())) + .setCommand(commandEvent.getMessage()) + .build() + ).build() + ); + break; } var response = NativeBridgeFfi.callEvent(request.build()); diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index f678892..762bc03 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -11,6 +11,10 @@ option java_package = "patchbukkit.events"; message Event { oneof data { PlayerJoinEvent player_join = 1; + PlayerLeaveEvent player_leave = 2; + PlayerMoveEvent player_move = 3; + PlayerChatEvent player_chat = 4; + PlayerCommandEvent player_command = 5; } } diff --git a/proto/patchbukkit/events/player_events.proto b/proto/patchbukkit/events/player_events.proto index cd92e96..d79bdb6 100644 --- a/proto/patchbukkit/events/player_events.proto +++ b/proto/patchbukkit/events/player_events.proto @@ -10,3 +10,25 @@ message PlayerJoinEvent { patchbukkit.common.UUID player_uuid = 1; string join_message = 2; } + +message PlayerLeaveEvent { + patchbukkit.common.UUID player_uuid = 1; + string leave_message = 2; +} + +message PlayerMoveEvent { + patchbukkit.common.UUID player_uuid = 1; + patchbukkit.common.Location from = 2; + patchbukkit.common.Location to = 3; +} + +message PlayerChatEvent { + patchbukkit.common.UUID player_uuid = 1; + string message = 2; + repeated patchbukkit.common.UUID recipients = 3; +} + +message PlayerCommandEvent { + patchbukkit.common.UUID player_uuid = 1; + string command = 2; +} diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index b41e374..cfff07b 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -6,12 +6,15 @@ use pumpkin::entity::player::Player; use pumpkin::plugin::{BoxFuture, Cancellable, EventHandler, Payload}; use pumpkin::server::Server; use pumpkin_api_macros::with_runtime; +use pumpkin_util::math::vector3::Vector3; use tokio::sync::{mpsc, oneshot}; use crate::java::jvm::commands::JvmCommand; -use crate::proto::patchbukkit::common::Uuid; +use crate::proto::patchbukkit::common::{Location, Uuid, Vec3, World}; use crate::proto::patchbukkit::events::event::Data; -use crate::proto::patchbukkit::events::{Event, PlayerJoinEvent}; +use crate::proto::patchbukkit::events::{ + Event, PlayerChatEvent, PlayerCommandEvent, PlayerJoinEvent, PlayerLeaveEvent, PlayerMoveEvent, +}; pub struct EventContext { pub server: Arc, @@ -52,12 +55,190 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_join::PlayerJoinEvent self.join_message = serde_json::from_str(&event.join_message).ok()?; server.get_player_by_uuid(uuid::Uuid::from_str(&event.player_uuid?.value).ok()?)?; } + _ => {} } Some(()) } } +impl PatchBukkitEvent for pumpkin::plugin::player::player_leave::PlayerLeaveEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerLeave(PlayerLeaveEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + leave_message: serde_json::to_string(&self.leave_message).unwrap(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerLeave(event) => { + self.leave_message = serde_json::from_str(&event.leave_message).ok()?; + server.get_player_by_uuid(uuid::Uuid::from_str(&event.player_uuid?.value).ok()?)?; + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_move::PlayerMoveEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let world_uuid = self.player.world().uuid; + let yaw = self.player.living_entity.entity.yaw.load(); + let pitch = self.player.living_entity.entity.pitch.load(); + + JvmEventPayload { + event: Event { + data: Some(Data::PlayerMove(PlayerMoveEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + from: Some(build_location(world_uuid, &self.from, yaw, pitch)), + to: Some(build_location(world_uuid, &self.to, yaw, pitch)), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerMove(event) => { + server.get_player_by_uuid(uuid::Uuid::from_str(&event.player_uuid?.value).ok()?)?; + if let Some(from) = event.from { + if let Some(from_vec) = location_to_vec3(from) { + self.from = from_vec; + } + } + if let Some(to) = event.to { + if let Some(to_vec) = location_to_vec3(to) { + self.to = to_vec; + } + } + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_chat::PlayerChatEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let recipients = self + .recipients + .iter() + .map(|player| Uuid { + value: player.gameprofile.id.to_string(), + }) + .collect(); + + JvmEventPayload { + event: Event { + data: Some(Data::PlayerChat(PlayerChatEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + message: self.message.clone(), + recipients, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerChat(event) => { + self.message = event.message; + if !event.recipients.is_empty() { + let mut recipients = Vec::new(); + for recipient in event.recipients { + let uuid = uuid::Uuid::from_str(&recipient.value).ok()?; + if let Some(player) = server.get_player_by_uuid(uuid) { + recipients.push(player); + } + } + self.recipients = recipients; + } + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_command_send::PlayerCommandSendEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerCommand(PlayerCommandEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + command: self.command.clone(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerCommand(event) => { + self.command = event.command; + } + _ => {} + } + + Some(()) + } +} + +fn build_location(world_uuid: uuid::Uuid, position: &Vector3, yaw: f32, pitch: f32) -> Location { + Location { + world: Some(World { + uuid: Some(Uuid { + value: world_uuid.to_string(), + }), + }), + position: Some(Vec3 { + x: position.x, + y: position.y, + z: position.z, + }), + yaw, + pitch, + } +} + +fn location_to_vec3(location: Location) -> Option> { + let pos = location.position?; + Some(Vector3::new(pos.x, pos.y, pos.z)) +} + pub struct PatchBukkitEventHandler { plugin_name: String, command_tx: mpsc::Sender, diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index 3b5fa28..e7ecf10 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -1,7 +1,12 @@ use std::sync::Arc; use pumpkin::plugin::EventPriority; +use pumpkin::plugin::player::player_chat::PlayerChatEvent; +use pumpkin::plugin::player::player_command_send::PlayerCommandSendEvent; use pumpkin::plugin::player::player_join::PlayerJoinEvent; +use pumpkin::plugin::player::player_leave::PlayerLeaveEvent; +use pumpkin::plugin::player::player_move::PlayerMoveEvent; +use pumpkin_util::math::vector3::Vector3; use pumpkin_util::text::TextComponent; use crate::events::handler::PatchBukkitEventHandler; @@ -50,6 +55,68 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.player.PlayerQuitEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_leave::PlayerLeaveEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerMoveEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_move::PlayerMoveEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.AsyncPlayerChatEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_chat::PlayerChatEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerCommandPreprocessEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_command_send::PlayerCommandSendEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_command_send::PlayerCommandSendEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } _ => { log::warn!( "Unsupported Bukkit event type '{}' from plugin '{}'", @@ -84,6 +151,67 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let uuid = + uuid::Uuid::parse_str(&player_leave_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let pumpkin_event = PlayerLeaveEvent::new( + player, + TextComponent::from_legacy_string(&player_leave_event_data.leave_message), + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerMove(player_move_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_move_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let from = player_move_event_data.from?.position?; + let to = player_move_event_data.to?.position?; + let pumpkin_event = PlayerMoveEvent::new( + player, + Vector3::new(from.x, from.y, from.z), + Vector3::new(to.x, to.y, to.z), + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerChat(player_chat_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_chat_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let mut recipients = Vec::new(); + if player_chat_event_data.recipients.is_empty() { + recipients = context.server.get_all_players(); + } else { + for recipient in player_chat_event_data.recipients { + if let Ok(uuid) = uuid::Uuid::parse_str(&recipient.value) { + if let Some(recipient_player) = + context.server.get_player_by_uuid(uuid) + { + recipients.push(recipient_player); + } + } + } + } + + let pumpkin_event = PlayerChatEvent::new( + player, + player_chat_event_data.message, + recipients, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerCommand(player_command_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_command_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let pumpkin_event = + PlayerCommandSendEvent::new(player, player_command_event_data.command); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } } }) })?; From a1f66a350c812c6df8fdd5f90ad8085f71820f33 Mon Sep 17 00:00:00 2001 From: yunuservices Date: Wed, 4 Feb 2026 20:19:18 +0300 Subject: [PATCH 02/56] Add server command and broadcast events --- .../events/PatchBukkitEventFactory.java | 32 ++++++++++ .../events/PatchBukkitEventManager.java | 27 ++++++++ proto/patchbukkit/events/event.proto | 3 + proto/patchbukkit/events/server_events.proto | 16 +++++ rust/src/events/handler.rs | 62 +++++++++++++++++++ rust/src/java/native_callbacks/events.rs | 55 ++++++++++++++++ 6 files changed, 195 insertions(+) create mode 100644 proto/patchbukkit/events/server_events.proto diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index e2ec102..f63adbc 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -11,9 +11,12 @@ import org.bukkit.event.player.PlayerCommandPreprocessEvent; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.server.BroadcastMessageEvent; +import org.bukkit.event.server.ServerCommandEvent; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.patchbukkit.bridge.BridgeUtils; +import org.patchbukkit.command.PatchBukkitConsoleCommandSender; import patchbukkit.common.UUID; import patchbukkit.events.Event; import patchbukkit.events.FireEventResponse; @@ -97,6 +100,16 @@ public static org.bukkit.event.Event createEvent(@NotNull Event event) { yield new PlayerCommandPreprocessEvent(player, commandEvent.getCommand()); } + case SERVER_COMMAND -> { + patchbukkit.events.ServerCommandEvent commandEvent = event.getServerCommand(); + yield new ServerCommandEvent(new PatchBukkitConsoleCommandSender(), commandEvent.getCommand()); + } + case SERVER_BROADCAST -> { + patchbukkit.events.ServerBroadcastEvent broadcastEvent = event.getServerBroadcast(); + Component messageComponent = GsonComponentSerializer.gson().deserialize(broadcastEvent.getMessage()); + String message = PlainTextComponentSerializer.plainText().serialize(messageComponent); + yield new BroadcastMessageEvent(message); + } case DATA_NOT_SET -> { LOGGER.warning("EventFactory: Received Event with no data"); yield null; @@ -170,6 +183,25 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .setCommand(commandEvent.getMessage()) .build() ); + } else if (event instanceof ServerCommandEvent commandEvent) { + eventBuilder.setServerCommand( + patchbukkit.events.ServerCommandEvent.newBuilder() + .setCommand(commandEvent.getCommand()) + .build() + ); + } else if (event instanceof BroadcastMessageEvent broadcastEvent) { + String messageJson = GsonComponentSerializer.gson().serialize( + net.kyori.adventure.text.Component.text(broadcastEvent.getMessage()) + ); + String senderJson = GsonComponentSerializer.gson().serialize( + net.kyori.adventure.text.Component.text("") + ); + eventBuilder.setServerBroadcast( + patchbukkit.events.ServerBroadcastEvent.newBuilder() + .setMessage(messageJson) + .setSender(senderJson) + .build() + ); } builder.setData(eventBuilder.build()); 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 da4f084..fa9dcec 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -13,6 +13,8 @@ import org.bukkit.plugin.Plugin; import org.bukkit.plugin.RegisteredListener; import org.patchbukkit.bridge.BridgeUtils; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import com.google.common.collect.Sets; @@ -26,6 +28,8 @@ import patchbukkit.events.PlayerJoinEvent; import patchbukkit.events.PlayerLeaveEvent; import patchbukkit.events.PlayerMoveEvent; +import patchbukkit.events.ServerBroadcastEvent; +import patchbukkit.events.ServerCommandEvent; import patchbukkit.events.RegisterEventRequest; import java.lang.reflect.Method; @@ -108,6 +112,29 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.server.ServerCommandEvent": + var serverCommandEvent = (org.bukkit.event.server.ServerCommandEvent) event; + request.setEvent( + patchbukkit.events.Event.newBuilder().setServerCommand( + ServerCommandEvent.newBuilder() + .setCommand(serverCommandEvent.getCommand()) + .build() + ).build() + ); + break; + case "org.bukkit.event.server.BroadcastMessageEvent": + var broadcastEvent = (org.bukkit.event.server.BroadcastMessageEvent) event; + String messageJson = GsonComponentSerializer.gson().serialize(Component.text(broadcastEvent.getMessage())); + String senderJson = GsonComponentSerializer.gson().serialize(Component.text("")); + request.setEvent( + patchbukkit.events.Event.newBuilder().setServerBroadcast( + ServerBroadcastEvent.newBuilder() + .setMessage(messageJson) + .setSender(senderJson) + .build() + ).build() + ); + break; } var response = NativeBridgeFfi.callEvent(request.build()); diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index 762bc03..b1c50e0 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -4,6 +4,7 @@ package patchbukkit.events; import "patchbukkit/common/types.proto"; import "patchbukkit/events/player_events.proto"; +import "patchbukkit/events/server_events.proto"; option java_multiple_files = true; option java_package = "patchbukkit.events"; @@ -15,6 +16,8 @@ message Event { PlayerMoveEvent player_move = 3; PlayerChatEvent player_chat = 4; PlayerCommandEvent player_command = 5; + ServerCommandEvent server_command = 6; + ServerBroadcastEvent server_broadcast = 7; } } diff --git a/proto/patchbukkit/events/server_events.proto b/proto/patchbukkit/events/server_events.proto new file mode 100644 index 0000000..bba90a8 --- /dev/null +++ b/proto/patchbukkit/events/server_events.proto @@ -0,0 +1,16 @@ +syntax = "proto3"; +package patchbukkit.events; + +import "patchbukkit/common/types.proto"; + +option java_multiple_files = true; +option java_package = "patchbukkit.events"; + +message ServerCommandEvent { + string command = 1; +} + +message ServerBroadcastEvent { + string message = 1; + string sender = 2; +} diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index cfff07b..a5336ae 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -7,6 +7,7 @@ use pumpkin::plugin::{BoxFuture, Cancellable, EventHandler, Payload}; use pumpkin::server::Server; use pumpkin_api_macros::with_runtime; use pumpkin_util::math::vector3::Vector3; +use pumpkin_util::text::TextComponent; use tokio::sync::{mpsc, oneshot}; use crate::java::jvm::commands::JvmCommand; @@ -14,6 +15,7 @@ use crate::proto::patchbukkit::common::{Location, Uuid, Vec3, World}; use crate::proto::patchbukkit::events::event::Data; use crate::proto::patchbukkit::events::{ Event, PlayerChatEvent, PlayerCommandEvent, PlayerJoinEvent, PlayerLeaveEvent, PlayerMoveEvent, + ServerBroadcastEvent, ServerCommandEvent, }; pub struct EventContext { @@ -217,6 +219,66 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_command_send::PlayerCo } } +impl PatchBukkitEvent for pumpkin::plugin::server::server_command::ServerCommandEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::ServerCommand(ServerCommandEvent { + command: self.command.clone(), + })), + }, + context: EventContext { + server, + player: None, + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::ServerCommand(event) => { + self.command = event.command; + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::server::server_broadcast::ServerBroadcastEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::ServerBroadcast(ServerBroadcastEvent { + message: serde_json::to_string(&self.message).unwrap(), + sender: serde_json::to_string(&self.sender).unwrap(), + })), + }, + context: EventContext { + server, + player: None, + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::ServerBroadcast(event) => { + self.message = serde_json::from_str(&event.message).unwrap_or_else(|_| { + TextComponent::from_legacy_string(&event.message) + }); + self.sender = serde_json::from_str(&event.sender).unwrap_or_else(|_| { + TextComponent::from_legacy_string(&event.sender) + }); + } + _ => {} + } + + Some(()) + } +} + fn build_location(world_uuid: uuid::Uuid, position: &Vector3, yaw: f32, pitch: f32) -> Location { Location { world: Some(World { diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index e7ecf10..3b7eb26 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -6,6 +6,8 @@ use pumpkin::plugin::player::player_command_send::PlayerCommandSendEvent; use pumpkin::plugin::player::player_join::PlayerJoinEvent; use pumpkin::plugin::player::player_leave::PlayerLeaveEvent; use pumpkin::plugin::player::player_move::PlayerMoveEvent; +use pumpkin::plugin::server::server_broadcast::ServerBroadcastEvent; +use pumpkin::plugin::server::server_command::ServerCommandEvent; use pumpkin_util::math::vector3::Vector3; use pumpkin_util::text::TextComponent; @@ -117,6 +119,40 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.server.ServerCommandEvent" => { + context + .register_event::< + pumpkin::plugin::server::server_command::ServerCommandEvent, + PatchBukkitEventHandler< + pumpkin::plugin::server::server_command::ServerCommandEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.server.BroadcastMessageEvent" => { + context + .register_event::< + pumpkin::plugin::server::server_broadcast::ServerBroadcastEvent, + PatchBukkitEventHandler< + pumpkin::plugin::server::server_broadcast::ServerBroadcastEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } _ => { log::warn!( "Unsupported Bukkit event type '{}' from plugin '{}'", @@ -212,6 +248,25 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let pumpkin_event = + ServerCommandEvent::new(server_command_event_data.command); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::ServerBroadcast(server_broadcast_event_data) => { + let message = serde_json::from_str(&server_broadcast_event_data.message) + .unwrap_or_else(|_| { + TextComponent::from_legacy_string(&server_broadcast_event_data.message) + }); + let sender = serde_json::from_str(&server_broadcast_event_data.sender) + .unwrap_or_else(|_| { + TextComponent::from_legacy_string(&server_broadcast_event_data.sender) + }); + let pumpkin_event = ServerBroadcastEvent::new(message, sender); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } } }) })?; From 6d0b4552cd5bbdf99bde455ae1a623687c5856bf Mon Sep 17 00:00:00 2001 From: yunuservices Date: Wed, 4 Feb 2026 20:30:24 +0300 Subject: [PATCH 03/56] Add block and interact event bridge --- .../events/PatchBukkitEventFactory.java | 126 ++++++++++++++ .../events/PatchBukkitEventManager.java | 45 +++++ .../patchbukkit/world/PatchBukkitBlock.java | 129 +++++++++++++++ .../world/PatchBukkitBlockState.java | 72 ++++++++ .../patchbukkit/world/PatchBukkitWorld.java | 5 +- proto/patchbukkit/events/block_events.proto | 30 ++++ proto/patchbukkit/events/event.proto | 4 + rust/src/events/handler.rs | 155 +++++++++++++++++- rust/src/java/native_callbacks/events.rs | 139 ++++++++++++++++ 9 files changed, 699 insertions(+), 6 deletions(-) create mode 100644 java/patchbukkit/src/main/java/org/patchbukkit/world/PatchBukkitBlock.java create mode 100644 java/patchbukkit/src/main/java/org/patchbukkit/world/PatchBukkitBlockState.java create mode 100644 proto/patchbukkit/events/block_events.proto diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index f63adbc..f2d4a41 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -7,7 +7,10 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.Player; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.player.AsyncPlayerChatEvent; +import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerCommandPreprocessEvent; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerQuitEvent; @@ -17,6 +20,8 @@ import org.jetbrains.annotations.Nullable; import org.patchbukkit.bridge.BridgeUtils; import org.patchbukkit.command.PatchBukkitConsoleCommandSender; +import org.patchbukkit.world.PatchBukkitBlock; +import org.patchbukkit.world.PatchBukkitWorld; import patchbukkit.common.UUID; import patchbukkit.events.Event; import patchbukkit.events.FireEventResponse; @@ -100,6 +105,86 @@ public static org.bukkit.event.Event createEvent(@NotNull Event event) { yield new PlayerCommandPreprocessEvent(player, commandEvent.getCommand()); } + case PLAYER_INTERACT -> { + patchbukkit.events.PlayerInteractEvent interactEvent = event.getPlayerInteract(); + Player player = getPlayer(interactEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + + Location clicked = BridgeUtils.convertLocation(interactEvent.getClicked()); + org.bukkit.block.Block clickedBlock = null; + if (clicked != null && clicked.getWorld() instanceof PatchBukkitWorld world) { + clickedBlock = PatchBukkitBlock.create( + world, + clicked.getBlockX(), + clicked.getBlockY(), + clicked.getBlockZ(), + interactEvent.getBlockKey() + ); + } + + org.bukkit.event.block.Action action = + org.bukkit.event.block.Action.valueOf(interactEvent.getAction()); + yield new PlayerInteractEvent(player, action, null, clickedBlock, null); + } + case BLOCK_BREAK -> { + patchbukkit.events.BlockBreakEvent breakEvent = event.getBlockBreak(); + Player player = getPlayer(breakEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + + Location location = BridgeUtils.convertLocation(breakEvent.getLocation()); + if (location == null || !(location.getWorld() instanceof PatchBukkitWorld world)) { + yield null; + } + + org.bukkit.block.Block block = PatchBukkitBlock.create( + world, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ(), + breakEvent.getBlockKey() + ); + + BlockBreakEvent eventObj = new BlockBreakEvent(block, player); + eventObj.setExpToDrop(breakEvent.getExp()); + eventObj.setDropItems(breakEvent.getDrop()); + yield eventObj; + } + case BLOCK_PLACE -> { + patchbukkit.events.BlockPlaceEvent placeEvent = event.getBlockPlace(); + Player player = getPlayer(placeEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + + Location location = BridgeUtils.convertLocation(placeEvent.getLocation()); + if (location == null || !(location.getWorld() instanceof PatchBukkitWorld world)) { + yield null; + } + + org.bukkit.block.Block placed = PatchBukkitBlock.create( + world, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ(), + placeEvent.getBlockKey() + ); + org.bukkit.block.Block against = PatchBukkitBlock.create( + world, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ(), + placeEvent.getBlockAgainstKey() + ); + + BlockPlaceEvent eventObj = new BlockPlaceEvent( + placed, + placed.getState(), + against, + null, + player, + placeEvent.getCanBuild(), + null + ); + yield eventObj; + } case SERVER_COMMAND -> { patchbukkit.events.ServerCommandEvent commandEvent = event.getServerCommand(); yield new ServerCommandEvent(new PatchBukkitConsoleCommandSender(), commandEvent.getCommand()); @@ -183,6 +268,47 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .setCommand(commandEvent.getMessage()) .build() ); + } else if (event instanceof PlayerInteractEvent interactEvent) { + var block = interactEvent.getClickedBlock(); + var location = block != null ? block.getLocation() : null; + String blockKey = block != null ? block.getType().getKey().toString() : "minecraft:air"; + eventBuilder.setPlayerInteract( + patchbukkit.events.PlayerInteractEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(interactEvent.getPlayer().getUniqueId().toString()) + .build()) + .setAction(interactEvent.getAction().name()) + .setBlockKey(blockKey) + .setClicked(BridgeUtils.convertLocation(location)) + .build() + ); + } else if (event instanceof BlockBreakEvent breakEvent) { + var block = breakEvent.getBlock(); + eventBuilder.setBlockBreak( + patchbukkit.events.BlockBreakEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(breakEvent.getPlayer().getUniqueId().toString()) + .build()) + .setBlockKey(block.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(block.getLocation())) + .setExp(breakEvent.getExpToDrop()) + .setDrop(breakEvent.isDropItems()) + .build() + ); + } else if (event instanceof BlockPlaceEvent placeEvent) { + var block = placeEvent.getBlockPlaced(); + var against = placeEvent.getBlockAgainst(); + eventBuilder.setBlockPlace( + patchbukkit.events.BlockPlaceEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(placeEvent.getPlayer().getUniqueId().toString()) + .build()) + .setBlockKey(block.getType().getKey().toString()) + .setBlockAgainstKey(against.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(block.getLocation())) + .setCanBuild(placeEvent.canBuild()) + .build() + ); } else if (event instanceof ServerCommandEvent commandEvent) { eventBuilder.setServerCommand( patchbukkit.events.ServerCommandEvent.newBuilder() 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 fa9dcec..5e997da 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -30,6 +30,9 @@ import patchbukkit.events.PlayerMoveEvent; import patchbukkit.events.ServerBroadcastEvent; import patchbukkit.events.ServerCommandEvent; +import patchbukkit.events.BlockBreakEvent; +import patchbukkit.events.BlockPlaceEvent; +import patchbukkit.events.PlayerInteractEvent; import patchbukkit.events.RegisterEventRequest; import java.lang.reflect.Method; @@ -112,6 +115,48 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.player.PlayerInteractEvent": + var interactEvent = (org.bukkit.event.player.PlayerInteractEvent) event; + var clicked = interactEvent.getClickedBlock(); + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerInteract( + PlayerInteractEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(interactEvent.getPlayer().getUniqueId())) + .setAction(interactEvent.getAction().name()) + .setBlockKey(clicked != null ? clicked.getType().getKey().toString() : "minecraft:air") + .setClicked(BridgeUtils.convertLocation(clicked != null ? clicked.getLocation() : null)) + .build() + ).build() + ); + break; + case "org.bukkit.event.block.BlockBreakEvent": + var breakEvent = (org.bukkit.event.block.BlockBreakEvent) event; + request.setEvent( + patchbukkit.events.Event.newBuilder().setBlockBreak( + BlockBreakEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(breakEvent.getPlayer().getUniqueId())) + .setBlockKey(breakEvent.getBlock().getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(breakEvent.getBlock().getLocation())) + .setExp(breakEvent.getExpToDrop()) + .setDrop(breakEvent.isDropItems()) + .build() + ).build() + ); + break; + case "org.bukkit.event.block.BlockPlaceEvent": + var placeEvent = (org.bukkit.event.block.BlockPlaceEvent) event; + request.setEvent( + patchbukkit.events.Event.newBuilder().setBlockPlace( + BlockPlaceEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(placeEvent.getPlayer().getUniqueId())) + .setBlockKey(placeEvent.getBlockPlaced().getType().getKey().toString()) + .setBlockAgainstKey(placeEvent.getBlockAgainst().getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(placeEvent.getBlockPlaced().getLocation())) + .setCanBuild(placeEvent.canBuild()) + .build() + ).build() + ); + break; case "org.bukkit.event.server.ServerCommandEvent": var serverCommandEvent = (org.bukkit.event.server.ServerCommandEvent) event; request.setEvent( diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/world/PatchBukkitBlock.java b/java/patchbukkit/src/main/java/org/patchbukkit/world/PatchBukkitBlock.java new file mode 100644 index 0000000..aff60fe --- /dev/null +++ b/java/patchbukkit/src/main/java/org/patchbukkit/world/PatchBukkitBlock.java @@ -0,0 +1,129 @@ +package org.patchbukkit.world; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.Locale; + +public final class PatchBukkitBlock { + private PatchBukkitBlock() { + } + + public static Block create(PatchBukkitWorld world, int x, int y, int z, String blockKey) { + Material material = resolveMaterial(blockKey); + return (Block) Proxy.newProxyInstance( + PatchBukkitBlock.class.getClassLoader(), + new Class[]{Block.class}, + new Handler(world, x, y, z, material, blockKey) + ); + } + + static Material resolveMaterial(String blockKey) { + if (blockKey == null || blockKey.isBlank()) { + return Material.AIR; + } + + Material material = Material.matchMaterial(blockKey); + if (material != null) { + return material; + } + + String key = blockKey.contains(":") ? blockKey : "minecraft:" + blockKey; + material = Material.matchMaterial(key); + if (material != null) { + return material; + } + + String legacy = blockKey.replace("minecraft:", "").toUpperCase(Locale.ROOT); + material = Material.getMaterial(legacy); + return material != null ? material : Material.AIR; + } + + private static final class Handler implements InvocationHandler { + private final PatchBukkitWorld world; + private final int x; + private final int y; + private final int z; + private final Material material; + private final String blockKey; + + private Handler(PatchBukkitWorld world, int x, int y, int z, Material material, String blockKey) { + this.world = world; + this.x = x; + this.y = y; + this.z = z; + this.material = material; + this.blockKey = blockKey; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) { + String name = method.getName(); + switch (name) { + case "getWorld": + return world; + case "getX": + return x; + case "getY": + return y; + case "getZ": + return z; + case "getLocation": + return new Location(world, x, y, z); + case "getType": + return material; + case "getBlockData": + return material.createBlockData(); + case "getState": + return PatchBukkitBlockState.create(world, x, y, z, material, blockKey); + case "isEmpty": + return material.isAir(); + case "isLiquid": + return material.isLiquid(); + case "getRelative": + return getRelative(args); + case "getChunk": + throw new UnsupportedOperationException("Unimplemented method 'getChunk'"); + throw new UnsupportedOperationException("Unimplemented method '" + name + "'"); + case "equals": + return proxy == args[0]; + case "hashCode": + return System.identityHashCode(proxy); + case "toString": + return "PatchBukkitBlock{" + blockKey + " @ " + x + "," + y + "," + z + "}"; + default: + throw new UnsupportedOperationException("Unimplemented method '" + name + "'"); + } + } + + private Block getRelative(Object[] args) { + if (args == null || args.length == 0) { + return create(world, x, y, z, blockKey); + } + if (args.length == 1 && args[0] instanceof BlockFace face) { + return create(world, x + face.getModX(), y + face.getModY(), z + face.getModZ(), "minecraft:air"); + } + if (args.length == 2 && args[0] instanceof BlockFace face && args[1] instanceof Integer distance) { + return create( + world, + x + face.getModX() * distance, + y + face.getModY() * distance, + z + face.getModZ() * distance, + "minecraft:air" + ); + } + if (args.length == 3 + && args[0] instanceof Integer dx + && args[1] instanceof Integer dy + && args[2] instanceof Integer dz) { + return create(world, x + dx, y + dy, z + dz, "minecraft:air"); + } + throw new UnsupportedOperationException("Unimplemented method 'getRelative'"); + } + } +} diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/world/PatchBukkitBlockState.java b/java/patchbukkit/src/main/java/org/patchbukkit/world/PatchBukkitBlockState.java new file mode 100644 index 0000000..f160dce --- /dev/null +++ b/java/patchbukkit/src/main/java/org/patchbukkit/world/PatchBukkitBlockState.java @@ -0,0 +1,72 @@ +package org.patchbukkit.world; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.block.BlockState; +import org.bukkit.block.data.BlockData; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; + +public final class PatchBukkitBlockState { + private PatchBukkitBlockState() { + } + + public static BlockState create(PatchBukkitWorld world, int x, int y, int z, Material material, String blockKey) { + return (BlockState) Proxy.newProxyInstance( + PatchBukkitBlockState.class.getClassLoader(), + new Class[]{BlockState.class}, + new Handler(world, x, y, z, material, blockKey) + ); + } + + private static final class Handler implements InvocationHandler { + private final PatchBukkitWorld world; + private final int x; + private final int y; + private final int z; + private final Material material; + private final String blockKey; + + private Handler(PatchBukkitWorld world, int x, int y, int z, Material material, String blockKey) { + this.world = world; + this.x = x; + this.y = y; + this.z = z; + this.material = material; + this.blockKey = blockKey; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) { + String name = method.getName(); + switch (name) { + case "getBlock": + return PatchBukkitBlock.create(world, x, y, z, blockKey); + case "getWorld": + return world; + case "getLocation": + return new Location(world, x, y, z); + case "getX": + return x; + case "getY": + return y; + case "getZ": + return z; + case "getType": + return material; + case "getBlockData": + return material.createBlockData(); + case "update": + return false; + case "toString": + return "PatchBukkitBlockState{" + blockKey + " @ " + x + "," + y + "," + z + "}"; + default: + throw new UnsupportedOperationException("Unimplemented method '" + name + "'"); + } + } + } +} diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/world/PatchBukkitWorld.java b/java/patchbukkit/src/main/java/org/patchbukkit/world/PatchBukkitWorld.java index e8c2c36..293316d 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/world/PatchBukkitWorld.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/world/PatchBukkitWorld.java @@ -149,10 +149,7 @@ public boolean hasStructureAt( @Override public @NotNull Block getBlockAt(int x, int y, int z) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException( - "Unimplemented method 'getBlockAt'" - ); + return PatchBukkitBlock.create(this, x, y, z, "minecraft:air"); } @Override diff --git a/proto/patchbukkit/events/block_events.proto b/proto/patchbukkit/events/block_events.proto new file mode 100644 index 0000000..cee859a --- /dev/null +++ b/proto/patchbukkit/events/block_events.proto @@ -0,0 +1,30 @@ +syntax = "proto3"; +package patchbukkit.events; + +import "patchbukkit/common/types.proto"; + +option java_multiple_files = true; +option java_package = "patchbukkit.events"; + +message BlockBreakEvent { + patchbukkit.common.UUID player_uuid = 1; + string block_key = 2; + patchbukkit.common.Location location = 3; + uint32 exp = 4; + bool drop = 5; +} + +message BlockPlaceEvent { + patchbukkit.common.UUID player_uuid = 1; + string block_key = 2; + string block_against_key = 3; + patchbukkit.common.Location location = 4; + bool can_build = 5; +} + +message PlayerInteractEvent { + patchbukkit.common.UUID player_uuid = 1; + string action = 2; + string block_key = 3; + patchbukkit.common.Location clicked = 4; +} diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index b1c50e0..2f32aaf 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -5,6 +5,7 @@ package patchbukkit.events; import "patchbukkit/common/types.proto"; import "patchbukkit/events/player_events.proto"; import "patchbukkit/events/server_events.proto"; +import "patchbukkit/events/block_events.proto"; option java_multiple_files = true; option java_package = "patchbukkit.events"; @@ -18,6 +19,9 @@ message Event { PlayerCommandEvent player_command = 5; ServerCommandEvent server_command = 6; ServerBroadcastEvent server_broadcast = 7; + BlockBreakEvent block_break = 8; + BlockPlaceEvent block_place = 9; + PlayerInteractEvent player_interact = 10; } } diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index a5336ae..81c2d76 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -6,6 +6,7 @@ use pumpkin::entity::player::Player; use pumpkin::plugin::{BoxFuture, Cancellable, EventHandler, Payload}; use pumpkin::server::Server; use pumpkin_api_macros::with_runtime; +use pumpkin_data::Block; use pumpkin_util::math::vector3::Vector3; use pumpkin_util::text::TextComponent; use tokio::sync::{mpsc, oneshot}; @@ -14,8 +15,8 @@ use crate::java::jvm::commands::JvmCommand; use crate::proto::patchbukkit::common::{Location, Uuid, Vec3, World}; use crate::proto::patchbukkit::events::event::Data; use crate::proto::patchbukkit::events::{ - Event, PlayerChatEvent, PlayerCommandEvent, PlayerJoinEvent, PlayerLeaveEvent, PlayerMoveEvent, - ServerBroadcastEvent, ServerCommandEvent, + BlockBreakEvent, BlockPlaceEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerJoinEvent, + PlayerLeaveEvent, PlayerMoveEvent, PlayerInteractEvent, ServerBroadcastEvent, ServerCommandEvent, }; pub struct EventContext { @@ -219,6 +220,135 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_command_send::PlayerCo } } +impl PatchBukkitEvent for pumpkin::plugin::player::player_interact_event::PlayerInteractEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let world_uuid = self.player.world().uuid; + let yaw = self.player.living_entity.entity.yaw.load(); + let pitch = self.player.living_entity.entity.pitch.load(); + + let clicked = self.clicked_pos.map(|pos| { + build_location( + world_uuid, + &Vector3::new( + f64::from(pos.0.x), + f64::from(pos.0.y), + f64::from(pos.0.z), + ), + yaw, + pitch, + ) + }); + + JvmEventPayload { + event: Event { + data: Some(Data::PlayerInteract(PlayerInteractEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + action: interact_action_to_bukkit(&self.action), + block_key: block_to_key(self.block), + clicked, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, _data: Data) -> Option<()> { + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::block::block_break::BlockBreakEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let (player_uuid, world_uuid) = if let Some(player) = &self.player { + (player.gameprofile.id.to_string(), Some(player.world().uuid)) + } else { + ("00000000-0000-0000-0000-000000000000".to_string(), None) + }; + + let location = world_uuid.map(|world_uuid| { + build_location( + world_uuid, + &Vector3::new( + f64::from(self.block_position.0.x), + f64::from(self.block_position.0.y), + f64::from(self.block_position.0.z), + ), + 0.0, + 0.0, + ) + }); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockBreak(BlockBreakEvent { + player_uuid: Some(Uuid { value: player_uuid }), + block_key: block_to_key(self.block), + location, + exp: self.exp, + drop: self.drop, + })), + }, + context: EventContext { + server, + player: self.player.clone(), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::BlockBreak(event) => { + self.exp = event.exp; + self.drop = event.drop; + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::block::block_place::BlockPlaceEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let player_uuid = self.player.gameprofile.id.to_string(); + let world_uuid = self.player.world().uuid; + let position = self.player.position(); + let location = build_location(world_uuid, &position, 0.0, 0.0); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockPlace(BlockPlaceEvent { + player_uuid: Some(Uuid { value: player_uuid }), + block_key: block_to_key(self.block_placed), + block_against_key: block_to_key(self.block_placed_against), + location: Some(location), + can_build: self.can_build, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::BlockPlace(event) => { + self.can_build = event.can_build; + } + _ => {} + } + + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::server::server_command::ServerCommandEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { JvmEventPayload { @@ -301,6 +431,27 @@ fn location_to_vec3(location: Location) -> Option> { Some(Vector3::new(pos.x, pos.y, pos.z)) } +fn block_to_key(block: &Block) -> String { + format!("minecraft:{}", block.name) +} + +fn interact_action_to_bukkit(action: &pumpkin::plugin::player::player_interact_event::InteractAction) -> String { + match action { + pumpkin::plugin::player::player_interact_event::InteractAction::LeftClickBlock => { + "LEFT_CLICK_BLOCK".to_string() + } + pumpkin::plugin::player::player_interact_event::InteractAction::LeftClickAir => { + "LEFT_CLICK_AIR".to_string() + } + pumpkin::plugin::player::player_interact_event::InteractAction::RightClickAir => { + "RIGHT_CLICK_AIR".to_string() + } + pumpkin::plugin::player::player_interact_event::InteractAction::RightClickBlock => { + "RIGHT_CLICK_BLOCK".to_string() + } + } +} + pub struct PatchBukkitEventHandler { plugin_name: String, command_tx: mpsc::Sender, diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index 3b7eb26..f4f6257 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -1,15 +1,21 @@ use std::sync::Arc; use pumpkin::plugin::EventPriority; +use pumpkin::plugin::block::block_break::BlockBreakEvent; +use pumpkin::plugin::block::block_place::BlockPlaceEvent; use pumpkin::plugin::player::player_chat::PlayerChatEvent; use pumpkin::plugin::player::player_command_send::PlayerCommandSendEvent; +use pumpkin::plugin::player::player_interact_event::{InteractAction, PlayerInteractEvent}; use pumpkin::plugin::player::player_join::PlayerJoinEvent; use pumpkin::plugin::player::player_leave::PlayerLeaveEvent; use pumpkin::plugin::player::player_move::PlayerMoveEvent; use pumpkin::plugin::server::server_broadcast::ServerBroadcastEvent; use pumpkin::plugin::server::server_command::ServerCommandEvent; +use pumpkin_data::Block; +use pumpkin_world::item::ItemStack; use pumpkin_util::math::vector3::Vector3; use pumpkin_util::text::TextComponent; +use tokio::sync::Mutex; use crate::events::handler::PatchBukkitEventHandler; use crate::java::native_callbacks::CALLBACK_CONTEXT; @@ -119,6 +125,53 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.player.PlayerInteractEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_interact_event::PlayerInteractEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_interact_event::PlayerInteractEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.BlockBreakEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_break::BlockBreakEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.BlockPlaceEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_place::BlockPlaceEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.server.ServerCommandEvent" => { context .register_event::< @@ -248,6 +301,87 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let uuid = + uuid::Uuid::parse_str(&player_interact_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let action = match player_interact_event_data.action.as_str() { + "LEFT_CLICK_BLOCK" => InteractAction::LeftClickBlock, + "LEFT_CLICK_AIR" => InteractAction::LeftClickAir, + "RIGHT_CLICK_BLOCK" => InteractAction::RightClickBlock, + "RIGHT_CLICK_AIR" => InteractAction::RightClickAir, + _ => InteractAction::RightClickAir, + }; + + let clicked_pos = player_interact_event_data + .clicked + .and_then(|loc| loc.position) + .map(|pos| { + pumpkin_util::math::position::BlockPos::new( + pos.x as i32, + pos.y as i32, + pos.z as i32, + ) + }); + + let block = block_from_key(&player_interact_event_data.block_key); + let item = Arc::new(Mutex::new(ItemStack::EMPTY.clone())); + + let pumpkin_event = PlayerInteractEvent::new( + &player, + action, + &item, + block, + clicked_pos, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::BlockBreak(block_break_event_data) => { + let uuid = uuid::Uuid::parse_str(&block_break_event_data.player_uuid?.value) + .ok()?; + let player = context.server.get_player_by_uuid(uuid); + let block = block_from_key(&block_break_event_data.block_key); + let position = block_break_event_data + .location + .and_then(|loc| loc.position) + .map(|pos| { + pumpkin_util::math::position::BlockPos::new( + pos.x as i32, + pos.y as i32, + pos.z as i32, + ) + }) + .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); + + let pumpkin_event = BlockBreakEvent::new( + player, + block, + position, + block_break_event_data.exp, + block_break_event_data.drop, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::BlockPlace(block_place_event_data) => { + let uuid = uuid::Uuid::parse_str(&block_place_event_data.player_uuid?.value) + .ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let block = block_from_key(&block_place_event_data.block_key); + let against = block_from_key(&block_place_event_data.block_against_key); + + let pumpkin_event = BlockPlaceEvent { + player, + block_placed: block, + block_placed_against: against, + can_build: block_place_event_data.can_build, + cancelled: false, + }; + + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } Data::ServerCommand(server_command_event_data) => { let pumpkin_event = ServerCommandEvent::new(server_command_event_data.command); @@ -273,3 +407,8 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option &'static Block { + let trimmed = key.strip_prefix("minecraft:").unwrap_or(key); + Block::from_registry_key(trimmed).unwrap_or(&Block::AIR) +} From f63621a86fbd3c63c05d904d0b4c7f5d106e146e Mon Sep 17 00:00:00 2001 From: yunuservices Date: Wed, 4 Feb 2026 20:35:33 +0300 Subject: [PATCH 04/56] Add native block lookup bridge --- .../patchbukkit/world/PatchBukkitWorld.java | 12 ++++++- proto/patchbukkit/block.proto | 18 +++++++++++ proto/patchbukkit/bridge.proto | 3 ++ rust/src/java/native_callbacks/block.rs | 32 +++++++++++++++++++ rust/src/java/native_callbacks/mod.rs | 3 ++ rust/src/proto/mod.rs | 4 +++ 6 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 proto/patchbukkit/block.proto create mode 100644 rust/src/java/native_callbacks/block.rs diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/world/PatchBukkitWorld.java b/java/patchbukkit/src/main/java/org/patchbukkit/world/PatchBukkitWorld.java index 293316d..fec1bd0 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/world/PatchBukkitWorld.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/world/PatchBukkitWorld.java @@ -149,7 +149,17 @@ public boolean hasStructureAt( @Override public @NotNull Block getBlockAt(int x, int y, int z) { - return PatchBukkitBlock.create(this, x, y, z, "minecraft:air"); + var request = patchbukkit.block.GetBlockRequest.newBuilder() + .setWorld(patchbukkit.common.World.newBuilder() + .setUuid(org.patchbukkit.bridge.BridgeUtils.convertUuid(this.uuid)) + .build()) + .setX(x) + .setY(y) + .setZ(z) + .build(); + var response = patchbukkit.bridge.NativeBridgeFfi.getBlock(request); + String blockKey = response != null ? response.getBlockKey() : "minecraft:air"; + return PatchBukkitBlock.create(this, x, y, z, blockKey); } @Override diff --git a/proto/patchbukkit/block.proto b/proto/patchbukkit/block.proto new file mode 100644 index 0000000..f3ab319 --- /dev/null +++ b/proto/patchbukkit/block.proto @@ -0,0 +1,18 @@ +syntax = "proto3"; +package patchbukkit.block; + +import "patchbukkit/common/types.proto"; + +option java_multiple_files = true; +option java_package = "patchbukkit.block"; + +message GetBlockRequest { + patchbukkit.common.World world = 1; + int32 x = 2; + int32 y = 3; + int32 z = 4; +} + +message GetBlockResponse { + string block_key = 1; +} diff --git a/proto/patchbukkit/bridge.proto b/proto/patchbukkit/bridge.proto index 5338248..fc835de 100644 --- a/proto/patchbukkit/bridge.proto +++ b/proto/patchbukkit/bridge.proto @@ -4,6 +4,7 @@ package patchbukkit.bridge; import "google/protobuf/empty.proto"; import "google/protobuf/wrappers.proto"; import "patchbukkit/abilities.proto"; +import "patchbukkit/block.proto"; import "patchbukkit/common/types.proto"; import "patchbukkit/events/event.proto"; import "patchbukkit/message.proto"; @@ -21,6 +22,8 @@ service NativeBridge { rpc GetLocation(patchbukkit.common.UUID) returns (patchbukkit.common.Location); + rpc GetBlock(patchbukkit.block.GetBlockRequest) returns (patchbukkit.block.GetBlockResponse); + rpc GetRegistryData(patchbukkit.registry.GetRegistryDataRequest) returns (patchbukkit.registry.GetRegistryDataResponse); rpc PlayerEntityPlaySound(patchbukkit.sound.PlayerEntityPlaySoundRequest) returns (google.protobuf.Empty); diff --git a/rust/src/java/native_callbacks/block.rs b/rust/src/java/native_callbacks/block.rs new file mode 100644 index 0000000..c4437a4 --- /dev/null +++ b/rust/src/java/native_callbacks/block.rs @@ -0,0 +1,32 @@ +use pumpkin_util::math::position::BlockPos; + +use crate::{ + java::native_callbacks::CALLBACK_CONTEXT, + proto::patchbukkit::{ + block::{GetBlockRequest, GetBlockResponse}, + }, +}; + +pub fn ffi_native_bridge_get_block_impl(request: GetBlockRequest) -> Option { + let ctx = CALLBACK_CONTEXT.get()?; + let world = request.world?; + let world_uuid = world.uuid?.value; + let world_uuid = uuid::Uuid::parse_str(&world_uuid).ok()?; + + let server = ctx.plugin_context.server.clone(); + let block_key = tokio::task::block_in_place(|| { + ctx.runtime.block_on(async move { + let world = server + .worlds + .load() + .iter() + .find(|world| world.uuid == world_uuid)? + .clone(); + let pos = BlockPos::new(request.x, request.y, request.z); + let block = world.get_block(&pos).await; + Some(format!("minecraft:{}", block.name)) + }) + })?; + + Some(GetBlockResponse { block_key }) +} diff --git a/rust/src/java/native_callbacks/mod.rs b/rust/src/java/native_callbacks/mod.rs index dc65f60..f889df9 100644 --- a/rust/src/java/native_callbacks/mod.rs +++ b/rust/src/java/native_callbacks/mod.rs @@ -22,6 +22,9 @@ pub use message::*; pub mod registry; pub use registry::*; +pub mod block; +pub use block::*; + pub mod sound; pub use sound::*; diff --git a/rust/src/proto/mod.rs b/rust/src/proto/mod.rs index 64a6435..abbd684 100644 --- a/rust/src/proto/mod.rs +++ b/rust/src/proto/mod.rs @@ -23,6 +23,10 @@ pub mod patchbukkit { include!(concat!(env!("OUT_DIR"), "/patchbukkit.registry.rs")); } + pub mod block { + include!(concat!(env!("OUT_DIR"), "/patchbukkit.block.rs")); + } + pub mod sound { include!(concat!(env!("OUT_DIR"), "/patchbukkit.sound.rs")); } From b91f9e8fff08d2a746a3a2269dd9eab8fccd9bcb Mon Sep 17 00:00:00 2001 From: yunuservices Date: Wed, 4 Feb 2026 20:40:47 +0300 Subject: [PATCH 05/56] Document GraalVM JVM compatibility --- README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/README.md b/README.md index b77184c..a3b1a3d 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,27 @@ A plugin for [PumpkinMC](https://pumpkinmc.org/) that adds support for [PaperMC] 4. **Initialize**: Restart PumpkinMC. This creates a new `patchbukkit/` directory in your server root. 5. **Add Plugins**: Drop your .jar plugin files (Paper/Spigot/Bukkit) into the newly created `patchbukkit/patchbukkit-plugins/` folder and restart. +## GraalVM (Ecosystem Compatibility) + +PatchBukkit is a **native Rust plugin** that embeds a JVM for Bukkit/Paper/Spigot plugins. For +maximum ecosystem compatibility, the recommended GraalVM usage is **JVM mode**, not native-image. + +**Recommended approach** +- Use GraalVM JDK as a drop-in replacement for a standard JDK. +- Keep plugins running on the JVM (dynamic classloading, reflection, JNI/FFM). + +**Why not native-image yet** +- Bukkit/Paper plugins rely heavily on dynamic classloading, reflection, and Java agents. +- PatchBukkit embeds a JVM and uses JNI/FFM; native-image would require extensive config + and compatibility work across the plugin ecosystem. + +**Suggested JVM flags (starting point)** +- `-XX:+UseG1GC` +- `-XX:+UseStringDeduplication` +- `-Dpolyglot.engine.WarnInterpreterOnly=false` + +These are general JVM tuning hints; validate against your workload. + ## Development If you wish to contribute to PatchBukkit, follow the following steps: From 0dc86cee4f75f78f17cef5b762031e3f96d752b1 Mon Sep 17 00:00:00 2001 From: yunuservices Date: Wed, 4 Feb 2026 20:56:34 +0300 Subject: [PATCH 06/56] Enhance interact and entity event bridge --- .../events/PatchBukkitEventFactory.java | 83 +++++++++++++- .../events/PatchBukkitEventManager.java | 45 ++++++++ proto/patchbukkit/events/block_events.proto | 2 + proto/patchbukkit/events/entity_events.proto | 23 ++++ proto/patchbukkit/events/event.proto | 4 + rust/Cargo.toml | 10 +- rust/src/events/handler.rs | 96 +++++++++++++++- rust/src/java/native_callbacks/events.rs | 108 +++++++++++++++++- 8 files changed, 361 insertions(+), 10 deletions(-) create mode 100644 proto/patchbukkit/events/entity_events.proto diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index f2d4a41..c09826f 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -16,12 +16,21 @@ import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.server.BroadcastMessageEvent; import org.bukkit.event.server.ServerCommandEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.event.entity.EntitySpawnEvent; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.patchbukkit.bridge.BridgeUtils; import org.patchbukkit.command.PatchBukkitConsoleCommandSender; import org.patchbukkit.world.PatchBukkitBlock; import org.patchbukkit.world.PatchBukkitWorld; +import org.patchbukkit.entity.PatchBukkitEntity; +import org.patchbukkit.entity.PatchBukkitLivingEntity; +import org.bukkit.block.BlockFace; +import org.bukkit.inventory.ItemStack; +import org.bukkit.Material; import patchbukkit.common.UUID; import patchbukkit.events.Event; import patchbukkit.events.FireEventResponse; @@ -124,7 +133,25 @@ public static org.bukkit.event.Event createEvent(@NotNull Event event) { org.bukkit.event.block.Action action = org.bukkit.event.block.Action.valueOf(interactEvent.getAction()); - yield new PlayerInteractEvent(player, action, null, clickedBlock, null); + ItemStack item = null; + if (!interactEvent.getItemKey().isEmpty()) { + Material material = Material.matchMaterial(interactEvent.getItemKey()); + if (material == null) { + material = Material.matchMaterial("minecraft:" + interactEvent.getItemKey()); + } + if (material != null) { + item = new ItemStack(material); + } + } + BlockFace face = null; + if (!interactEvent.getBlockFace().isEmpty()) { + try { + face = BlockFace.valueOf(interactEvent.getBlockFace()); + } catch (IllegalArgumentException ignored) { + face = null; + } + } + yield new PlayerInteractEvent(player, action, item, clickedBlock, face); } case BLOCK_BREAK -> { patchbukkit.events.BlockBreakEvent breakEvent = event.getBlockBreak(); @@ -185,6 +212,24 @@ public static org.bukkit.event.Event createEvent(@NotNull Event event) { ); yield eventObj; } + case ENTITY_SPAWN -> { + patchbukkit.events.EntitySpawnEvent spawnEvent = event.getEntitySpawn(); + java.util.UUID entityUuid = java.util.UUID.fromString(spawnEvent.getEntityUuid().getValue()); + PatchBukkitEntity entity = new PatchBukkitEntity(entityUuid, spawnEvent.getEntityType()); + yield new EntitySpawnEvent(entity); + } + case ENTITY_DAMAGE -> { + patchbukkit.events.EntityDamageEvent damageEvent = event.getEntityDamage(); + java.util.UUID entityUuid = java.util.UUID.fromString(damageEvent.getEntityUuid().getValue()); + PatchBukkitEntity entity = new PatchBukkitEntity(entityUuid, "Entity"); + yield new EntityDamageEvent(entity, DamageCause.CUSTOM, damageEvent.getDamage()); + } + case ENTITY_DEATH -> { + patchbukkit.events.EntityDeathEvent deathEvent = event.getEntityDeath(); + java.util.UUID entityUuid = java.util.UUID.fromString(deathEvent.getEntityUuid().getValue()); + PatchBukkitLivingEntity entity = new PatchBukkitLivingEntity(entityUuid, "Entity"); + yield new EntityDeathEvent(entity, java.util.Collections.emptyList(), 0); + } case SERVER_COMMAND -> { patchbukkit.events.ServerCommandEvent commandEvent = event.getServerCommand(); yield new ServerCommandEvent(new PatchBukkitConsoleCommandSender(), commandEvent.getCommand()); @@ -272,6 +317,12 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) var block = interactEvent.getClickedBlock(); var location = block != null ? block.getLocation() : null; String blockKey = block != null ? block.getType().getKey().toString() : "minecraft:air"; + String itemKey = interactEvent.getItem() != null + ? interactEvent.getItem().getType().getKey().toString() + : "minecraft:air"; + String face = interactEvent.getBlockFace() != null + ? interactEvent.getBlockFace().name() + : ""; eventBuilder.setPlayerInteract( patchbukkit.events.PlayerInteractEvent.newBuilder() .setPlayerUuid(UUID.newBuilder() @@ -279,6 +330,8 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .build()) .setAction(interactEvent.getAction().name()) .setBlockKey(blockKey) + .setItemKey(itemKey) + .setBlockFace(face) .setClicked(BridgeUtils.convertLocation(location)) .build() ); @@ -309,6 +362,34 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .setCanBuild(placeEvent.canBuild()) .build() ); + } else if (event instanceof EntitySpawnEvent spawnEvent) { + eventBuilder.setEntitySpawn( + patchbukkit.events.EntitySpawnEvent.newBuilder() + .setEntityUuid(UUID.newBuilder() + .setValue(spawnEvent.getEntity().getUniqueId().toString()) + .build()) + .setEntityType(spawnEvent.getEntity().getType().name()) + .build() + ); + } else if (event instanceof EntityDamageEvent damageEvent) { + eventBuilder.setEntityDamage( + patchbukkit.events.EntityDamageEvent.newBuilder() + .setEntityUuid(UUID.newBuilder() + .setValue(damageEvent.getEntity().getUniqueId().toString()) + .build()) + .setDamage((float) damageEvent.getFinalDamage()) + .setDamageType(damageEvent.getCause().name()) + .build() + ); + } else if (event instanceof EntityDeathEvent deathEvent) { + eventBuilder.setEntityDeath( + patchbukkit.events.EntityDeathEvent.newBuilder() + .setEntityUuid(UUID.newBuilder() + .setValue(deathEvent.getEntity().getUniqueId().toString()) + .build()) + .setDamageType("CUSTOM") + .build() + ); } else if (event instanceof ServerCommandEvent commandEvent) { eventBuilder.setServerCommand( patchbukkit.events.ServerCommandEvent.newBuilder() 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 5e997da..b006097 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -33,6 +33,9 @@ import patchbukkit.events.BlockBreakEvent; import patchbukkit.events.BlockPlaceEvent; import patchbukkit.events.PlayerInteractEvent; +import patchbukkit.events.EntitySpawnEvent; +import patchbukkit.events.EntityDamageEvent; +import patchbukkit.events.EntityDeathEvent; import patchbukkit.events.RegisterEventRequest; import java.lang.reflect.Method; @@ -118,6 +121,12 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { case "org.bukkit.event.player.PlayerInteractEvent": var interactEvent = (org.bukkit.event.player.PlayerInteractEvent) event; var clicked = interactEvent.getClickedBlock(); + String itemKey = interactEvent.getItem() != null + ? interactEvent.getItem().getType().getKey().toString() + : "minecraft:air"; + String face = interactEvent.getBlockFace() != null + ? interactEvent.getBlockFace().name() + : ""; request.setEvent( patchbukkit.events.Event.newBuilder().setPlayerInteract( PlayerInteractEvent.newBuilder() @@ -125,6 +134,8 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { .setAction(interactEvent.getAction().name()) .setBlockKey(clicked != null ? clicked.getType().getKey().toString() : "minecraft:air") .setClicked(BridgeUtils.convertLocation(clicked != null ? clicked.getLocation() : null)) + .setItemKey(itemKey) + .setBlockFace(face) .build() ).build() ); @@ -157,6 +168,40 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.entity.EntitySpawnEvent": + var spawnEvent = (org.bukkit.event.entity.EntitySpawnEvent) event; + request.setEvent( + patchbukkit.events.Event.newBuilder().setEntitySpawn( + EntitySpawnEvent.newBuilder() + .setEntityUuid(BridgeUtils.convertUuid(spawnEvent.getEntity().getUniqueId())) + .setEntityType(spawnEvent.getEntity().getType().name()) + .build() + ).build() + ); + break; + case "org.bukkit.event.entity.EntityDamageEvent": + var damageEvent = (org.bukkit.event.entity.EntityDamageEvent) event; + request.setEvent( + patchbukkit.events.Event.newBuilder().setEntityDamage( + EntityDamageEvent.newBuilder() + .setEntityUuid(BridgeUtils.convertUuid(damageEvent.getEntity().getUniqueId())) + .setDamage((float) damageEvent.getFinalDamage()) + .setDamageType(damageEvent.getCause().name()) + .build() + ).build() + ); + break; + case "org.bukkit.event.entity.EntityDeathEvent": + var deathEvent = (org.bukkit.event.entity.EntityDeathEvent) event; + request.setEvent( + patchbukkit.events.Event.newBuilder().setEntityDeath( + EntityDeathEvent.newBuilder() + .setEntityUuid(BridgeUtils.convertUuid(deathEvent.getEntity().getUniqueId())) + .setDamageType("CUSTOM") + .build() + ).build() + ); + break; case "org.bukkit.event.server.ServerCommandEvent": var serverCommandEvent = (org.bukkit.event.server.ServerCommandEvent) event; request.setEvent( diff --git a/proto/patchbukkit/events/block_events.proto b/proto/patchbukkit/events/block_events.proto index cee859a..d13a724 100644 --- a/proto/patchbukkit/events/block_events.proto +++ b/proto/patchbukkit/events/block_events.proto @@ -27,4 +27,6 @@ message PlayerInteractEvent { string action = 2; string block_key = 3; patchbukkit.common.Location clicked = 4; + string item_key = 5; + string block_face = 6; } diff --git a/proto/patchbukkit/events/entity_events.proto b/proto/patchbukkit/events/entity_events.proto new file mode 100644 index 0000000..85dd61c --- /dev/null +++ b/proto/patchbukkit/events/entity_events.proto @@ -0,0 +1,23 @@ +syntax = "proto3"; +package patchbukkit.events; + +import "patchbukkit/common/types.proto"; + +option java_multiple_files = true; +option java_package = "patchbukkit.events"; + +message EntitySpawnEvent { + patchbukkit.common.UUID entity_uuid = 1; + string entity_type = 2; +} + +message EntityDamageEvent { + patchbukkit.common.UUID entity_uuid = 1; + float damage = 2; + string damage_type = 3; +} + +message EntityDeathEvent { + patchbukkit.common.UUID entity_uuid = 1; + string damage_type = 2; +} diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index 2f32aaf..a06f8cc 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -6,6 +6,7 @@ import "patchbukkit/common/types.proto"; import "patchbukkit/events/player_events.proto"; import "patchbukkit/events/server_events.proto"; import "patchbukkit/events/block_events.proto"; +import "patchbukkit/events/entity_events.proto"; option java_multiple_files = true; option java_package = "patchbukkit.events"; @@ -22,6 +23,9 @@ message Event { BlockBreakEvent block_break = 8; BlockPlaceEvent block_place = 9; PlayerInteractEvent player_interact = 10; + EntitySpawnEvent entity_spawn = 11; + EntityDamageEvent entity_damage = 12; + EntityDeathEvent entity_death = 13; } } diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 65178bf..39fc8e0 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -9,11 +9,11 @@ build = "build/main.rs" crate-type = ["cdylib"] [dependencies] -pumpkin = { git = "https://github.com/Pumpkin-MC/Pumpkin.git", branch = "master", package = "pumpkin" } -pumpkin-data = { git = "https://github.com/Pumpkin-MC/Pumpkin.git", branch = "master", package = "pumpkin-data" } -pumpkin-protocol = { git = "https://github.com/Pumpkin-MC/Pumpkin.git", branch = "master", package = "pumpkin-protocol" } -pumpkin-util = { git = "https://github.com/Pumpkin-MC/Pumpkin.git", branch = "master", package = "pumpkin-util" } -pumpkin-api-macros = { git = "https://github.com/Pumpkin-MC/Pumpkin.git", branch = "master", package = "pumpkin-api-macros" } +pumpkin = { path = "../../Pumpkin/pumpkin", package = "pumpkin" } +pumpkin-data = { path = "../../Pumpkin/pumpkin-data", package = "pumpkin-data" } +pumpkin-protocol = { path = "../../Pumpkin/pumpkin-protocol", package = "pumpkin-protocol" } +pumpkin-util = { path = "../../Pumpkin/pumpkin-util", package = "pumpkin-util" } +pumpkin-api-macros = { path = "../../Pumpkin/pumpkin-api-macros", package = "pumpkin-api-macros" } tokio = "1" log = "0.4" diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index 81c2d76..f68b899 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -6,7 +6,7 @@ use pumpkin::entity::player::Player; use pumpkin::plugin::{BoxFuture, Cancellable, EventHandler, Payload}; use pumpkin::server::Server; use pumpkin_api_macros::with_runtime; -use pumpkin_data::Block; +use pumpkin_data::{Block, BlockDirection}; use pumpkin_util::math::vector3::Vector3; use pumpkin_util::text::TextComponent; use tokio::sync::{mpsc, oneshot}; @@ -17,6 +17,7 @@ use crate::proto::patchbukkit::events::event::Data; use crate::proto::patchbukkit::events::{ BlockBreakEvent, BlockPlaceEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerJoinEvent, PlayerLeaveEvent, PlayerMoveEvent, PlayerInteractEvent, ServerBroadcastEvent, ServerCommandEvent, + EntityDamageEvent, EntityDeathEvent, EntitySpawnEvent, }; pub struct EventContext { @@ -248,6 +249,8 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_interact_event::Player action: interact_action_to_bukkit(&self.action), block_key: block_to_key(self.block), clicked, + item_key: self.item_key.clone(), + block_face: block_face_to_bukkit(self.face), })), }, context: EventContext { @@ -317,8 +320,16 @@ impl PatchBukkitEvent for pumpkin::plugin::block::block_place::BlockPlaceEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { let player_uuid = self.player.gameprofile.id.to_string(); let world_uuid = self.player.world().uuid; - let position = self.player.position(); - let location = build_location(world_uuid, &position, 0.0, 0.0); + let location = build_location( + world_uuid, + &Vector3::new( + f64::from(self.position.0.x), + f64::from(self.position.0.y), + f64::from(self.position.0.z), + ), + 0.0, + 0.0, + ); JvmEventPayload { event: Event { @@ -349,6 +360,73 @@ impl PatchBukkitEvent for pumpkin::plugin::block::block_place::BlockPlaceEvent { } } +impl PatchBukkitEvent for pumpkin::plugin::entity::entity_spawn::EntitySpawnEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::EntitySpawn(EntitySpawnEvent { + entity_uuid: Some(Uuid { + value: self.entity_uuid.to_string(), + }), + entity_type: self.entity_type.id.to_string(), + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, _data: Data) -> Option<()> { + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::entity::entity_damage::EntityDamageEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::EntityDamage(EntityDamageEvent { + entity_uuid: Some(Uuid { + value: self.entity_uuid.to_string(), + }), + damage: self.damage, + damage_type: self.damage_type.message_id.to_string(), + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::EntityDamage(event) => { + self.damage = event.damage; + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::entity::entity_death::EntityDeathEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::EntityDeath(EntityDeathEvent { + entity_uuid: Some(Uuid { + value: self.entity_uuid.to_string(), + }), + damage_type: self.damage_type.message_id.to_string(), + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, _data: Data) -> Option<()> { + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::server::server_command::ServerCommandEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { JvmEventPayload { @@ -452,6 +530,18 @@ fn interact_action_to_bukkit(action: &pumpkin::plugin::player::player_interact_e } } +fn block_face_to_bukkit(face: Option) -> String { + match face { + Some(BlockDirection::Up) => "UP".to_string(), + Some(BlockDirection::Down) => "DOWN".to_string(), + Some(BlockDirection::North) => "NORTH".to_string(), + Some(BlockDirection::South) => "SOUTH".to_string(), + Some(BlockDirection::West) => "WEST".to_string(), + Some(BlockDirection::East) => "EAST".to_string(), + None => String::new(), + } +} + pub struct PatchBukkitEventHandler { plugin_name: String, command_tx: mpsc::Sender, diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index f4f6257..4245fcc 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -12,6 +12,8 @@ use pumpkin::plugin::player::player_move::PlayerMoveEvent; use pumpkin::plugin::server::server_broadcast::ServerBroadcastEvent; use pumpkin::plugin::server::server_command::ServerCommandEvent; use pumpkin_data::Block; +use pumpkin_data::BlockDirection; +use pumpkin_data::item::Item; use pumpkin_world::item::ItemStack; use pumpkin_util::math::vector3::Vector3; use pumpkin_util::text::TextComponent; @@ -172,6 +174,51 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.entity.EntitySpawnEvent" => { + context + .register_event::< + pumpkin::plugin::entity::entity_spawn::EntitySpawnEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.entity.EntityDamageEvent" => { + context + .register_event::< + pumpkin::plugin::entity::entity_damage::EntityDamageEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.entity.EntityDeathEvent" => { + context + .register_event::< + pumpkin::plugin::entity::entity_death::EntityDeathEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.server.ServerCommandEvent" => { context .register_event::< @@ -325,14 +372,21 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option Option { + let uuid = uuid::Uuid::parse_str(&entity_spawn_event_data.entity_uuid?.value) + .ok()?; + let pumpkin_event = + pumpkin::plugin::entity::entity_spawn::EntitySpawnEvent::new( + uuid, + &pumpkin_data::entity::EntityType::PLAYER, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::EntityDamage(entity_damage_event_data) => { + let uuid = uuid::Uuid::parse_str(&entity_damage_event_data.entity_uuid?.value) + .ok()?; + let pumpkin_event = + pumpkin::plugin::entity::entity_damage::EntityDamageEvent::new( + uuid, + entity_damage_event_data.damage, + pumpkin_data::damage::DamageType::GENERIC, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::EntityDeath(entity_death_event_data) => { + let uuid = uuid::Uuid::parse_str(&entity_death_event_data.entity_uuid?.value) + .ok()?; + let pumpkin_event = + pumpkin::plugin::entity::entity_death::EntityDeathEvent::new( + uuid, + pumpkin_data::damage::DamageType::GENERIC, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } Data::ServerCommand(server_command_event_data) => { let pumpkin_event = ServerCommandEvent::new(server_command_event_data.command); @@ -412,3 +500,21 @@ fn block_from_key(key: &str) -> &'static Block { let trimmed = key.strip_prefix("minecraft:").unwrap_or(key); Block::from_registry_key(trimmed).unwrap_or(&Block::AIR) } + +fn item_from_key(key: &str) -> ItemStack { + let trimmed = key.strip_prefix("minecraft:").unwrap_or(key); + let item = Item::from_registry_key(trimmed).unwrap_or(&Item::AIR); + ItemStack::new(1, item) +} + +fn bukkit_block_face_to_direction(face: &str) -> Option { + match face { + "UP" => Some(BlockDirection::Up), + "DOWN" => Some(BlockDirection::Down), + "NORTH" => Some(BlockDirection::North), + "SOUTH" => Some(BlockDirection::South), + "WEST" => Some(BlockDirection::West), + "EAST" => Some(BlockDirection::East), + _ => None, + } +} From b3247727911fcc17d304076374c43ef7e0355f78 Mon Sep 17 00:00:00 2001 From: yunuservices Date: Wed, 4 Feb 2026 21:11:18 +0300 Subject: [PATCH 07/56] Add player login/teleport/world/gamemode event bridge --- .../events/PatchBukkitEventFactory.java | 130 +++++++++++++ .../events/PatchBukkitEventManager.java | 61 ++++++ proto/patchbukkit/events/event.proto | 28 +-- proto/patchbukkit/events/player_events.proto | 27 +++ rust/src/events/handler.rs | 181 ++++++++++++++++++ rust/src/java/native_callbacks/events.rs | 157 +++++++++++++++ 6 files changed, 572 insertions(+), 12 deletions(-) diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index c09826f..ed98ba5 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -12,6 +12,10 @@ import org.bukkit.event.player.AsyncPlayerChatEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerCommandPreprocessEvent; +import org.bukkit.event.player.PlayerLoginEvent; +import org.bukkit.event.player.PlayerTeleportEvent; +import org.bukkit.event.player.PlayerChangedWorldEvent; +import org.bukkit.event.player.PlayerGameModeChangeEvent; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.server.BroadcastMessageEvent; @@ -31,6 +35,8 @@ import org.bukkit.block.BlockFace; import org.bukkit.inventory.ItemStack; import org.bukkit.Material; +import org.bukkit.GameMode; +import java.net.InetAddress; import patchbukkit.common.UUID; import patchbukkit.events.Event; import patchbukkit.events.FireEventResponse; @@ -69,6 +75,18 @@ public static org.bukkit.event.Event createEvent(@NotNull Event event) { Component joinMessage = GsonComponentSerializer.gson().deserialize(joinEvent.getJoinMessage()); yield new org.bukkit.event.player.PlayerJoinEvent(player, joinMessage); } + case PLAYER_LOGIN -> { + patchbukkit.events.PlayerLoginEvent loginEvent = event.getPlayerLogin(); + Player player = getPlayer(loginEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + Component kickMessage = GsonComponentSerializer.gson().deserialize(loginEvent.getKickMessage()); + PlayerLoginEvent login = createLoginEvent(player); + if (login != null) { + login.setKickMessage(PlainTextComponentSerializer.plainText().serialize(kickMessage)); + yield login; + } + yield null; + } case PLAYER_LEAVE -> { PlayerLeaveEvent leaveEvent = event.getPlayerLeave(); Player player = getPlayer(leaveEvent.getPlayerUuid().getValue()); @@ -88,6 +106,47 @@ public static org.bukkit.event.Event createEvent(@NotNull Event event) { yield new PlayerMoveEvent(player, from, to); } + case PLAYER_TELEPORT -> { + patchbukkit.events.PlayerTeleportEvent teleportEvent = event.getPlayerTeleport(); + Player player = getPlayer(teleportEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + Location from = BridgeUtils.convertLocation(teleportEvent.getFrom()); + Location to = BridgeUtils.convertLocation(teleportEvent.getTo()); + if (from == null || to == null) yield null; + PlayerTeleportEvent.TeleportCause cause = PlayerTeleportEvent.TeleportCause.UNKNOWN; + if (!teleportEvent.getCause().isEmpty()) { + try { + cause = PlayerTeleportEvent.TeleportCause.valueOf(teleportEvent.getCause()); + } catch (IllegalArgumentException ignored) { + cause = PlayerTeleportEvent.TeleportCause.UNKNOWN; + } + } + yield new PlayerTeleportEvent(player, from, to, cause); + } + case PLAYER_CHANGE_WORLD -> { + patchbukkit.events.PlayerChangeWorldEvent changeEvent = event.getPlayerChangeWorld(); + Player player = getPlayer(changeEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + if (changeEvent.getPreviousWorld() == null || changeEvent.getPreviousWorld().getUuid() == null) { + yield null; + } + java.util.UUID prevUuid = java.util.UUID.fromString(changeEvent.getPreviousWorld().getUuid().getValue()); + yield new PlayerChangedWorldEvent(player, PatchBukkitWorld.getOrCreate(prevUuid)); + } + case PLAYER_GAMEMODE_CHANGE -> { + patchbukkit.events.PlayerGamemodeChangeEvent gmEvent = event.getPlayerGamemodeChange(); + Player player = getPlayer(gmEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + GameMode mode = GameMode.SURVIVAL; + if (!gmEvent.getNewGamemode().isEmpty()) { + try { + mode = GameMode.valueOf(gmEvent.getNewGamemode()); + } catch (IllegalArgumentException ignored) { + mode = GameMode.SURVIVAL; + } + } + yield new PlayerGameModeChangeEvent(player, mode); + } case PLAYER_CHAT -> { PlayerChatEvent chatEvent = event.getPlayerChat(); Player player = getPlayer(chatEvent.getPlayerUuid().getValue()); @@ -278,6 +337,19 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .setLeaveMessage(quitMessage) .build() ); + } else if (event instanceof PlayerLoginEvent loginEvent) { + String kickMessage = loginEvent.getKickMessage(); + if (kickMessage == null) { + kickMessage = ""; + } + eventBuilder.setPlayerLogin( + patchbukkit.events.PlayerLoginEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(loginEvent.getPlayer().getUniqueId().toString()) + .build()) + .setKickMessage(GsonComponentSerializer.gson().serialize(Component.text(kickMessage))) + .build() + ); } else if (event instanceof PlayerMoveEvent moveEvent) { eventBuilder.setPlayerMove( patchbukkit.events.PlayerMoveEvent.newBuilder() @@ -288,6 +360,48 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .setTo(BridgeUtils.convertLocation(moveEvent.getTo())) .build() ); + } else if (event instanceof PlayerTeleportEvent teleportEvent) { + String cause = teleportEvent.getCause() != null + ? teleportEvent.getCause().name() + : ""; + eventBuilder.setPlayerTeleport( + patchbukkit.events.PlayerTeleportEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(teleportEvent.getPlayer().getUniqueId().toString()) + .build()) + .setFrom(BridgeUtils.convertLocation(teleportEvent.getFrom())) + .setTo(BridgeUtils.convertLocation(teleportEvent.getTo())) + .setCause(cause) + .build() + ); + } else if (event instanceof PlayerChangedWorldEvent changeEvent) { + var previousWorld = changeEvent.getFrom(); + var currentWorld = changeEvent.getPlayer().getWorld(); + var location = changeEvent.getPlayer().getLocation(); + eventBuilder.setPlayerChangeWorld( + patchbukkit.events.PlayerChangeWorldEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(changeEvent.getPlayer().getUniqueId().toString()) + .build()) + .setPreviousWorld(BridgeUtils.convertWorld(previousWorld)) + .setNewWorld(BridgeUtils.convertWorld(currentWorld)) + .setPosition(BridgeUtils.convertLocation(location)) + .setYaw(location.getYaw()) + .setPitch(location.getPitch()) + .build() + ); + } else if (event instanceof PlayerGameModeChangeEvent gameModeChangeEvent) { + GameMode previous = gameModeChangeEvent.getPlayer().getGameMode(); + GameMode next = gameModeChangeEvent.getNewGameMode(); + eventBuilder.setPlayerGamemodeChange( + patchbukkit.events.PlayerGamemodeChangeEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(gameModeChangeEvent.getPlayer().getUniqueId().toString()) + .build()) + .setPreviousGamemode(previous != null ? previous.name() : "") + .setNewGamemode(next != null ? next.name() : "") + .build() + ); } else if (event instanceof AsyncPlayerChatEvent chatEvent) { var playerEventBuilder = patchbukkit.events.PlayerChatEvent.newBuilder() .setPlayerUuid(UUID.newBuilder() @@ -434,4 +548,20 @@ private static Player getPlayer(@NotNull String uuidStr) { return null; } } + + @Nullable + private static PlayerLoginEvent createLoginEvent(@NotNull Player player) { + try { + return PlayerLoginEvent.class.getConstructor(Player.class, String.class, InetAddress.class) + .newInstance(player, "", null); + } catch (ReflectiveOperationException ignored) { + try { + return PlayerLoginEvent.class.getConstructor(Player.class, String.class, java.net.InetAddress.class, + PlayerLoginEvent.Result.class, String.class) + .newInstance(player, "", null, PlayerLoginEvent.Result.ALLOWED, ""); + } catch (ReflectiveOperationException ignoredAgain) { + return null; + } + } + } } 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 b006097..2745dd3 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -73,6 +73,21 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.player.PlayerLoginEvent": + var loginEvent = (org.bukkit.event.player.PlayerLoginEvent) event; + String loginKick = loginEvent.getKickMessage(); + if (loginKick == null) { + loginKick = ""; + } + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerLogin( + patchbukkit.events.PlayerLoginEvent.newBuilder() + .setKickMessage(loginKick) + .setPlayerUuid(BridgeUtils.convertUuid(loginEvent.getPlayer().getUniqueId())) + .build() + ).build() + ); + break; case "org.bukkit.event.player.PlayerQuitEvent": var quitEvent = (org.bukkit.event.player.PlayerQuitEvent) event; request.setEvent( @@ -95,6 +110,52 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.player.PlayerTeleportEvent": + var teleportEvent = (org.bukkit.event.player.PlayerTeleportEvent) event; + String cause = teleportEvent.getCause() != null ? teleportEvent.getCause().name() : ""; + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerTeleport( + patchbukkit.events.PlayerTeleportEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(teleportEvent.getPlayer().getUniqueId())) + .setFrom(BridgeUtils.convertLocation(teleportEvent.getFrom())) + .setTo(BridgeUtils.convertLocation(teleportEvent.getTo())) + .setCause(cause) + .build() + ).build() + ); + break; + case "org.bukkit.event.player.PlayerChangedWorldEvent": + var changeEvent = (org.bukkit.event.player.PlayerChangedWorldEvent) event; + var previousWorld = changeEvent.getFrom(); + var currentWorld = changeEvent.getPlayer().getWorld(); + var location = changeEvent.getPlayer().getLocation(); + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerChangeWorld( + patchbukkit.events.PlayerChangeWorldEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(changeEvent.getPlayer().getUniqueId())) + .setPreviousWorld(BridgeUtils.convertWorld(previousWorld)) + .setNewWorld(BridgeUtils.convertWorld(currentWorld)) + .setPosition(BridgeUtils.convertLocation(location)) + .setYaw(location.getYaw()) + .setPitch(location.getPitch()) + .build() + ).build() + ); + break; + case "org.bukkit.event.player.PlayerGameModeChangeEvent": + var gameModeChangeEvent = (org.bukkit.event.player.PlayerGameModeChangeEvent) event; + var previousMode = gameModeChangeEvent.getPlayer().getGameMode(); + var nextMode = gameModeChangeEvent.getNewGameMode(); + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerGamemodeChange( + patchbukkit.events.PlayerGamemodeChangeEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(gameModeChangeEvent.getPlayer().getUniqueId())) + .setPreviousGamemode(previousMode != null ? previousMode.name() : "") + .setNewGamemode(nextMode != null ? nextMode.name() : "") + .build() + ).build() + ); + break; case "org.bukkit.event.player.AsyncPlayerChatEvent": var chatEvent = (org.bukkit.event.player.AsyncPlayerChatEvent) event; var chatBuilder = PlayerChatEvent.newBuilder() diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index a06f8cc..efada23 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -14,18 +14,22 @@ option java_package = "patchbukkit.events"; message Event { oneof data { PlayerJoinEvent player_join = 1; - PlayerLeaveEvent player_leave = 2; - PlayerMoveEvent player_move = 3; - PlayerChatEvent player_chat = 4; - PlayerCommandEvent player_command = 5; - ServerCommandEvent server_command = 6; - ServerBroadcastEvent server_broadcast = 7; - BlockBreakEvent block_break = 8; - BlockPlaceEvent block_place = 9; - PlayerInteractEvent player_interact = 10; - EntitySpawnEvent entity_spawn = 11; - EntityDamageEvent entity_damage = 12; - EntityDeathEvent entity_death = 13; + PlayerLoginEvent player_login = 2; + PlayerLeaveEvent player_leave = 3; + PlayerMoveEvent player_move = 4; + PlayerChatEvent player_chat = 5; + PlayerCommandEvent player_command = 6; + PlayerTeleportEvent player_teleport = 7; + PlayerChangeWorldEvent player_change_world = 8; + PlayerGamemodeChangeEvent player_gamemode_change = 9; + ServerCommandEvent server_command = 10; + ServerBroadcastEvent server_broadcast = 11; + BlockBreakEvent block_break = 12; + BlockPlaceEvent block_place = 13; + PlayerInteractEvent player_interact = 14; + EntitySpawnEvent entity_spawn = 15; + EntityDamageEvent entity_damage = 16; + EntityDeathEvent entity_death = 17; } } diff --git a/proto/patchbukkit/events/player_events.proto b/proto/patchbukkit/events/player_events.proto index d79bdb6..8bde250 100644 --- a/proto/patchbukkit/events/player_events.proto +++ b/proto/patchbukkit/events/player_events.proto @@ -11,6 +11,11 @@ message PlayerJoinEvent { string join_message = 2; } +message PlayerLoginEvent { + patchbukkit.common.UUID player_uuid = 1; + string kick_message = 2; +} + message PlayerLeaveEvent { patchbukkit.common.UUID player_uuid = 1; string leave_message = 2; @@ -22,6 +27,28 @@ message PlayerMoveEvent { patchbukkit.common.Location to = 3; } +message PlayerTeleportEvent { + patchbukkit.common.UUID player_uuid = 1; + patchbukkit.common.Location from = 2; + patchbukkit.common.Location to = 3; + string cause = 4; +} + +message PlayerChangeWorldEvent { + patchbukkit.common.UUID player_uuid = 1; + patchbukkit.common.World previous_world = 2; + patchbukkit.common.World new_world = 3; + patchbukkit.common.Location position = 4; + float yaw = 5; + float pitch = 6; +} + +message PlayerGamemodeChangeEvent { + patchbukkit.common.UUID player_uuid = 1; + string previous_gamemode = 2; + string new_gamemode = 3; +} + message PlayerChatEvent { patchbukkit.common.UUID player_uuid = 1; string message = 2; diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index f68b899..d23fbbf 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -18,6 +18,7 @@ use crate::proto::patchbukkit::events::{ BlockBreakEvent, BlockPlaceEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerJoinEvent, PlayerLeaveEvent, PlayerMoveEvent, PlayerInteractEvent, ServerBroadcastEvent, ServerCommandEvent, EntityDamageEvent, EntityDeathEvent, EntitySpawnEvent, + PlayerLoginEvent, PlayerTeleportEvent, PlayerChangeWorldEvent, PlayerGamemodeChangeEvent, }; pub struct EventContext { @@ -66,6 +67,37 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_join::PlayerJoinEvent } } +impl PatchBukkitEvent for pumpkin::plugin::player::player_login::PlayerLoginEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerLogin(PlayerLoginEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + kick_message: serde_json::to_string(&self.kick_message).unwrap(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerLogin(event) => { + self.kick_message = serde_json::from_str(&event.kick_message).ok()?; + server.get_player_by_uuid(uuid::Uuid::from_str(&event.player_uuid?.value).ok()?)?; + } + _ => {} + } + + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::player::player_leave::PlayerLeaveEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { JvmEventPayload { @@ -142,6 +174,136 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_move::PlayerMoveEvent } } +impl PatchBukkitEvent for pumpkin::plugin::player::player_teleport::PlayerTeleportEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let world_uuid = self.player.world().uuid; + let yaw = self.player.living_entity.entity.yaw.load(); + let pitch = self.player.living_entity.entity.pitch.load(); + + JvmEventPayload { + event: Event { + data: Some(Data::PlayerTeleport(PlayerTeleportEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + from: Some(build_location(world_uuid, &self.from, yaw, pitch)), + to: Some(build_location(world_uuid, &self.to, yaw, pitch)), + cause: String::new(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerTeleport(event) => { + server.get_player_by_uuid(uuid::Uuid::from_str(&event.player_uuid?.value).ok()?)?; + if let Some(from) = event.from { + if let Some(from_vec) = location_to_vec3(from) { + self.from = from_vec; + } + } + if let Some(to) = event.to { + if let Some(to_vec) = location_to_vec3(to) { + self.to = to_vec; + } + } + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_change_world::PlayerChangeWorldEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let location = build_location(self.new_world.uuid, &self.position, self.yaw, self.pitch); + + JvmEventPayload { + event: Event { + data: Some(Data::PlayerChangeWorld(PlayerChangeWorldEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + previous_world: Some(World { + uuid: Some(Uuid { + value: self.previous_world.uuid.to_string(), + }), + }), + new_world: Some(World { + uuid: Some(Uuid { + value: self.new_world.uuid.to_string(), + }), + }), + position: Some(location), + yaw: self.yaw, + pitch: self.pitch, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerChangeWorld(event) => { + if let Some(position) = event.position.and_then(location_to_vec3) { + self.position = position; + } + self.yaw = event.yaw; + self.pitch = event.pitch; + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_gamemode_change::PlayerGamemodeChangeEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerGamemodeChange(PlayerGamemodeChangeEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + previous_gamemode: gamemode_to_bukkit(self.previous_gamemode), + new_gamemode: gamemode_to_bukkit(self.new_gamemode), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerGamemodeChange(event) => { + if let Some(prev) = gamemode_from_bukkit(&event.previous_gamemode) { + self.previous_gamemode = prev; + } + if let Some(next) = gamemode_from_bukkit(&event.new_gamemode) { + self.new_gamemode = next; + } + } + _ => {} + } + + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::player::player_chat::PlayerChatEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { let recipients = self @@ -530,6 +692,25 @@ fn interact_action_to_bukkit(action: &pumpkin::plugin::player::player_interact_e } } +fn gamemode_to_bukkit(mode: pumpkin_util::GameMode) -> String { + match mode { + pumpkin_util::GameMode::Survival => "SURVIVAL".to_string(), + pumpkin_util::GameMode::Creative => "CREATIVE".to_string(), + pumpkin_util::GameMode::Adventure => "ADVENTURE".to_string(), + pumpkin_util::GameMode::Spectator => "SPECTATOR".to_string(), + } +} + +fn gamemode_from_bukkit(mode: &str) -> Option { + match mode { + "SURVIVAL" => Some(pumpkin_util::GameMode::Survival), + "CREATIVE" => Some(pumpkin_util::GameMode::Creative), + "ADVENTURE" => Some(pumpkin_util::GameMode::Adventure), + "SPECTATOR" => Some(pumpkin_util::GameMode::Spectator), + _ => None, + } +} + fn block_face_to_bukkit(face: Option) -> String { match face { Some(BlockDirection::Up) => "UP".to_string(), diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index 4245fcc..1dfa34b 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -7,8 +7,12 @@ use pumpkin::plugin::player::player_chat::PlayerChatEvent; use pumpkin::plugin::player::player_command_send::PlayerCommandSendEvent; use pumpkin::plugin::player::player_interact_event::{InteractAction, PlayerInteractEvent}; use pumpkin::plugin::player::player_join::PlayerJoinEvent; +use pumpkin::plugin::player::player_login::PlayerLoginEvent; use pumpkin::plugin::player::player_leave::PlayerLeaveEvent; use pumpkin::plugin::player::player_move::PlayerMoveEvent; +use pumpkin::plugin::player::player_teleport::PlayerTeleportEvent; +use pumpkin::plugin::player::player_change_world::PlayerChangeWorldEvent; +use pumpkin::plugin::player::player_gamemode_change::PlayerGamemodeChangeEvent; use pumpkin::plugin::server::server_broadcast::ServerBroadcastEvent; use pumpkin::plugin::server::server_command::ServerCommandEvent; use pumpkin_data::Block; @@ -65,6 +69,21 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.player.PlayerLoginEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_login::PlayerLoginEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.player.PlayerQuitEvent" => { context .register_event::< @@ -95,6 +114,55 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.player.PlayerTeleportEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_teleport::PlayerTeleportEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerChangedWorldEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_change_world::PlayerChangeWorldEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_change_world::PlayerChangeWorldEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerGameModeChangeEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_gamemode_change::PlayerGamemodeChangeEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_gamemode_change::PlayerGamemodeChangeEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.player.AsyncPlayerChatEvent" => { context .register_event::< @@ -287,6 +355,17 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let uuid = + uuid::Uuid::parse_str(&player_login_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let pumpkin_event = PlayerLoginEvent::new( + player, + TextComponent::from_legacy_string(&player_login_event_data.kick_message), + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } Data::PlayerLeave(player_leave_event_data) => { let uuid = uuid::Uuid::parse_str(&player_leave_event_data.player_uuid?.value).ok()?; @@ -312,6 +391,74 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let uuid = + uuid::Uuid::parse_str(&player_teleport_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let from = player_teleport_event_data.from?.position?; + let to = player_teleport_event_data.to?.position?; + let pumpkin_event = PlayerTeleportEvent::new( + player, + Vector3::new(from.x, from.y, from.z), + Vector3::new(to.x, to.y, to.z), + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerChangeWorld(player_change_world_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_change_world_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let prev_uuid = uuid::Uuid::parse_str( + &player_change_world_event_data.previous_world?.uuid?.value, + ) + .ok()?; + let new_uuid = uuid::Uuid::parse_str( + &player_change_world_event_data.new_world?.uuid?.value, + ) + .ok()?; + let prev_world = context + .server + .worlds + .load() + .iter() + .find(|world| world.uuid == prev_uuid)? + .clone(); + let new_world = context + .server + .worlds + .load() + .iter() + .find(|world| world.uuid == new_uuid)? + .clone(); + let position = player_change_world_event_data + .position + .and_then(|loc| loc.position) + .map(|pos| Vector3::new(pos.x, pos.y, pos.z)) + .unwrap_or_else(|| player.position()); + let pumpkin_event = PlayerChangeWorldEvent::new( + player, + prev_world, + new_world, + position, + player_change_world_event_data.yaw, + player_change_world_event_data.pitch, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerGamemodeChange(player_gamemode_change_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_gamemode_change_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let prev = gamemode_from_bukkit(&player_gamemode_change_event_data.previous_gamemode) + .unwrap_or(player.gamemode.load()); + let next = gamemode_from_bukkit(&player_gamemode_change_event_data.new_gamemode) + .unwrap_or(player.gamemode.load()); + let pumpkin_event = PlayerGamemodeChangeEvent::new(player, prev, next); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } Data::PlayerChat(player_chat_event_data) => { let uuid = uuid::Uuid::parse_str(&player_chat_event_data.player_uuid?.value).ok()?; @@ -518,3 +665,13 @@ fn bukkit_block_face_to_direction(face: &str) -> Option { _ => None, } } + +fn gamemode_from_bukkit(mode: &str) -> Option { + match mode { + "SURVIVAL" => Some(pumpkin_util::GameMode::Survival), + "CREATIVE" => Some(pumpkin_util::GameMode::Creative), + "ADVENTURE" => Some(pumpkin_util::GameMode::Adventure), + "SPECTATOR" => Some(pumpkin_util::GameMode::Spectator), + _ => None, + } +} From e5982aff417071d510ac42bc31388fda1c907ae4 Mon Sep 17 00:00:00 2001 From: yunuservices Date: Wed, 4 Feb 2026 21:20:58 +0300 Subject: [PATCH 08/56] Add prelogin, advancement, and animation event bridge --- .../events/PatchBukkitEventFactory.java | 102 ++++++++++++++++++ .../events/PatchBukkitEventManager.java | 45 ++++++++ proto/patchbukkit/events/event.proto | 3 + proto/patchbukkit/events/player_events.proto | 18 ++++ rust/src/events/handler.rs | 90 ++++++++++++++++ rust/src/java/native_callbacks/events.rs | 87 +++++++++++++++ 6 files changed, 345 insertions(+) diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index ed98ba5..e24f5ed 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -13,9 +13,13 @@ import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerCommandPreprocessEvent; import org.bukkit.event.player.PlayerLoginEvent; +import org.bukkit.event.player.AsyncPlayerPreLoginEvent; import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.event.player.PlayerChangedWorldEvent; import org.bukkit.event.player.PlayerGameModeChangeEvent; +import org.bukkit.event.player.PlayerAdvancementDoneEvent; +import org.bukkit.event.player.PlayerAnimationEvent; +import org.bukkit.event.player.PlayerAnimationType; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.server.BroadcastMessageEvent; @@ -36,6 +40,7 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.Material; import org.bukkit.GameMode; +import org.bukkit.NamespacedKey; import java.net.InetAddress; import patchbukkit.common.UUID; import patchbukkit.events.Event; @@ -87,6 +92,38 @@ public static org.bukkit.event.Event createEvent(@NotNull Event event) { } yield null; } + case ASYNC_PLAYER_PRE_LOGIN -> { + patchbukkit.events.AsyncPlayerPreLoginEvent preLoginEvent = event.getAsyncPlayerPreLogin(); + String name = preLoginEvent.getName(); + String uuidStr = preLoginEvent.getPlayerUuid().getValue(); + java.util.UUID uuid; + try { + uuid = java.util.UUID.fromString(uuidStr); + } catch (IllegalArgumentException e) { + yield null; + } + InetAddress address = null; + if (!preLoginEvent.getAddress().isEmpty()) { + try { + address = InetAddress.getByName(preLoginEvent.getAddress()); + } catch (Exception ignored) { + address = null; + } + } + AsyncPlayerPreLoginEvent.Result result = AsyncPlayerPreLoginEvent.Result.ALLOWED; + if (!preLoginEvent.getResult().isEmpty()) { + try { + result = AsyncPlayerPreLoginEvent.Result.valueOf(preLoginEvent.getResult()); + } catch (IllegalArgumentException ignored) { + result = AsyncPlayerPreLoginEvent.Result.ALLOWED; + } + } + AsyncPlayerPreLoginEvent eventObj = new AsyncPlayerPreLoginEvent(name, address, uuid); + if (result != AsyncPlayerPreLoginEvent.Result.ALLOWED) { + eventObj.disallow(result, preLoginEvent.getKickMessage()); + } + yield eventObj; + } case PLAYER_LEAVE -> { PlayerLeaveEvent leaveEvent = event.getPlayerLeave(); Player player = getPlayer(leaveEvent.getPlayerUuid().getValue()); @@ -147,6 +184,31 @@ public static org.bukkit.event.Event createEvent(@NotNull Event event) { } yield new PlayerGameModeChangeEvent(player, mode); } + case PLAYER_ADVANCEMENT_DONE -> { + patchbukkit.events.PlayerAdvancementDoneEvent advancementEvent = event.getPlayerAdvancementDone(); + Player player = getPlayer(advancementEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + if (advancementEvent.getAdvancementKey().isEmpty()) yield null; + NamespacedKey key = NamespacedKey.fromString(advancementEvent.getAdvancementKey()); + if (key == null) yield null; + org.bukkit.advancement.Advancement advancement = Bukkit.getAdvancement(key); + if (advancement == null) yield null; + yield new PlayerAdvancementDoneEvent(player, advancement); + } + case PLAYER_ANIMATION -> { + patchbukkit.events.PlayerAnimationEvent animationEvent = event.getPlayerAnimation(); + Player player = getPlayer(animationEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + PlayerAnimationType type = PlayerAnimationType.ARM_SWING; + if (!animationEvent.getAnimationType().isEmpty()) { + try { + type = PlayerAnimationType.valueOf(animationEvent.getAnimationType()); + } catch (IllegalArgumentException ignored) { + type = PlayerAnimationType.ARM_SWING; + } + } + yield new PlayerAnimationEvent(player, type); + } case PLAYER_CHAT -> { PlayerChatEvent chatEvent = event.getPlayerChat(); Player player = getPlayer(chatEvent.getPlayerUuid().getValue()); @@ -350,6 +412,27 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .setKickMessage(GsonComponentSerializer.gson().serialize(Component.text(kickMessage))) .build() ); + } else if (event instanceof AsyncPlayerPreLoginEvent preLoginEvent) { + String address = preLoginEvent.getAddress() != null + ? preLoginEvent.getAddress().getHostAddress() + : ""; + String result = preLoginEvent.getLoginResult() != null + ? preLoginEvent.getLoginResult().name() + : "ALLOWED"; + String kickMessage = preLoginEvent.getKickMessage() != null + ? preLoginEvent.getKickMessage() + : ""; + eventBuilder.setAsyncPlayerPreLogin( + patchbukkit.events.AsyncPlayerPreLoginEvent.newBuilder() + .setName(preLoginEvent.getName()) + .setPlayerUuid(UUID.newBuilder() + .setValue(preLoginEvent.getUniqueId().toString()) + .build()) + .setAddress(address) + .setResult(result) + .setKickMessage(kickMessage) + .build() + ); } else if (event instanceof PlayerMoveEvent moveEvent) { eventBuilder.setPlayerMove( patchbukkit.events.PlayerMoveEvent.newBuilder() @@ -402,6 +485,25 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .setNewGamemode(next != null ? next.name() : "") .build() ); + } else if (event instanceof PlayerAdvancementDoneEvent advancementEvent) { + String key = advancementEvent.getAdvancement().getKey().toString(); + eventBuilder.setPlayerAdvancementDone( + patchbukkit.events.PlayerAdvancementDoneEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(advancementEvent.getPlayer().getUniqueId().toString()) + .build()) + .setAdvancementKey(key) + .build() + ); + } else if (event instanceof PlayerAnimationEvent animationEvent) { + eventBuilder.setPlayerAnimation( + patchbukkit.events.PlayerAnimationEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(animationEvent.getPlayer().getUniqueId().toString()) + .build()) + .setAnimationType(animationEvent.getAnimationType().name()) + .build() + ); } else if (event instanceof AsyncPlayerChatEvent chatEvent) { var playerEventBuilder = patchbukkit.events.PlayerChatEvent.newBuilder() .setPlayerUuid(UUID.newBuilder() 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 2745dd3..8f4b1af 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -88,6 +88,29 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.player.AsyncPlayerPreLoginEvent": + var preLoginEvent = (org.bukkit.event.player.AsyncPlayerPreLoginEvent) event; + String address = preLoginEvent.getAddress() != null + ? preLoginEvent.getAddress().getHostAddress() + : ""; + String result = preLoginEvent.getLoginResult() != null + ? preLoginEvent.getLoginResult().name() + : "ALLOWED"; + String kickMessage = preLoginEvent.getKickMessage() != null + ? preLoginEvent.getKickMessage() + : ""; + request.setEvent( + patchbukkit.events.Event.newBuilder().setAsyncPlayerPreLogin( + patchbukkit.events.AsyncPlayerPreLoginEvent.newBuilder() + .setName(preLoginEvent.getName()) + .setPlayerUuid(BridgeUtils.convertUuid(preLoginEvent.getUniqueId())) + .setAddress(address) + .setResult(result) + .setKickMessage(kickMessage) + .build() + ).build() + ); + break; case "org.bukkit.event.player.PlayerQuitEvent": var quitEvent = (org.bukkit.event.player.PlayerQuitEvent) event; request.setEvent( @@ -156,6 +179,28 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.player.PlayerAdvancementDoneEvent": + var advancementEvent = (org.bukkit.event.player.PlayerAdvancementDoneEvent) event; + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerAdvancementDone( + patchbukkit.events.PlayerAdvancementDoneEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(advancementEvent.getPlayer().getUniqueId())) + .setAdvancementKey(advancementEvent.getAdvancement().getKey().toString()) + .build() + ).build() + ); + break; + case "org.bukkit.event.player.PlayerAnimationEvent": + var animationEvent = (org.bukkit.event.player.PlayerAnimationEvent) event; + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerAnimation( + patchbukkit.events.PlayerAnimationEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(animationEvent.getPlayer().getUniqueId())) + .setAnimationType(animationEvent.getAnimationType().name()) + .build() + ).build() + ); + break; case "org.bukkit.event.player.AsyncPlayerChatEvent": var chatEvent = (org.bukkit.event.player.AsyncPlayerChatEvent) event; var chatBuilder = PlayerChatEvent.newBuilder() diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index efada23..95ff160 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -30,6 +30,9 @@ message Event { EntitySpawnEvent entity_spawn = 15; EntityDamageEvent entity_damage = 16; EntityDeathEvent entity_death = 17; + AsyncPlayerPreLoginEvent async_player_pre_login = 18; + PlayerAdvancementDoneEvent player_advancement_done = 19; + PlayerAnimationEvent player_animation = 20; } } diff --git a/proto/patchbukkit/events/player_events.proto b/proto/patchbukkit/events/player_events.proto index 8bde250..0e8a28f 100644 --- a/proto/patchbukkit/events/player_events.proto +++ b/proto/patchbukkit/events/player_events.proto @@ -59,3 +59,21 @@ message PlayerCommandEvent { patchbukkit.common.UUID player_uuid = 1; string command = 2; } + +message AsyncPlayerPreLoginEvent { + string name = 1; + patchbukkit.common.UUID player_uuid = 2; + string address = 3; + string result = 4; + string kick_message = 5; +} + +message PlayerAdvancementDoneEvent { + patchbukkit.common.UUID player_uuid = 1; + string advancement_key = 2; +} + +message PlayerAnimationEvent { + patchbukkit.common.UUID player_uuid = 1; + string animation_type = 2; +} diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index d23fbbf..a934f5c 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -19,6 +19,7 @@ use crate::proto::patchbukkit::events::{ PlayerLeaveEvent, PlayerMoveEvent, PlayerInteractEvent, ServerBroadcastEvent, ServerCommandEvent, EntityDamageEvent, EntityDeathEvent, EntitySpawnEvent, PlayerLoginEvent, PlayerTeleportEvent, PlayerChangeWorldEvent, PlayerGamemodeChangeEvent, + AsyncPlayerPreLoginEvent, PlayerAdvancementDoneEvent, PlayerAnimationEvent, }; pub struct EventContext { @@ -98,6 +99,49 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_login::PlayerLoginEven } } +impl PatchBukkitEvent for pumpkin::plugin::player::player_pre_login::PlayerPreLoginEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::AsyncPlayerPreLogin(AsyncPlayerPreLoginEvent { + name: self.name.clone(), + player_uuid: Some(Uuid { + value: self.player_uuid.to_string(), + }), + address: self.address.clone(), + result: self.result.clone(), + kick_message: self.kick_message.clone(), + })), + }, + context: EventContext { + server, + player: None, + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::AsyncPlayerPreLogin(event) => { + self.result = event.result; + self.kick_message = event.kick_message; + if let Some(uuid) = event.player_uuid { + self.player_uuid = uuid::Uuid::from_str(&uuid.value).ok()?; + } + if !event.name.is_empty() { + self.name = event.name; + } + if !event.address.is_empty() { + self.address = event.address; + } + } + _ => {} + } + + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::player::player_leave::PlayerLeaveEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { JvmEventPayload { @@ -129,6 +173,52 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_leave::PlayerLeaveEven } } +impl PatchBukkitEvent for pumpkin::plugin::player::player_advancement_done::PlayerAdvancementDoneEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerAdvancementDone(PlayerAdvancementDoneEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + advancement_key: self.advancement_key.clone(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, _data: Data) -> Option<()> { + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_animation::PlayerAnimationEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerAnimation(PlayerAnimationEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + animation_type: self.animation_type.clone(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, _data: Data) -> Option<()> { + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::player::player_move::PlayerMoveEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { let world_uuid = self.player.world().uuid; diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index 1dfa34b..b64284e 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -8,6 +8,9 @@ use pumpkin::plugin::player::player_command_send::PlayerCommandSendEvent; use pumpkin::plugin::player::player_interact_event::{InteractAction, PlayerInteractEvent}; use pumpkin::plugin::player::player_join::PlayerJoinEvent; use pumpkin::plugin::player::player_login::PlayerLoginEvent; +use pumpkin::plugin::player::player_pre_login::PlayerPreLoginEvent; +use pumpkin::plugin::player::player_advancement_done::PlayerAdvancementDoneEvent; +use pumpkin::plugin::player::player_animation::PlayerAnimationEvent; use pumpkin::plugin::player::player_leave::PlayerLeaveEvent; use pumpkin::plugin::player::player_move::PlayerMoveEvent; use pumpkin::plugin::player::player_teleport::PlayerTeleportEvent; @@ -84,6 +87,21 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.player.AsyncPlayerPreLoginEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_pre_login::PlayerPreLoginEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.player.PlayerQuitEvent" => { context .register_event::< @@ -114,6 +132,40 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.player.PlayerAdvancementDoneEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_advancement_done::PlayerAdvancementDoneEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_advancement_done::PlayerAdvancementDoneEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerAnimationEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_animation::PlayerAnimationEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_animation::PlayerAnimationEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.player.PlayerTeleportEvent" => { context .register_event::< @@ -366,6 +418,19 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let uuid = + uuid::Uuid::parse_str(&player_pre_login_event_data.player_uuid?.value).ok()?; + let pumpkin_event = PlayerPreLoginEvent::new( + player_pre_login_event_data.name, + uuid, + player_pre_login_event_data.address, + player_pre_login_event_data.result, + player_pre_login_event_data.kick_message, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } Data::PlayerLeave(player_leave_event_data) => { let uuid = uuid::Uuid::parse_str(&player_leave_event_data.player_uuid?.value).ok()?; @@ -391,6 +456,28 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let uuid = + uuid::Uuid::parse_str(&player_advancement_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let pumpkin_event = PlayerAdvancementDoneEvent::new( + player, + player_advancement_event_data.advancement_key, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerAnimation(player_animation_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_animation_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let pumpkin_event = PlayerAnimationEvent::new( + player, + player_animation_event_data.animation_type, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } Data::PlayerTeleport(player_teleport_event_data) => { let uuid = uuid::Uuid::parse_str(&player_teleport_event_data.player_uuid?.value).ok()?; From f9499b58f0f6eef66f9b726316c23052fbe31021 Mon Sep 17 00:00:00 2001 From: yunuservices Date: Wed, 4 Feb 2026 21:50:22 +0300 Subject: [PATCH 09/56] Add armor stand manipulate event bridge --- .../entity/PatchBukkitArmorStand.java | 318 ++++++++++++++++++ .../events/PatchBukkitEventFactory.java | 63 ++++ .../events/PatchBukkitEventManager.java | 21 ++ proto/patchbukkit/events/event.proto | 1 + proto/patchbukkit/events/player_events.proto | 8 + rust/src/events/handler.rs | 49 +++ rust/src/java/native_callbacks/events.rs | 36 ++ 7 files changed, 496 insertions(+) create mode 100644 java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitArmorStand.java diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitArmorStand.java b/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitArmorStand.java new file mode 100644 index 0000000..a7b6cf7 --- /dev/null +++ b/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitArmorStand.java @@ -0,0 +1,318 @@ +package org.patchbukkit.entity; + +import java.util.Collections; +import java.util.Set; +import java.util.UUID; + +import org.bukkit.Material; +import org.bukkit.entity.ArmorStand; +import org.bukkit.inventory.EntityEquipment; +import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.ItemStack; +import org.bukkit.util.EulerAngle; + +import io.papermc.paper.math.Rotations; +import org.jetbrains.annotations.NotNull; + +public class PatchBukkitArmorStand extends PatchBukkitLivingEntity implements ArmorStand { + + public PatchBukkitArmorStand(UUID uuid, String name) { + super(uuid, name); + } + + @Override + public @NotNull ItemStack getItemInHand() { + return new ItemStack(Material.AIR); + } + + @Override + public void setItemInHand(ItemStack item) { + // TODO: integrate with equipment + throw new UnsupportedOperationException("Unimplemented method 'setItemInHand'"); + } + + @Override + public @NotNull ItemStack getBoots() { + return new ItemStack(Material.AIR); + } + + @Override + public void setBoots(ItemStack item) { + throw new UnsupportedOperationException("Unimplemented method 'setBoots'"); + } + + @Override + public @NotNull ItemStack getLeggings() { + return new ItemStack(Material.AIR); + } + + @Override + public void setLeggings(ItemStack item) { + throw new UnsupportedOperationException("Unimplemented method 'setLeggings'"); + } + + @Override + public @NotNull ItemStack getChestplate() { + return new ItemStack(Material.AIR); + } + + @Override + public void setChestplate(ItemStack item) { + throw new UnsupportedOperationException("Unimplemented method 'setChestplate'"); + } + + @Override + public @NotNull ItemStack getHelmet() { + return new ItemStack(Material.AIR); + } + + @Override + public void setHelmet(ItemStack item) { + throw new UnsupportedOperationException("Unimplemented method 'setHelmet'"); + } + + @Override + public @NotNull EulerAngle getBodyPose() { + return EulerAngle.ZERO; + } + + @Override + public void setBodyPose(EulerAngle pose) { + throw new UnsupportedOperationException("Unimplemented method 'setBodyPose'"); + } + + @Override + public @NotNull EulerAngle getLeftArmPose() { + return EulerAngle.ZERO; + } + + @Override + public void setLeftArmPose(EulerAngle pose) { + throw new UnsupportedOperationException("Unimplemented method 'setLeftArmPose'"); + } + + @Override + public @NotNull EulerAngle getRightArmPose() { + return EulerAngle.ZERO; + } + + @Override + public void setRightArmPose(EulerAngle pose) { + throw new UnsupportedOperationException("Unimplemented method 'setRightArmPose'"); + } + + @Override + public @NotNull EulerAngle getLeftLegPose() { + return EulerAngle.ZERO; + } + + @Override + public void setLeftLegPose(EulerAngle pose) { + throw new UnsupportedOperationException("Unimplemented method 'setLeftLegPose'"); + } + + @Override + public @NotNull EulerAngle getRightLegPose() { + return EulerAngle.ZERO; + } + + @Override + public void setRightLegPose(EulerAngle pose) { + throw new UnsupportedOperationException("Unimplemented method 'setRightLegPose'"); + } + + @Override + public @NotNull EulerAngle getHeadPose() { + return EulerAngle.ZERO; + } + + @Override + public void setHeadPose(EulerAngle pose) { + throw new UnsupportedOperationException("Unimplemented method 'setHeadPose'"); + } + + @Override + public boolean hasBasePlate() { + return true; + } + + @Override + public void setBasePlate(boolean basePlate) { + throw new UnsupportedOperationException("Unimplemented method 'setBasePlate'"); + } + + @Override + public boolean isVisible() { + return true; + } + + @Override + public void setVisible(boolean visible) { + throw new UnsupportedOperationException("Unimplemented method 'setVisible'"); + } + + @Override + public boolean hasArms() { + return true; + } + + @Override + public void setArms(boolean arms) { + throw new UnsupportedOperationException("Unimplemented method 'setArms'"); + } + + @Override + public boolean isSmall() { + return false; + } + + @Override + public void setSmall(boolean small) { + throw new UnsupportedOperationException("Unimplemented method 'setSmall'"); + } + + @Override + public boolean isMarker() { + return false; + } + + @Override + public void setMarker(boolean marker) { + throw new UnsupportedOperationException("Unimplemented method 'setMarker'"); + } + + @Override + public void addEquipmentLock(@NotNull EquipmentSlot slot, @NotNull LockType lockType) { + throw new UnsupportedOperationException("Unimplemented method 'addEquipmentLock'"); + } + + @Override + public void removeEquipmentLock(@NotNull EquipmentSlot slot, @NotNull LockType lockType) { + throw new UnsupportedOperationException("Unimplemented method 'removeEquipmentLock'"); + } + + @Override + public boolean hasEquipmentLock(@NotNull EquipmentSlot slot, @NotNull LockType lockType) { + return false; + } + + @Override + public boolean canMove() { + return true; + } + + @Override + public void setCanMove(boolean move) { + throw new UnsupportedOperationException("Unimplemented method 'setCanMove'"); + } + + @Override + public EntityEquipment getEquipment() { + return null; + } + + @Override + public boolean canTick() { + return true; + } + + @Override + public void setCanTick(boolean tick) { + throw new UnsupportedOperationException("Unimplemented method 'setCanTick'"); + } + + @Override + public @NotNull ItemStack getItem(@NotNull EquipmentSlot slot) { + return new ItemStack(Material.AIR); + } + + @Override + public void setItem(@NotNull EquipmentSlot slot, ItemStack item) { + throw new UnsupportedOperationException("Unimplemented method 'setItem'"); + } + + @Override + public @NotNull Set getDisabledSlots() { + return Collections.emptySet(); + } + + @Override + public void setDisabledSlots(@NotNull EquipmentSlot @NotNull... slots) { + throw new UnsupportedOperationException("Unimplemented method 'setDisabledSlots'"); + } + + @Override + public void addDisabledSlots(@NotNull EquipmentSlot @NotNull... slots) { + throw new UnsupportedOperationException("Unimplemented method 'addDisabledSlots'"); + } + + @Override + public void removeDisabledSlots(@NotNull EquipmentSlot @NotNull... slots) { + throw new UnsupportedOperationException("Unimplemented method 'removeDisabledSlots'"); + } + + @Override + public boolean isSlotDisabled(@NotNull EquipmentSlot slot) { + return false; + } + + @Override + public @NotNull Rotations getBodyRotations() { + return Rotations.ZERO; + } + + @Override + public void setBodyRotations(@NotNull Rotations rotations) { + throw new UnsupportedOperationException("Unimplemented method 'setBodyRotations'"); + } + + @Override + public @NotNull Rotations getLeftArmRotations() { + return Rotations.ZERO; + } + + @Override + public void setLeftArmRotations(@NotNull Rotations rotations) { + throw new UnsupportedOperationException("Unimplemented method 'setLeftArmRotations'"); + } + + @Override + public @NotNull Rotations getRightArmRotations() { + return Rotations.ZERO; + } + + @Override + public void setRightArmRotations(@NotNull Rotations rotations) { + throw new UnsupportedOperationException("Unimplemented method 'setRightArmRotations'"); + } + + @Override + public @NotNull Rotations getLeftLegRotations() { + return Rotations.ZERO; + } + + @Override + public void setLeftLegRotations(@NotNull Rotations rotations) { + throw new UnsupportedOperationException("Unimplemented method 'setLeftLegRotations'"); + } + + @Override + public @NotNull Rotations getRightLegRotations() { + return Rotations.ZERO; + } + + @Override + public void setRightLegRotations(@NotNull Rotations rotations) { + throw new UnsupportedOperationException("Unimplemented method 'setRightLegRotations'"); + } + + @Override + public @NotNull Rotations getHeadRotations() { + return Rotations.ZERO; + } + + @Override + public void setHeadRotations(@NotNull Rotations rotations) { + throw new UnsupportedOperationException("Unimplemented method 'setHeadRotations'"); + } +} diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index e24f5ed..60c7e2f 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -20,6 +20,7 @@ import org.bukkit.event.player.PlayerAdvancementDoneEvent; import org.bukkit.event.player.PlayerAnimationEvent; import org.bukkit.event.player.PlayerAnimationType; +import org.bukkit.event.player.PlayerArmorStandManipulateEvent; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.server.BroadcastMessageEvent; @@ -36,8 +37,10 @@ import org.patchbukkit.world.PatchBukkitWorld; import org.patchbukkit.entity.PatchBukkitEntity; import org.patchbukkit.entity.PatchBukkitLivingEntity; +import org.patchbukkit.entity.PatchBukkitArmorStand; import org.bukkit.block.BlockFace; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.EquipmentSlot; import org.bukkit.Material; import org.bukkit.GameMode; import org.bukkit.NamespacedKey; @@ -209,6 +212,32 @@ public static org.bukkit.event.Event createEvent(@NotNull Event event) { } yield new PlayerAnimationEvent(player, type); } + case PLAYER_ARMOR_STAND_MANIPULATE -> { + patchbukkit.events.PlayerArmorStandManipulateEvent armorEvent = + event.getPlayerArmorStandManipulate(); + Player player = getPlayer(armorEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + java.util.UUID standUuid; + try { + standUuid = java.util.UUID.fromString(armorEvent.getArmorStandUuid().getValue()); + } catch (IllegalArgumentException e) { + yield null; + } + PatchBukkitArmorStand armorStand = new PatchBukkitArmorStand(standUuid, "ArmorStand"); + + ItemStack playerItem = materialToItem(armorEvent.getItemKey()); + ItemStack standItem = materialToItem(armorEvent.getArmorStandItemKey()); + + EquipmentSlot slot = EquipmentSlot.HAND; + if (!armorEvent.getSlot().isEmpty()) { + try { + slot = EquipmentSlot.valueOf(armorEvent.getSlot()); + } catch (IllegalArgumentException ignored) { + slot = EquipmentSlot.HAND; + } + } + yield new PlayerArmorStandManipulateEvent(player, armorStand, playerItem, standItem, slot); + } case PLAYER_CHAT -> { PlayerChatEvent chatEvent = event.getPlayerChat(); Player player = getPlayer(chatEvent.getPlayerUuid().getValue()); @@ -504,6 +533,25 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .setAnimationType(animationEvent.getAnimationType().name()) .build() ); + } else if (event instanceof PlayerArmorStandManipulateEvent armorEvent) { + ItemStack playerItem = armorEvent.getPlayerItem(); + ItemStack standItem = armorEvent.getArmorStandItem(); + String playerKey = playerItem != null ? playerItem.getType().getKey().toString() : "minecraft:air"; + String standKey = standItem != null ? standItem.getType().getKey().toString() : "minecraft:air"; + String slot = armorEvent.getSlot() != null ? armorEvent.getSlot().name() : "HAND"; + eventBuilder.setPlayerArmorStandManipulate( + patchbukkit.events.PlayerArmorStandManipulateEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(armorEvent.getPlayer().getUniqueId().toString()) + .build()) + .setArmorStandUuid(UUID.newBuilder() + .setValue(armorEvent.getRightClicked().getUniqueId().toString()) + .build()) + .setItemKey(playerKey) + .setArmorStandItemKey(standKey) + .setSlot(slot) + .build() + ); } else if (event instanceof AsyncPlayerChatEvent chatEvent) { var playerEventBuilder = patchbukkit.events.PlayerChatEvent.newBuilder() .setPlayerUuid(UUID.newBuilder() @@ -666,4 +714,19 @@ private static PlayerLoginEvent createLoginEvent(@NotNull Player player) { } } } + + @NotNull + private static ItemStack materialToItem(@NotNull String key) { + if (key.isEmpty()) { + return new ItemStack(Material.AIR); + } + Material material = Material.matchMaterial(key); + if (material == null) { + material = Material.matchMaterial("minecraft:" + key); + } + if (material == null) { + material = Material.AIR; + } + return new ItemStack(material); + } } 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 8f4b1af..b5cb0db 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -201,6 +201,27 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.player.PlayerArmorStandManipulateEvent": + var armorEvent = (org.bukkit.event.player.PlayerArmorStandManipulateEvent) event; + String playerKey = armorEvent.getPlayerItem() != null + ? armorEvent.getPlayerItem().getType().getKey().toString() + : "minecraft:air"; + String standKey = armorEvent.getArmorStandItem() != null + ? armorEvent.getArmorStandItem().getType().getKey().toString() + : "minecraft:air"; + String slot = armorEvent.getSlot() != null ? armorEvent.getSlot().name() : "HAND"; + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerArmorStandManipulate( + patchbukkit.events.PlayerArmorStandManipulateEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(armorEvent.getPlayer().getUniqueId())) + .setArmorStandUuid(BridgeUtils.convertUuid(armorEvent.getRightClicked().getUniqueId())) + .setItemKey(playerKey) + .setArmorStandItemKey(standKey) + .setSlot(slot) + .build() + ).build() + ); + break; case "org.bukkit.event.player.AsyncPlayerChatEvent": var chatEvent = (org.bukkit.event.player.AsyncPlayerChatEvent) event; var chatBuilder = PlayerChatEvent.newBuilder() diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index 95ff160..197c866 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -33,6 +33,7 @@ message Event { AsyncPlayerPreLoginEvent async_player_pre_login = 18; PlayerAdvancementDoneEvent player_advancement_done = 19; PlayerAnimationEvent player_animation = 20; + PlayerArmorStandManipulateEvent player_armor_stand_manipulate = 21; } } diff --git a/proto/patchbukkit/events/player_events.proto b/proto/patchbukkit/events/player_events.proto index 0e8a28f..c302347 100644 --- a/proto/patchbukkit/events/player_events.proto +++ b/proto/patchbukkit/events/player_events.proto @@ -77,3 +77,11 @@ message PlayerAnimationEvent { patchbukkit.common.UUID player_uuid = 1; string animation_type = 2; } + +message PlayerArmorStandManipulateEvent { + patchbukkit.common.UUID player_uuid = 1; + patchbukkit.common.UUID armor_stand_uuid = 2; + string item_key = 3; + string armor_stand_item_key = 4; + string slot = 5; +} diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index a934f5c..6972ad7 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -20,6 +20,7 @@ use crate::proto::patchbukkit::events::{ EntityDamageEvent, EntityDeathEvent, EntitySpawnEvent, PlayerLoginEvent, PlayerTeleportEvent, PlayerChangeWorldEvent, PlayerGamemodeChangeEvent, AsyncPlayerPreLoginEvent, PlayerAdvancementDoneEvent, PlayerAnimationEvent, + PlayerArmorStandManipulateEvent, }; pub struct EventContext { @@ -219,6 +220,54 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_animation::PlayerAnima } } +impl PatchBukkitEvent for pumpkin::plugin::player::player_armor_stand_manipulate::PlayerArmorStandManipulateEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerArmorStandManipulate( + PlayerArmorStandManipulateEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + armor_stand_uuid: Some(Uuid { + value: self.armor_stand_uuid.to_string(), + }), + item_key: self.item_key.clone(), + armor_stand_item_key: self.armor_stand_item_key.clone(), + slot: self.slot.clone(), + }, + )), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerArmorStandManipulate(event) => { + if !event.item_key.is_empty() { + self.item_key = event.item_key; + } + if !event.armor_stand_item_key.is_empty() { + self.armor_stand_item_key = event.armor_stand_item_key; + } + if !event.slot.is_empty() { + self.slot = event.slot; + } + if let Some(uuid) = event.armor_stand_uuid { + self.armor_stand_uuid = uuid::Uuid::from_str(&uuid.value).ok()?; + } + } + _ => {} + } + + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::player::player_move::PlayerMoveEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { let world_uuid = self.player.world().uuid; diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index b64284e..fc51108 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -11,6 +11,7 @@ use pumpkin::plugin::player::player_login::PlayerLoginEvent; use pumpkin::plugin::player::player_pre_login::PlayerPreLoginEvent; use pumpkin::plugin::player::player_advancement_done::PlayerAdvancementDoneEvent; use pumpkin::plugin::player::player_animation::PlayerAnimationEvent; +use pumpkin::plugin::player::player_armor_stand_manipulate::PlayerArmorStandManipulateEvent; use pumpkin::plugin::player::player_leave::PlayerLeaveEvent; use pumpkin::plugin::player::player_move::PlayerMoveEvent; use pumpkin::plugin::player::player_teleport::PlayerTeleportEvent; @@ -166,6 +167,23 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.player.PlayerArmorStandManipulateEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_armor_stand_manipulate::PlayerArmorStandManipulateEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_armor_stand_manipulate::PlayerArmorStandManipulateEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.player.PlayerTeleportEvent" => { context .register_event::< @@ -478,6 +496,24 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let uuid = + uuid::Uuid::parse_str(&player_armor_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let armor_uuid = uuid::Uuid::parse_str( + &player_armor_event_data.armor_stand_uuid?.value, + ) + .ok()?; + let pumpkin_event = PlayerArmorStandManipulateEvent::new( + player, + armor_uuid, + player_armor_event_data.item_key, + player_armor_event_data.armor_stand_item_key, + player_armor_event_data.slot, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } Data::PlayerTeleport(player_teleport_event_data) => { let uuid = uuid::Uuid::parse_str(&player_teleport_event_data.player_uuid?.value).ok()?; From c27f40d5ba96812d527c61b01b893dcff957325e Mon Sep 17 00:00:00 2001 From: yunuservices Date: Wed, 4 Feb 2026 21:57:28 +0300 Subject: [PATCH 10/56] Add bed enter/leave event bridge --- .../events/PatchBukkitEventFactory.java | 40 ++++++++++ .../events/PatchBukkitEventManager.java | 22 ++++++ proto/patchbukkit/events/event.proto | 2 + proto/patchbukkit/events/player_events.proto | 10 +++ rust/src/events/handler.rs | 73 +++++++++++++++++++ rust/src/java/native_callbacks/events.rs | 62 ++++++++++++++++ 6 files changed, 209 insertions(+) diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index 60c7e2f..29744f3 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -21,6 +21,8 @@ import org.bukkit.event.player.PlayerAnimationEvent; import org.bukkit.event.player.PlayerAnimationType; import org.bukkit.event.player.PlayerArmorStandManipulateEvent; +import org.bukkit.event.player.PlayerBedEnterEvent; +import org.bukkit.event.player.PlayerBedLeaveEvent; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.server.BroadcastMessageEvent; @@ -238,6 +240,24 @@ public static org.bukkit.event.Event createEvent(@NotNull Event event) { } yield new PlayerArmorStandManipulateEvent(player, armorStand, playerItem, standItem, slot); } + case PLAYER_BED_ENTER -> { + patchbukkit.events.PlayerBedEnterEvent bedEvent = event.getPlayerBedEnter(); + Player player = getPlayer(bedEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + Location bedLocation = BridgeUtils.convertLocation(bedEvent.getBedLocation()); + if (bedLocation == null) yield null; + if (bedLocation.getWorld() == null) yield null; + yield new PlayerBedEnterEvent(player, bedLocation.getBlock()); + } + case PLAYER_BED_LEAVE -> { + patchbukkit.events.PlayerBedLeaveEvent bedEvent = event.getPlayerBedLeave(); + Player player = getPlayer(bedEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + Location bedLocation = BridgeUtils.convertLocation(bedEvent.getBedLocation()); + if (bedLocation == null) yield null; + if (bedLocation.getWorld() == null) yield null; + yield new PlayerBedLeaveEvent(player, bedLocation.getBlock()); + } case PLAYER_CHAT -> { PlayerChatEvent chatEvent = event.getPlayerChat(); Player player = getPlayer(chatEvent.getPlayerUuid().getValue()); @@ -552,6 +572,26 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .setSlot(slot) .build() ); + } else if (event instanceof PlayerBedEnterEvent bedEvent) { + Location location = bedEvent.getBed().getLocation(); + eventBuilder.setPlayerBedEnter( + patchbukkit.events.PlayerBedEnterEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(bedEvent.getPlayer().getUniqueId().toString()) + .build()) + .setBedLocation(BridgeUtils.convertLocation(location)) + .build() + ); + } else if (event instanceof PlayerBedLeaveEvent bedEvent) { + Location location = bedEvent.getBed().getLocation(); + eventBuilder.setPlayerBedLeave( + patchbukkit.events.PlayerBedLeaveEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(bedEvent.getPlayer().getUniqueId().toString()) + .build()) + .setBedLocation(BridgeUtils.convertLocation(location)) + .build() + ); } else if (event instanceof AsyncPlayerChatEvent chatEvent) { var playerEventBuilder = patchbukkit.events.PlayerChatEvent.newBuilder() .setPlayerUuid(UUID.newBuilder() 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 b5cb0db..9481372 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -222,6 +222,28 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.player.PlayerBedEnterEvent": + var bedEnterEvent = (org.bukkit.event.player.PlayerBedEnterEvent) event; + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerBedEnter( + patchbukkit.events.PlayerBedEnterEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(bedEnterEvent.getPlayer().getUniqueId())) + .setBedLocation(BridgeUtils.convertLocation(bedEnterEvent.getBed().getLocation())) + .build() + ).build() + ); + break; + case "org.bukkit.event.player.PlayerBedLeaveEvent": + var bedLeaveEvent = (org.bukkit.event.player.PlayerBedLeaveEvent) event; + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerBedLeave( + patchbukkit.events.PlayerBedLeaveEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(bedLeaveEvent.getPlayer().getUniqueId())) + .setBedLocation(BridgeUtils.convertLocation(bedLeaveEvent.getBed().getLocation())) + .build() + ).build() + ); + break; case "org.bukkit.event.player.AsyncPlayerChatEvent": var chatEvent = (org.bukkit.event.player.AsyncPlayerChatEvent) event; var chatBuilder = PlayerChatEvent.newBuilder() diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index 197c866..d1b21c9 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -34,6 +34,8 @@ message Event { PlayerAdvancementDoneEvent player_advancement_done = 19; PlayerAnimationEvent player_animation = 20; PlayerArmorStandManipulateEvent player_armor_stand_manipulate = 21; + PlayerBedEnterEvent player_bed_enter = 22; + PlayerBedLeaveEvent player_bed_leave = 23; } } diff --git a/proto/patchbukkit/events/player_events.proto b/proto/patchbukkit/events/player_events.proto index c302347..a78b4ce 100644 --- a/proto/patchbukkit/events/player_events.proto +++ b/proto/patchbukkit/events/player_events.proto @@ -85,3 +85,13 @@ message PlayerArmorStandManipulateEvent { string armor_stand_item_key = 4; string slot = 5; } + +message PlayerBedEnterEvent { + patchbukkit.common.UUID player_uuid = 1; + patchbukkit.common.Location bed_location = 2; +} + +message PlayerBedLeaveEvent { + patchbukkit.common.UUID player_uuid = 1; + patchbukkit.common.Location bed_location = 2; +} diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index 6972ad7..256da5a 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -21,6 +21,7 @@ use crate::proto::patchbukkit::events::{ PlayerLoginEvent, PlayerTeleportEvent, PlayerChangeWorldEvent, PlayerGamemodeChangeEvent, AsyncPlayerPreLoginEvent, PlayerAdvancementDoneEvent, PlayerAnimationEvent, PlayerArmorStandManipulateEvent, + PlayerBedEnterEvent, PlayerBedLeaveEvent, }; pub struct EventContext { @@ -268,6 +269,78 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_armor_stand_manipulate } } +impl PatchBukkitEvent for pumpkin::plugin::player::player_bed_enter::PlayerBedEnterEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let world_uuid = self.player.world().uuid; + + JvmEventPayload { + event: Event { + data: Some(Data::PlayerBedEnter(PlayerBedEnterEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + bed_location: Some(build_location(world_uuid, &self.bed_position, 0.0, 0.0)), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerBedEnter(event) => { + if let Some(location) = event.bed_location { + if let Some(pos) = location_to_vec3(location) { + self.bed_position = pos; + } + } + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_bed_leave::PlayerBedLeaveEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let world_uuid = self.player.world().uuid; + + JvmEventPayload { + event: Event { + data: Some(Data::PlayerBedLeave(PlayerBedLeaveEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + bed_location: Some(build_location(world_uuid, &self.bed_position, 0.0, 0.0)), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerBedLeave(event) => { + if let Some(location) = event.bed_location { + if let Some(pos) = location_to_vec3(location) { + self.bed_position = pos; + } + } + } + _ => {} + } + + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::player::player_move::PlayerMoveEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { let world_uuid = self.player.world().uuid; diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index fc51108..b7217bc 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -12,6 +12,8 @@ use pumpkin::plugin::player::player_pre_login::PlayerPreLoginEvent; use pumpkin::plugin::player::player_advancement_done::PlayerAdvancementDoneEvent; use pumpkin::plugin::player::player_animation::PlayerAnimationEvent; use pumpkin::plugin::player::player_armor_stand_manipulate::PlayerArmorStandManipulateEvent; +use pumpkin::plugin::player::player_bed_enter::PlayerBedEnterEvent; +use pumpkin::plugin::player::player_bed_leave::PlayerBedLeaveEvent; use pumpkin::plugin::player::player_leave::PlayerLeaveEvent; use pumpkin::plugin::player::player_move::PlayerMoveEvent; use pumpkin::plugin::player::player_teleport::PlayerTeleportEvent; @@ -184,6 +186,40 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.player.PlayerBedEnterEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_bed_enter::PlayerBedEnterEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_bed_enter::PlayerBedEnterEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerBedLeaveEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_bed_leave::PlayerBedLeaveEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_bed_leave::PlayerBedLeaveEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.player.PlayerTeleportEvent" => { context .register_event::< @@ -514,6 +550,32 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let uuid = + uuid::Uuid::parse_str(&player_bed_enter_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let position = player_bed_enter_event_data + .bed_location + .and_then(|loc| loc.position) + .map(|pos| Vector3::new(pos.x, pos.y, pos.z)) + .unwrap_or_else(|| player.position()); + let pumpkin_event = PlayerBedEnterEvent::new(player, position); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerBedLeave(player_bed_leave_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_bed_leave_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let position = player_bed_leave_event_data + .bed_location + .and_then(|loc| loc.position) + .map(|pos| Vector3::new(pos.x, pos.y, pos.z)) + .unwrap_or_else(|| player.position()); + let pumpkin_event = PlayerBedLeaveEvent::new(player, position); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } Data::PlayerTeleport(player_teleport_event_data) => { let uuid = uuid::Uuid::parse_str(&player_teleport_event_data.player_uuid?.value).ok()?; From 80e44eb90a1b1bf0c6761835645135b20472b2c0 Mon Sep 17 00:00:00 2001 From: yunuservices Date: Wed, 4 Feb 2026 22:07:38 +0300 Subject: [PATCH 11/56] Add bucket events bridge --- .../events/PatchBukkitEventFactory.java | 159 ++++++++++++++++++ .../events/PatchBukkitEventManager.java | 72 ++++++++ proto/patchbukkit/events/event.proto | 3 + proto/patchbukkit/events/player_events.proto | 27 +++ rust/src/events/handler.rs | 158 +++++++++++++++++ rust/src/java/native_callbacks/events.rs | 117 +++++++++++++ 6 files changed, 536 insertions(+) diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index 29744f3..ff761ba 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -23,6 +23,9 @@ import org.bukkit.event.player.PlayerArmorStandManipulateEvent; import org.bukkit.event.player.PlayerBedEnterEvent; import org.bukkit.event.player.PlayerBedLeaveEvent; +import org.bukkit.event.player.PlayerBucketEmptyEvent; +import org.bukkit.event.player.PlayerBucketFillEvent; +import org.bukkit.event.player.PlayerBucketEntityEvent; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.server.BroadcastMessageEvent; @@ -43,6 +46,7 @@ import org.bukkit.block.BlockFace; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.block.Block; import org.bukkit.Material; import org.bukkit.GameMode; import org.bukkit.NamespacedKey; @@ -258,6 +262,99 @@ public static org.bukkit.event.Event createEvent(@NotNull Event event) { if (bedLocation.getWorld() == null) yield null; yield new PlayerBedLeaveEvent(player, bedLocation.getBlock()); } + case PLAYER_BUCKET_EMPTY -> { + patchbukkit.events.PlayerBucketEmptyEvent bucketEvent = event.getPlayerBucketEmpty(); + Player player = getPlayer(bucketEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + Location location = BridgeUtils.convertLocation(bucketEvent.getLocation()); + if (location == null || !(location.getWorld() instanceof PatchBukkitWorld world)) { + yield null; + } + Block block = PatchBukkitBlock.create( + world, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ(), + bucketEvent.getBlockKey() + ); + BlockFace face = BlockFace.SELF; + if (!bucketEvent.getBlockFace().isEmpty()) { + try { + face = BlockFace.valueOf(bucketEvent.getBlockFace()); + } catch (IllegalArgumentException ignored) { + face = BlockFace.SELF; + } + } + ItemStack item = materialToItem(bucketEvent.getBucketItemKey()); + Material bucket = item.getType(); + EquipmentSlot slot = EquipmentSlot.HAND; + if (!bucketEvent.getHand().isEmpty()) { + try { + slot = EquipmentSlot.valueOf(bucketEvent.getHand()); + } catch (IllegalArgumentException ignored) { + slot = EquipmentSlot.HAND; + } + } + yield new PlayerBucketEmptyEvent(player, block, block, face, bucket, item, slot); + } + case PLAYER_BUCKET_FILL -> { + patchbukkit.events.PlayerBucketFillEvent bucketEvent = event.getPlayerBucketFill(); + Player player = getPlayer(bucketEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + Location location = BridgeUtils.convertLocation(bucketEvent.getLocation()); + if (location == null || !(location.getWorld() instanceof PatchBukkitWorld world)) { + yield null; + } + Block block = PatchBukkitBlock.create( + world, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ(), + bucketEvent.getBlockKey() + ); + BlockFace face = BlockFace.SELF; + if (!bucketEvent.getBlockFace().isEmpty()) { + try { + face = BlockFace.valueOf(bucketEvent.getBlockFace()); + } catch (IllegalArgumentException ignored) { + face = BlockFace.SELF; + } + } + ItemStack item = materialToItem(bucketEvent.getBucketItemKey()); + Material bucket = item.getType(); + EquipmentSlot slot = EquipmentSlot.HAND; + if (!bucketEvent.getHand().isEmpty()) { + try { + slot = EquipmentSlot.valueOf(bucketEvent.getHand()); + } catch (IllegalArgumentException ignored) { + slot = EquipmentSlot.HAND; + } + } + yield new PlayerBucketFillEvent(player, block, block, face, bucket, item, slot); + } + case PLAYER_BUCKET_ENTITY -> { + patchbukkit.events.PlayerBucketEntityEvent bucketEvent = event.getPlayerBucketEntity(); + Player player = getPlayer(bucketEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + java.util.UUID entityUuid; + try { + entityUuid = java.util.UUID.fromString(bucketEvent.getEntityUuid().getValue()); + } catch (IllegalArgumentException e) { + yield null; + } + PatchBukkitEntity entity = new PatchBukkitEntity(entityUuid, bucketEvent.getEntityType()); + ItemStack originalBucket = materialToItem(bucketEvent.getOriginalBucketKey()); + ItemStack entityBucket = materialToItem(bucketEvent.getEntityBucketKey()); + EquipmentSlot slot = EquipmentSlot.HAND; + if (!bucketEvent.getHand().isEmpty()) { + try { + slot = EquipmentSlot.valueOf(bucketEvent.getHand()); + } catch (IllegalArgumentException ignored) { + slot = EquipmentSlot.HAND; + } + } + yield new PlayerBucketEntityEvent(player, entity, originalBucket, entityBucket, slot); + } case PLAYER_CHAT -> { PlayerChatEvent chatEvent = event.getPlayerChat(); Player player = getPlayer(chatEvent.getPlayerUuid().getValue()); @@ -592,6 +689,68 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .setBedLocation(BridgeUtils.convertLocation(location)) .build() ); + } else if (event instanceof PlayerBucketEmptyEvent bucketEvent) { + Location location = bucketEvent.getBlock().getLocation(); + String blockKey = bucketEvent.getBlock().getType().getKey().toString(); + String face = bucketEvent.getBlockFace() != null ? bucketEvent.getBlockFace().name() : ""; + String bucketKey = bucketEvent.getItemStack() != null + ? bucketEvent.getItemStack().getType().getKey().toString() + : "minecraft:air"; + String hand = bucketEvent.getHand() != null ? bucketEvent.getHand().name() : "HAND"; + eventBuilder.setPlayerBucketEmpty( + patchbukkit.events.PlayerBucketEmptyEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(bucketEvent.getPlayer().getUniqueId().toString()) + .build()) + .setLocation(BridgeUtils.convertLocation(location)) + .setBlockKey(blockKey) + .setBlockFace(face) + .setBucketItemKey(bucketKey) + .setHand(hand) + .build() + ); + } else if (event instanceof PlayerBucketFillEvent bucketEvent) { + Location location = bucketEvent.getBlock().getLocation(); + String blockKey = bucketEvent.getBlock().getType().getKey().toString(); + String face = bucketEvent.getBlockFace() != null ? bucketEvent.getBlockFace().name() : ""; + String bucketKey = bucketEvent.getItemStack() != null + ? bucketEvent.getItemStack().getType().getKey().toString() + : "minecraft:air"; + String hand = bucketEvent.getHand() != null ? bucketEvent.getHand().name() : "HAND"; + eventBuilder.setPlayerBucketFill( + patchbukkit.events.PlayerBucketFillEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(bucketEvent.getPlayer().getUniqueId().toString()) + .build()) + .setLocation(BridgeUtils.convertLocation(location)) + .setBlockKey(blockKey) + .setBlockFace(face) + .setBucketItemKey(bucketKey) + .setHand(hand) + .build() + ); + } else if (event instanceof PlayerBucketEntityEvent bucketEvent) { + String originalBucket = bucketEvent.getOriginalBucket() != null + ? bucketEvent.getOriginalBucket().getType().getKey().toString() + : "minecraft:air"; + String entityBucket = bucketEvent.getEntityBucket() != null + ? bucketEvent.getEntityBucket().getType().getKey().toString() + : "minecraft:air"; + String hand = bucketEvent.getHand() != null ? bucketEvent.getHand().name() : "HAND"; + eventBuilder.setPlayerBucketEntity( + patchbukkit.events.PlayerBucketEntityEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(bucketEvent.getPlayer().getUniqueId().toString()) + .build()) + .setEntityUuid(UUID.newBuilder() + .setValue(bucketEvent.getEntity().getUniqueId().toString()) + .build()) + .setEntityType(bucketEvent.getEntity().getType().name()) + .setOriginalBucketKey(originalBucket) + .setEntityBucketKey(entityBucket) + .setHand(hand) + .build() + ); } else if (event instanceof AsyncPlayerChatEvent chatEvent) { var playerEventBuilder = patchbukkit.events.PlayerChatEvent.newBuilder() .setPlayerUuid(UUID.newBuilder() 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 9481372..84efaf0 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -244,6 +244,78 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.player.PlayerBucketEmptyEvent": + var bucketEmptyEvent = (org.bukkit.event.player.PlayerBucketEmptyEvent) event; + String emptyFace = bucketEmptyEvent.getBlockFace() != null + ? bucketEmptyEvent.getBlockFace().name() + : ""; + String emptyBucket = bucketEmptyEvent.getItemStack() != null + ? bucketEmptyEvent.getItemStack().getType().getKey().toString() + : "minecraft:air"; + String emptyHand = bucketEmptyEvent.getHand() != null + ? bucketEmptyEvent.getHand().name() + : "HAND"; + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerBucketEmpty( + patchbukkit.events.PlayerBucketEmptyEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(bucketEmptyEvent.getPlayer().getUniqueId())) + .setLocation(BridgeUtils.convertLocation(bucketEmptyEvent.getBlock().getLocation())) + .setBlockKey(bucketEmptyEvent.getBlock().getType().getKey().toString()) + .setBlockFace(emptyFace) + .setBucketItemKey(emptyBucket) + .setHand(emptyHand) + .build() + ).build() + ); + break; + case "org.bukkit.event.player.PlayerBucketFillEvent": + var bucketFillEvent = (org.bukkit.event.player.PlayerBucketFillEvent) event; + String fillFace = bucketFillEvent.getBlockFace() != null + ? bucketFillEvent.getBlockFace().name() + : ""; + String fillBucket = bucketFillEvent.getItemStack() != null + ? bucketFillEvent.getItemStack().getType().getKey().toString() + : "minecraft:air"; + String fillHand = bucketFillEvent.getHand() != null + ? bucketFillEvent.getHand().name() + : "HAND"; + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerBucketFill( + patchbukkit.events.PlayerBucketFillEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(bucketFillEvent.getPlayer().getUniqueId())) + .setLocation(BridgeUtils.convertLocation(bucketFillEvent.getBlock().getLocation())) + .setBlockKey(bucketFillEvent.getBlock().getType().getKey().toString()) + .setBlockFace(fillFace) + .setBucketItemKey(fillBucket) + .setHand(fillHand) + .build() + ).build() + ); + break; + case "org.bukkit.event.player.PlayerBucketEntityEvent": + var bucketEntityEvent = (org.bukkit.event.player.PlayerBucketEntityEvent) event; + String originalBucket = bucketEntityEvent.getOriginalBucket() != null + ? bucketEntityEvent.getOriginalBucket().getType().getKey().toString() + : "minecraft:air"; + String entityBucket = bucketEntityEvent.getEntityBucket() != null + ? bucketEntityEvent.getEntityBucket().getType().getKey().toString() + : "minecraft:air"; + String entityHand = bucketEntityEvent.getHand() != null + ? bucketEntityEvent.getHand().name() + : "HAND"; + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerBucketEntity( + patchbukkit.events.PlayerBucketEntityEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(bucketEntityEvent.getPlayer().getUniqueId())) + .setEntityUuid(BridgeUtils.convertUuid(bucketEntityEvent.getEntity().getUniqueId())) + .setEntityType(bucketEntityEvent.getEntity().getType().name()) + .setOriginalBucketKey(originalBucket) + .setEntityBucketKey(entityBucket) + .setHand(entityHand) + .build() + ).build() + ); + break; case "org.bukkit.event.player.AsyncPlayerChatEvent": var chatEvent = (org.bukkit.event.player.AsyncPlayerChatEvent) event; var chatBuilder = PlayerChatEvent.newBuilder() diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index d1b21c9..04e2bbd 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -36,6 +36,9 @@ message Event { PlayerArmorStandManipulateEvent player_armor_stand_manipulate = 21; PlayerBedEnterEvent player_bed_enter = 22; PlayerBedLeaveEvent player_bed_leave = 23; + PlayerBucketEmptyEvent player_bucket_empty = 24; + PlayerBucketFillEvent player_bucket_fill = 25; + PlayerBucketEntityEvent player_bucket_entity = 26; } } diff --git a/proto/patchbukkit/events/player_events.proto b/proto/patchbukkit/events/player_events.proto index a78b4ce..85e11ab 100644 --- a/proto/patchbukkit/events/player_events.proto +++ b/proto/patchbukkit/events/player_events.proto @@ -95,3 +95,30 @@ message PlayerBedLeaveEvent { patchbukkit.common.UUID player_uuid = 1; patchbukkit.common.Location bed_location = 2; } + +message PlayerBucketEmptyEvent { + patchbukkit.common.UUID player_uuid = 1; + patchbukkit.common.Location location = 2; + string block_key = 3; + string block_face = 4; + string bucket_item_key = 5; + string hand = 6; +} + +message PlayerBucketFillEvent { + patchbukkit.common.UUID player_uuid = 1; + patchbukkit.common.Location location = 2; + string block_key = 3; + string block_face = 4; + string bucket_item_key = 5; + string hand = 6; +} + +message PlayerBucketEntityEvent { + patchbukkit.common.UUID player_uuid = 1; + patchbukkit.common.UUID entity_uuid = 2; + string entity_type = 3; + string original_bucket_key = 4; + string entity_bucket_key = 5; + string hand = 6; +} diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index 256da5a..d0b86cf 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -22,6 +22,7 @@ use crate::proto::patchbukkit::events::{ AsyncPlayerPreLoginEvent, PlayerAdvancementDoneEvent, PlayerAnimationEvent, PlayerArmorStandManipulateEvent, PlayerBedEnterEvent, PlayerBedLeaveEvent, + PlayerBucketEmptyEvent, PlayerBucketFillEvent, PlayerBucketEntityEvent, }; pub struct EventContext { @@ -341,6 +342,151 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_bed_leave::PlayerBedLe } } +impl PatchBukkitEvent for pumpkin::plugin::player::player_bucket_empty::PlayerBucketEmptyEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let world_uuid = self.player.world().uuid; + JvmEventPayload { + event: Event { + data: Some(Data::PlayerBucketEmpty(PlayerBucketEmptyEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + location: Some(build_location(world_uuid, &self.position, 0.0, 0.0)), + block_key: self.block_key.clone(), + block_face: block_face_to_bukkit(self.face), + bucket_item_key: self.bucket_item_key.clone(), + hand: self.hand.clone(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerBucketEmpty(event) => { + if let Some(location) = event.location { + if let Some(pos) = location_to_vec3(location) { + self.position = pos; + } + } + if !event.block_key.is_empty() { + self.block_key = event.block_key; + } + if !event.bucket_item_key.is_empty() { + self.bucket_item_key = event.bucket_item_key; + } + if !event.hand.is_empty() { + self.hand = event.hand; + } + self.face = bukkit_block_face_from_string(&event.block_face); + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_bucket_fill::PlayerBucketFillEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let world_uuid = self.player.world().uuid; + JvmEventPayload { + event: Event { + data: Some(Data::PlayerBucketFill(PlayerBucketFillEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + location: Some(build_location(world_uuid, &self.position, 0.0, 0.0)), + block_key: self.block_key.clone(), + block_face: block_face_to_bukkit(self.face), + bucket_item_key: self.bucket_item_key.clone(), + hand: self.hand.clone(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerBucketFill(event) => { + if let Some(location) = event.location { + if let Some(pos) = location_to_vec3(location) { + self.position = pos; + } + } + if !event.block_key.is_empty() { + self.block_key = event.block_key; + } + if !event.bucket_item_key.is_empty() { + self.bucket_item_key = event.bucket_item_key; + } + if !event.hand.is_empty() { + self.hand = event.hand; + } + self.face = bukkit_block_face_from_string(&event.block_face); + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_bucket_entity::PlayerBucketEntityEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerBucketEntity(PlayerBucketEntityEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + entity_uuid: Some(Uuid { + value: self.entity_uuid.to_string(), + }), + entity_type: self.entity_type.clone(), + original_bucket_key: self.original_bucket_key.clone(), + entity_bucket_key: self.entity_bucket_key.clone(), + hand: self.hand.clone(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerBucketEntity(event) => { + if let Some(uuid) = event.entity_uuid { + self.entity_uuid = uuid::Uuid::from_str(&uuid.value).ok()?; + } + if !event.entity_type.is_empty() { + self.entity_type = event.entity_type; + } + if !event.original_bucket_key.is_empty() { + self.original_bucket_key = event.original_bucket_key; + } + if !event.entity_bucket_key.is_empty() { + self.entity_bucket_key = event.entity_bucket_key; + } + if !event.hand.is_empty() { + self.hand = event.hand; + } + } + _ => {} + } + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::player::player_move::PlayerMoveEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { let world_uuid = self.player.world().uuid; @@ -935,6 +1081,18 @@ fn block_face_to_bukkit(face: Option) -> String { } } +fn bukkit_block_face_from_string(face: &str) -> Option { + match face { + "UP" => Some(BlockDirection::Up), + "DOWN" => Some(BlockDirection::Down), + "NORTH" => Some(BlockDirection::North), + "SOUTH" => Some(BlockDirection::South), + "WEST" => Some(BlockDirection::West), + "EAST" => Some(BlockDirection::East), + _ => None, + } +} + pub struct PatchBukkitEventHandler { plugin_name: String, command_tx: mpsc::Sender, diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index b7217bc..0504d41 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -14,6 +14,9 @@ use pumpkin::plugin::player::player_animation::PlayerAnimationEvent; use pumpkin::plugin::player::player_armor_stand_manipulate::PlayerArmorStandManipulateEvent; use pumpkin::plugin::player::player_bed_enter::PlayerBedEnterEvent; use pumpkin::plugin::player::player_bed_leave::PlayerBedLeaveEvent; +use pumpkin::plugin::player::player_bucket_empty::PlayerBucketEmptyEvent; +use pumpkin::plugin::player::player_bucket_fill::PlayerBucketFillEvent; +use pumpkin::plugin::player::player_bucket_entity::PlayerBucketEntityEvent; use pumpkin::plugin::player::player_leave::PlayerLeaveEvent; use pumpkin::plugin::player::player_move::PlayerMoveEvent; use pumpkin::plugin::player::player_teleport::PlayerTeleportEvent; @@ -220,6 +223,57 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.player.PlayerBucketEmptyEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_bucket_empty::PlayerBucketEmptyEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_bucket_empty::PlayerBucketEmptyEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerBucketFillEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_bucket_fill::PlayerBucketFillEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_bucket_fill::PlayerBucketFillEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerBucketEntityEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_bucket_entity::PlayerBucketEntityEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_bucket_entity::PlayerBucketEntityEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.player.PlayerTeleportEvent" => { context .register_event::< @@ -576,6 +630,69 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let uuid = + uuid::Uuid::parse_str(&player_bucket_empty_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let position = player_bucket_empty_event_data + .location + .and_then(|loc| loc.position) + .map(|pos| Vector3::new(pos.x, pos.y, pos.z)) + .unwrap_or_else(|| player.position()); + let face = bukkit_block_face_to_direction( + &player_bucket_empty_event_data.block_face, + ); + let pumpkin_event = PlayerBucketEmptyEvent::new( + player, + position, + player_bucket_empty_event_data.block_key, + face, + player_bucket_empty_event_data.bucket_item_key, + player_bucket_empty_event_data.hand, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerBucketFill(player_bucket_fill_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_bucket_fill_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let position = player_bucket_fill_event_data + .location + .and_then(|loc| loc.position) + .map(|pos| Vector3::new(pos.x, pos.y, pos.z)) + .unwrap_or_else(|| player.position()); + let face = bukkit_block_face_to_direction( + &player_bucket_fill_event_data.block_face, + ); + let pumpkin_event = PlayerBucketFillEvent::new( + player, + position, + player_bucket_fill_event_data.block_key, + face, + player_bucket_fill_event_data.bucket_item_key, + player_bucket_fill_event_data.hand, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerBucketEntity(player_bucket_entity_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_bucket_entity_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let entity_uuid = + uuid::Uuid::parse_str(&player_bucket_entity_event_data.entity_uuid?.value).ok()?; + let pumpkin_event = PlayerBucketEntityEvent::new( + player, + entity_uuid, + player_bucket_entity_event_data.entity_type, + player_bucket_entity_event_data.original_bucket_key, + player_bucket_entity_event_data.entity_bucket_key, + player_bucket_entity_event_data.hand, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } Data::PlayerTeleport(player_teleport_event_data) => { let uuid = uuid::Uuid::parse_str(&player_teleport_event_data.player_uuid?.value).ok()?; From 98792030b796413d93813a4d4a0138ff1524c70c Mon Sep 17 00:00:00 2001 From: yunuservices Date: Wed, 4 Feb 2026 22:17:32 +0300 Subject: [PATCH 12/56] Add PlayerChangedMainHandEvent --- .../events/PatchBukkitEventFactory.java | 28 +++++++++++++ .../events/PatchBukkitEventManager.java | 14 +++++++ proto/patchbukkit/events/event.proto | 1 + proto/patchbukkit/events/player_events.proto | 5 +++ rust/src/events/handler.rs | 40 +++++++++++++++++++ rust/src/java/native_callbacks/events.rs | 39 ++++++++++++++++++ 6 files changed, 127 insertions(+) diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index ff761ba..a05110a 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -26,6 +26,7 @@ import org.bukkit.event.player.PlayerBucketEmptyEvent; import org.bukkit.event.player.PlayerBucketFillEvent; import org.bukkit.event.player.PlayerBucketEntityEvent; +import org.bukkit.event.player.PlayerChangedMainHandEvent; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.server.BroadcastMessageEvent; @@ -46,6 +47,7 @@ import org.bukkit.block.BlockFace; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.MainHand; import org.bukkit.block.Block; import org.bukkit.Material; import org.bukkit.GameMode; @@ -355,6 +357,20 @@ public static org.bukkit.event.Event createEvent(@NotNull Event event) { } yield new PlayerBucketEntityEvent(player, entity, originalBucket, entityBucket, slot); } + case PLAYER_CHANGED_MAIN_HAND -> { + patchbukkit.events.PlayerChangedMainHandEvent mainHandEvent = event.getPlayerChangedMainHand(); + Player player = getPlayer(mainHandEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + MainHand mainHand = MainHand.RIGHT; + if (!mainHandEvent.getMainHand().isEmpty()) { + try { + mainHand = MainHand.valueOf(mainHandEvent.getMainHand()); + } catch (IllegalArgumentException ignored) { + mainHand = MainHand.RIGHT; + } + } + yield new PlayerChangedMainHandEvent(player, mainHand); + } case PLAYER_CHAT -> { PlayerChatEvent chatEvent = event.getPlayerChat(); Player player = getPlayer(chatEvent.getPlayerUuid().getValue()); @@ -751,6 +767,18 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .setHand(hand) .build() ); + } else if (event instanceof PlayerChangedMainHandEvent mainHandEvent) { + String mainHand = mainHandEvent.getMainHand() != null + ? mainHandEvent.getMainHand().name() + : "RIGHT"; + eventBuilder.setPlayerChangedMainHand( + patchbukkit.events.PlayerChangedMainHandEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(mainHandEvent.getPlayer().getUniqueId().toString()) + .build()) + .setMainHand(mainHand) + .build() + ); } else if (event instanceof AsyncPlayerChatEvent chatEvent) { var playerEventBuilder = patchbukkit.events.PlayerChatEvent.newBuilder() .setPlayerUuid(UUID.newBuilder() 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 84efaf0..038d2d4 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -316,6 +316,20 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.player.PlayerChangedMainHandEvent": + var mainHandEvent = (org.bukkit.event.player.PlayerChangedMainHandEvent) event; + String mainHand = mainHandEvent.getMainHand() != null + ? mainHandEvent.getMainHand().name() + : "RIGHT"; + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerChangedMainHand( + patchbukkit.events.PlayerChangedMainHandEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(mainHandEvent.getPlayer().getUniqueId())) + .setMainHand(mainHand) + .build() + ).build() + ); + break; case "org.bukkit.event.player.AsyncPlayerChatEvent": var chatEvent = (org.bukkit.event.player.AsyncPlayerChatEvent) event; var chatBuilder = PlayerChatEvent.newBuilder() diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index 04e2bbd..b5a1df8 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -39,6 +39,7 @@ message Event { PlayerBucketEmptyEvent player_bucket_empty = 24; PlayerBucketFillEvent player_bucket_fill = 25; PlayerBucketEntityEvent player_bucket_entity = 26; + PlayerChangedMainHandEvent player_changed_main_hand = 27; } } diff --git a/proto/patchbukkit/events/player_events.proto b/proto/patchbukkit/events/player_events.proto index 85e11ab..2135377 100644 --- a/proto/patchbukkit/events/player_events.proto +++ b/proto/patchbukkit/events/player_events.proto @@ -122,3 +122,8 @@ message PlayerBucketEntityEvent { string entity_bucket_key = 5; string hand = 6; } + +message PlayerChangedMainHandEvent { + patchbukkit.common.UUID player_uuid = 1; + string main_hand = 2; +} diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index d0b86cf..7aa043e 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -7,6 +7,7 @@ use pumpkin::plugin::{BoxFuture, Cancellable, EventHandler, Payload}; use pumpkin::server::Server; use pumpkin_api_macros::with_runtime; use pumpkin_data::{Block, BlockDirection}; +use pumpkin_util::Hand; use pumpkin_util::math::vector3::Vector3; use pumpkin_util::text::TextComponent; use tokio::sync::{mpsc, oneshot}; @@ -23,6 +24,7 @@ use crate::proto::patchbukkit::events::{ PlayerArmorStandManipulateEvent, PlayerBedEnterEvent, PlayerBedLeaveEvent, PlayerBucketEmptyEvent, PlayerBucketFillEvent, PlayerBucketEntityEvent, + PlayerChangedMainHandEvent, }; pub struct EventContext { @@ -487,6 +489,37 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_bucket_entity::PlayerB } } +impl PatchBukkitEvent for pumpkin::plugin::player::player_changed_main_hand::PlayerChangedMainHandEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerChangedMainHand(PlayerChangedMainHandEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + main_hand: bukkit_main_hand(self.main_hand), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerChangedMainHand(event) => { + if let Ok(uuid) = uuid::Uuid::from_str(&event.player_uuid?.value) { + server.get_player_by_uuid(uuid)?; + } + } + _ => {} + } + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::player::player_move::PlayerMoveEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { let world_uuid = self.player.world().uuid; @@ -1093,6 +1126,13 @@ fn bukkit_block_face_from_string(face: &str) -> Option { } } +fn bukkit_main_hand(hand: Hand) -> String { + match hand { + Hand::Left => "LEFT".to_string(), + Hand::Right => "RIGHT".to_string(), + } +} + pub struct PatchBukkitEventHandler { plugin_name: String, command_tx: mpsc::Sender, diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index 0504d41..46ba6b8 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -17,6 +17,7 @@ use pumpkin::plugin::player::player_bed_leave::PlayerBedLeaveEvent; use pumpkin::plugin::player::player_bucket_empty::PlayerBucketEmptyEvent; use pumpkin::plugin::player::player_bucket_fill::PlayerBucketFillEvent; use pumpkin::plugin::player::player_bucket_entity::PlayerBucketEntityEvent; +use pumpkin::plugin::player::player_changed_main_hand::PlayerChangedMainHandEvent; use pumpkin::plugin::player::player_leave::PlayerLeaveEvent; use pumpkin::plugin::player::player_move::PlayerMoveEvent; use pumpkin::plugin::player::player_teleport::PlayerTeleportEvent; @@ -30,6 +31,7 @@ use pumpkin_data::item::Item; use pumpkin_world::item::ItemStack; use pumpkin_util::math::vector3::Vector3; use pumpkin_util::text::TextComponent; +use pumpkin_util::Hand; use tokio::sync::Mutex; use crate::events::handler::PatchBukkitEventHandler; @@ -274,6 +276,23 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.player.PlayerChangedMainHandEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_changed_main_hand::PlayerChangedMainHandEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_changed_main_hand::PlayerChangedMainHandEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.player.PlayerTeleportEvent" => { context .register_event::< @@ -693,6 +712,18 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let uuid = + uuid::Uuid::parse_str(&player_changed_main_hand_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let main_hand = main_hand_from_bukkit( + &player_changed_main_hand_event_data.main_hand, + ) + .unwrap_or(Hand::Right); + let pumpkin_event = PlayerChangedMainHandEvent::new(player, main_hand); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } Data::PlayerTeleport(player_teleport_event_data) => { let uuid = uuid::Uuid::parse_str(&player_teleport_event_data.player_uuid?.value).ok()?; @@ -977,3 +1008,11 @@ fn gamemode_from_bukkit(mode: &str) -> Option { _ => None, } } + +fn main_hand_from_bukkit(hand: &str) -> Option { + match hand { + "LEFT" => Some(Hand::Left), + "RIGHT" => Some(Hand::Right), + _ => None, + } +} From 95437f9851177a0085a74c24f54e0f9d43daa409 Mon Sep 17 00:00:00 2001 From: yunuservices Date: Wed, 4 Feb 2026 22:24:35 +0300 Subject: [PATCH 13/56] Add player channel events --- .../events/PatchBukkitEventFactory.java | 32 +++++++++ .../events/PatchBukkitEventManager.java | 22 ++++++ proto/patchbukkit/events/event.proto | 2 + proto/patchbukkit/events/player_events.proto | 10 +++ rust/src/events/handler.rs | 69 +++++++++++++++++++ rust/src/java/native_callbacks/events.rs | 58 ++++++++++++++++ 6 files changed, 193 insertions(+) diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index a05110a..413cdb0 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -27,6 +27,8 @@ import org.bukkit.event.player.PlayerBucketFillEvent; import org.bukkit.event.player.PlayerBucketEntityEvent; import org.bukkit.event.player.PlayerChangedMainHandEvent; +import org.bukkit.event.player.PlayerRegisterChannelEvent; +import org.bukkit.event.player.PlayerUnregisterChannelEvent; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.server.BroadcastMessageEvent; @@ -371,6 +373,18 @@ public static org.bukkit.event.Event createEvent(@NotNull Event event) { } yield new PlayerChangedMainHandEvent(player, mainHand); } + case PLAYER_REGISTER_CHANNEL -> { + patchbukkit.events.PlayerRegisterChannelEvent channelEvent = event.getPlayerRegisterChannel(); + Player player = getPlayer(channelEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + yield new PlayerRegisterChannelEvent(player, channelEvent.getChannel()); + } + case PLAYER_UNREGISTER_CHANNEL -> { + patchbukkit.events.PlayerUnregisterChannelEvent channelEvent = event.getPlayerUnregisterChannel(); + Player player = getPlayer(channelEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + yield new PlayerUnregisterChannelEvent(player, channelEvent.getChannel()); + } case PLAYER_CHAT -> { PlayerChatEvent chatEvent = event.getPlayerChat(); Player player = getPlayer(chatEvent.getPlayerUuid().getValue()); @@ -779,6 +793,24 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .setMainHand(mainHand) .build() ); + } else if (event instanceof PlayerRegisterChannelEvent registerChannelEvent) { + eventBuilder.setPlayerRegisterChannel( + patchbukkit.events.PlayerRegisterChannelEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(registerChannelEvent.getPlayer().getUniqueId().toString()) + .build()) + .setChannel(registerChannelEvent.getChannel()) + .build() + ); + } else if (event instanceof PlayerUnregisterChannelEvent unregisterChannelEvent) { + eventBuilder.setPlayerUnregisterChannel( + patchbukkit.events.PlayerUnregisterChannelEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(unregisterChannelEvent.getPlayer().getUniqueId().toString()) + .build()) + .setChannel(unregisterChannelEvent.getChannel()) + .build() + ); } else if (event instanceof AsyncPlayerChatEvent chatEvent) { var playerEventBuilder = patchbukkit.events.PlayerChatEvent.newBuilder() .setPlayerUuid(UUID.newBuilder() 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 038d2d4..77ac607 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -330,6 +330,28 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.player.PlayerRegisterChannelEvent": + var registerChannelEvent = (org.bukkit.event.player.PlayerRegisterChannelEvent) event; + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerRegisterChannel( + patchbukkit.events.PlayerRegisterChannelEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(registerChannelEvent.getPlayer().getUniqueId())) + .setChannel(registerChannelEvent.getChannel()) + .build() + ).build() + ); + break; + case "org.bukkit.event.player.PlayerUnregisterChannelEvent": + var unregisterChannelEvent = (org.bukkit.event.player.PlayerUnregisterChannelEvent) event; + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerUnregisterChannel( + patchbukkit.events.PlayerUnregisterChannelEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(unregisterChannelEvent.getPlayer().getUniqueId())) + .setChannel(unregisterChannelEvent.getChannel()) + .build() + ).build() + ); + break; case "org.bukkit.event.player.AsyncPlayerChatEvent": var chatEvent = (org.bukkit.event.player.AsyncPlayerChatEvent) event; var chatBuilder = PlayerChatEvent.newBuilder() diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index b5a1df8..89a17d0 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -40,6 +40,8 @@ message Event { PlayerBucketFillEvent player_bucket_fill = 25; PlayerBucketEntityEvent player_bucket_entity = 26; PlayerChangedMainHandEvent player_changed_main_hand = 27; + PlayerRegisterChannelEvent player_register_channel = 28; + PlayerUnregisterChannelEvent player_unregister_channel = 29; } } diff --git a/proto/patchbukkit/events/player_events.proto b/proto/patchbukkit/events/player_events.proto index 2135377..870df1c 100644 --- a/proto/patchbukkit/events/player_events.proto +++ b/proto/patchbukkit/events/player_events.proto @@ -127,3 +127,13 @@ message PlayerChangedMainHandEvent { patchbukkit.common.UUID player_uuid = 1; string main_hand = 2; } + +message PlayerRegisterChannelEvent { + patchbukkit.common.UUID player_uuid = 1; + string channel = 2; +} + +message PlayerUnregisterChannelEvent { + patchbukkit.common.UUID player_uuid = 1; + string channel = 2; +} diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index 7aa043e..7cb9ec4 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -25,6 +25,7 @@ use crate::proto::patchbukkit::events::{ PlayerBedEnterEvent, PlayerBedLeaveEvent, PlayerBucketEmptyEvent, PlayerBucketFillEvent, PlayerBucketEntityEvent, PlayerChangedMainHandEvent, + PlayerRegisterChannelEvent, PlayerUnregisterChannelEvent, }; pub struct EventContext { @@ -520,6 +521,74 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_changed_main_hand::Pla } } +impl PatchBukkitEvent for pumpkin::plugin::player::player_register_channel::PlayerRegisterChannelEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerRegisterChannel(PlayerRegisterChannelEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + channel: self.channel.clone(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerRegisterChannel(event) => { + if let Ok(uuid) = uuid::Uuid::from_str(&event.player_uuid?.value) { + server.get_player_by_uuid(uuid)?; + } + if !event.channel.is_empty() { + self.channel = event.channel; + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_unregister_channel::PlayerUnregisterChannelEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerUnregisterChannel(PlayerUnregisterChannelEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + channel: self.channel.clone(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerUnregisterChannel(event) => { + if let Ok(uuid) = uuid::Uuid::from_str(&event.player_uuid?.value) { + server.get_player_by_uuid(uuid)?; + } + if !event.channel.is_empty() { + self.channel = event.channel; + } + } + _ => {} + } + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::player::player_move::PlayerMoveEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { let world_uuid = self.player.world().uuid; diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index 46ba6b8..ed2a9da 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -18,6 +18,8 @@ use pumpkin::plugin::player::player_bucket_empty::PlayerBucketEmptyEvent; use pumpkin::plugin::player::player_bucket_fill::PlayerBucketFillEvent; use pumpkin::plugin::player::player_bucket_entity::PlayerBucketEntityEvent; use pumpkin::plugin::player::player_changed_main_hand::PlayerChangedMainHandEvent; +use pumpkin::plugin::player::player_register_channel::PlayerRegisterChannelEvent; +use pumpkin::plugin::player::player_unregister_channel::PlayerUnregisterChannelEvent; use pumpkin::plugin::player::player_leave::PlayerLeaveEvent; use pumpkin::plugin::player::player_move::PlayerMoveEvent; use pumpkin::plugin::player::player_teleport::PlayerTeleportEvent; @@ -293,6 +295,40 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.player.PlayerRegisterChannelEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_register_channel::PlayerRegisterChannelEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_register_channel::PlayerRegisterChannelEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerUnregisterChannelEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_unregister_channel::PlayerUnregisterChannelEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_unregister_channel::PlayerUnregisterChannelEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.player.PlayerTeleportEvent" => { context .register_event::< @@ -724,6 +760,28 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let uuid = + uuid::Uuid::parse_str(&player_register_channel_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let pumpkin_event = PlayerRegisterChannelEvent::new( + player, + player_register_channel_event_data.channel, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerUnregisterChannel(player_unregister_channel_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_unregister_channel_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let pumpkin_event = PlayerUnregisterChannelEvent::new( + player, + player_unregister_channel_event_data.channel, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } Data::PlayerTeleport(player_teleport_event_data) => { let uuid = uuid::Uuid::parse_str(&player_teleport_event_data.player_uuid?.value).ok()?; From 4bfe6607d2adefbab5b2ae3b3a033ec025f4a3c9 Mon Sep 17 00:00:00 2001 From: yunuservices Date: Wed, 4 Feb 2026 22:34:14 +0300 Subject: [PATCH 14/56] Add command preprocess/send events --- .../events/PatchBukkitEventFactory.java | 14 +++++++ .../events/PatchBukkitEventManager.java | 11 ++++++ proto/patchbukkit/events/event.proto | 1 + proto/patchbukkit/events/player_events.proto | 5 +++ rust/src/events/handler.rs | 38 +++++++++++++++++-- rust/src/java/native_callbacks/events.rs | 29 +++++++++++++- 6 files changed, 94 insertions(+), 4 deletions(-) diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index 413cdb0..2a10162 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -12,6 +12,7 @@ import org.bukkit.event.player.AsyncPlayerChatEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerCommandPreprocessEvent; +import org.bukkit.event.player.PlayerCommandSendEvent; import org.bukkit.event.player.PlayerLoginEvent; import org.bukkit.event.player.AsyncPlayerPreLoginEvent; import org.bukkit.event.player.PlayerTeleportEvent; @@ -411,6 +412,12 @@ public static org.bukkit.event.Event createEvent(@NotNull Event event) { yield new PlayerCommandPreprocessEvent(player, commandEvent.getCommand()); } + case PLAYER_COMMAND_SEND -> { + patchbukkit.events.PlayerCommandSendEvent commandEvent = event.getPlayerCommandSend(); + Player player = getPlayer(commandEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + yield new PlayerCommandSendEvent(player, new HashSet<>(commandEvent.getCommandsList())); + } case PLAYER_INTERACT -> { patchbukkit.events.PlayerInteractEvent interactEvent = event.getPlayerInteract(); Player player = getPlayer(interactEvent.getPlayerUuid().getValue()); @@ -836,6 +843,13 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .setCommand(commandEvent.getMessage()) .build() ); + } else if (event instanceof PlayerCommandSendEvent commandSendEvent) { + var builder = patchbukkit.events.PlayerCommandSendEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(commandSendEvent.getPlayer().getUniqueId().toString()) + .build()); + builder.addAllCommands(commandSendEvent.getCommands()); + eventBuilder.setPlayerCommandSend(builder.build()); } else if (event instanceof PlayerInteractEvent interactEvent) { var block = interactEvent.getClickedBlock(); var location = block != null ? block.getLocation() : null; 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 77ac607..4903d61 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -375,6 +375,17 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.player.PlayerCommandSendEvent": + var commandSendEvent = (org.bukkit.event.player.PlayerCommandSendEvent) event; + var commandSendBuilder = patchbukkit.events.PlayerCommandSendEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(commandSendEvent.getPlayer().getUniqueId())); + commandSendBuilder.addAllCommands(commandSendEvent.getCommands()); + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerCommandSend( + commandSendBuilder.build() + ).build() + ); + break; case "org.bukkit.event.player.PlayerInteractEvent": var interactEvent = (org.bukkit.event.player.PlayerInteractEvent) event; var clicked = interactEvent.getClickedBlock(); diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index 89a17d0..341f7d9 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -42,6 +42,7 @@ message Event { PlayerChangedMainHandEvent player_changed_main_hand = 27; PlayerRegisterChannelEvent player_register_channel = 28; PlayerUnregisterChannelEvent player_unregister_channel = 29; + PlayerCommandSendEvent player_command_send = 30; } } diff --git a/proto/patchbukkit/events/player_events.proto b/proto/patchbukkit/events/player_events.proto index 870df1c..f416de0 100644 --- a/proto/patchbukkit/events/player_events.proto +++ b/proto/patchbukkit/events/player_events.proto @@ -60,6 +60,11 @@ message PlayerCommandEvent { string command = 2; } +message PlayerCommandSendEvent { + patchbukkit.common.UUID player_uuid = 1; + repeated string commands = 2; +} + message AsyncPlayerPreLoginEvent { string name = 1; patchbukkit.common.UUID player_uuid = 2; diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index 7cb9ec4..540cc0e 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -16,7 +16,7 @@ use crate::java::jvm::commands::JvmCommand; use crate::proto::patchbukkit::common::{Location, Uuid, Vec3, World}; use crate::proto::patchbukkit::events::event::Data; use crate::proto::patchbukkit::events::{ - BlockBreakEvent, BlockPlaceEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerJoinEvent, + BlockBreakEvent, BlockPlaceEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, PlayerLeaveEvent, PlayerMoveEvent, PlayerInteractEvent, ServerBroadcastEvent, ServerCommandEvent, EntityDamageEvent, EntityDeathEvent, EntitySpawnEvent, PlayerLoginEvent, PlayerTeleportEvent, PlayerChangeWorldEvent, PlayerGamemodeChangeEvent, @@ -813,7 +813,7 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_chat::PlayerChatEvent } } -impl PatchBukkitEvent for pumpkin::plugin::player::player_command_send::PlayerCommandSendEvent { +impl PatchBukkitEvent for pumpkin::plugin::player::player_command_preprocess::PlayerCommandPreprocessEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { JvmEventPayload { event: Event { @@ -834,7 +834,39 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_command_send::PlayerCo fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { match data { Data::PlayerCommand(event) => { - self.command = event.command; + if !event.command.is_empty() { + self.command = event.command; + } + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_command_send::PlayerCommandSendEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerCommandSend(crate::proto::patchbukkit::events::PlayerCommandSendEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + commands: self.commands.clone(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerCommandSend(event) => { + self.commands = event.commands; } _ => {} } diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index ed2a9da..2142eb9 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -4,6 +4,7 @@ use pumpkin::plugin::EventPriority; use pumpkin::plugin::block::block_break::BlockBreakEvent; use pumpkin::plugin::block::block_place::BlockPlaceEvent; use pumpkin::plugin::player::player_chat::PlayerChatEvent; +use pumpkin::plugin::player::player_command_preprocess::PlayerCommandPreprocessEvent; use pumpkin::plugin::player::player_command_send::PlayerCommandSendEvent; use pumpkin::plugin::player::player_interact_event::{InteractAction, PlayerInteractEvent}; use pumpkin::plugin::player::player_join::PlayerJoinEvent; @@ -394,6 +395,23 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O .await; } "org.bukkit.event.player.PlayerCommandPreprocessEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_command_preprocess::PlayerCommandPreprocessEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_command_preprocess::PlayerCommandPreprocessEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerCommandSendEvent" => { context .register_event::< pumpkin::plugin::player::player_command_send::PlayerCommandSendEvent, @@ -882,7 +900,16 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let uuid = + uuid::Uuid::parse_str(&player_command_send_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let pumpkin_event = + PlayerCommandSendEvent::new(player, player_command_send_event_data.commands); context.server.plugin_manager.fire(pumpkin_event).await; Some(true) } From 7dc20eca3e71efbe1032ae79fd67d8bf9cfa0e25 Mon Sep 17 00:00:00 2001 From: yunuservices Date: Wed, 4 Feb 2026 22:49:18 +0300 Subject: [PATCH 15/56] Add PlayerDropItemEvent --- .../patchbukkit/entity/PatchBukkitItem.java | 93 +++++++++++++++++++ .../events/PatchBukkitEventFactory.java | 43 +++++++++ .../events/PatchBukkitEventManager.java | 22 +++++ proto/patchbukkit/events/event.proto | 1 + proto/patchbukkit/events/player_events.proto | 7 ++ rust/src/events/handler.rs | 68 +++++++++++++- rust/src/java/native_callbacks/events.rs | 40 ++++++++ 7 files changed, 273 insertions(+), 1 deletion(-) create mode 100644 java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitItem.java diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitItem.java b/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitItem.java new file mode 100644 index 0000000..1e5e849 --- /dev/null +++ b/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitItem.java @@ -0,0 +1,93 @@ +package org.patchbukkit.entity; + +import java.util.UUID; + +import org.bukkit.entity.Item; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class PatchBukkitItem extends PatchBukkitEntity implements Item { + private ItemStack itemStack; + private int pickupDelay = 10; + private boolean unlimitedLifetime = false; + private boolean canMobPickup = true; + private boolean canPlayerPickup = true; + private UUID owner; + private UUID thrower; + + public PatchBukkitItem(@NotNull UUID uuid, @NotNull ItemStack itemStack) { + super(uuid, "ITEM"); + this.itemStack = itemStack; + } + + @Override + public @NotNull ItemStack getItemStack() { + return itemStack; + } + + @Override + public void setItemStack(@NotNull ItemStack stack) { + this.itemStack = stack; + } + + @Override + public int getPickupDelay() { + return pickupDelay; + } + + @Override + public void setPickupDelay(int delay) { + this.pickupDelay = delay; + } + + @Override + public void setUnlimitedLifetime(boolean value) { + this.unlimitedLifetime = value; + } + + @Override + public boolean isUnlimitedLifetime() { + return unlimitedLifetime; + } + + @Override + public void setCanMobPickup(boolean value) { + this.canMobPickup = value; + } + + @Override + public boolean canMobPickup() { + return canMobPickup; + } + + @Override + public void setCanPlayerPickup(boolean value) { + this.canPlayerPickup = value; + } + + @Override + public boolean canPlayerPickup() { + return canPlayerPickup; + } + + @Override + public void setOwner(@Nullable UUID owner) { + this.owner = owner; + } + + @Override + public @Nullable UUID getOwner() { + return owner; + } + + @Override + public void setThrower(@Nullable UUID thrower) { + this.thrower = thrower; + } + + @Override + public @Nullable UUID getThrower() { + return thrower; + } +} diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index 2a10162..45d8ce4 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -30,6 +30,7 @@ import org.bukkit.event.player.PlayerChangedMainHandEvent; import org.bukkit.event.player.PlayerRegisterChannelEvent; import org.bukkit.event.player.PlayerUnregisterChannelEvent; +import org.bukkit.event.player.PlayerDropItemEvent; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.server.BroadcastMessageEvent; @@ -47,6 +48,7 @@ import org.patchbukkit.entity.PatchBukkitEntity; import org.patchbukkit.entity.PatchBukkitLivingEntity; import org.patchbukkit.entity.PatchBukkitArmorStand; +import org.patchbukkit.entity.PatchBukkitItem; import org.bukkit.block.BlockFace; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.EquipmentSlot; @@ -418,6 +420,20 @@ public static org.bukkit.event.Event createEvent(@NotNull Event event) { if (player == null) yield null; yield new PlayerCommandSendEvent(player, new HashSet<>(commandEvent.getCommandsList())); } + case PLAYER_DROP_ITEM -> { + patchbukkit.events.PlayerDropItemEvent dropEvent = event.getPlayerDropItem(); + Player player = getPlayer(dropEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + java.util.UUID itemUuid; + try { + itemUuid = java.util.UUID.fromString(dropEvent.getItemUuid().getValue()); + } catch (IllegalArgumentException e) { + yield null; + } + ItemStack stack = materialToItem(dropEvent.getItemKey(), dropEvent.getItemAmount()); + PatchBukkitItem item = new PatchBukkitItem(itemUuid, stack); + yield new PlayerDropItemEvent(player, item); + } case PLAYER_INTERACT -> { patchbukkit.events.PlayerInteractEvent interactEvent = event.getPlayerInteract(); Player player = getPlayer(interactEvent.getPlayerUuid().getValue()); @@ -850,6 +866,26 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .build()); builder.addAllCommands(commandSendEvent.getCommands()); eventBuilder.setPlayerCommandSend(builder.build()); + } else if (event instanceof PlayerDropItemEvent dropEvent) { + var item = dropEvent.getItemDrop(); + String itemKey = "minecraft:air"; + int itemAmount = 0; + if (item != null && item.getItemStack() != null) { + itemKey = item.getItemStack().getType().getKey().toString(); + itemAmount = item.getItemStack().getAmount(); + } + eventBuilder.setPlayerDropItem( + patchbukkit.events.PlayerDropItemEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(dropEvent.getPlayer().getUniqueId().toString()) + .build()) + .setItemUuid(UUID.newBuilder() + .setValue(item != null ? item.getUniqueId().toString() : java.util.UUID.randomUUID().toString()) + .build()) + .setItemKey(itemKey) + .setItemAmount(itemAmount) + .build() + ); } else if (event instanceof PlayerInteractEvent interactEvent) { var block = interactEvent.getClickedBlock(); var location = block != null ? block.getLocation() : null; @@ -988,6 +1024,13 @@ private static PlayerLoginEvent createLoginEvent(@NotNull Player player) { } } + @NotNull + private static ItemStack materialToItem(@NotNull String key, int amount) { + ItemStack stack = materialToItem(key); + stack.setAmount(Math.max(amount, 0)); + return stack; + } + @NotNull private static ItemStack materialToItem(@NotNull String key) { if (key.isEmpty()) { 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 4903d61..7ef644d 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -386,6 +386,28 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.player.PlayerDropItemEvent": + var dropEvent = (org.bukkit.event.player.PlayerDropItemEvent) event; + var item = dropEvent.getItemDrop(); + String dropKey = "minecraft:air"; + int dropAmount = 0; + java.util.UUID itemUuid = java.util.UUID.randomUUID(); + if (item != null && item.getItemStack() != null) { + dropKey = item.getItemStack().getType().getKey().toString(); + dropAmount = item.getItemStack().getAmount(); + itemUuid = item.getUniqueId(); + } + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerDropItem( + patchbukkit.events.PlayerDropItemEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(dropEvent.getPlayer().getUniqueId())) + .setItemUuid(BridgeUtils.convertUuid(itemUuid)) + .setItemKey(dropKey) + .setItemAmount(dropAmount) + .build() + ).build() + ); + break; case "org.bukkit.event.player.PlayerInteractEvent": var interactEvent = (org.bukkit.event.player.PlayerInteractEvent) event; var clicked = interactEvent.getClickedBlock(); diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index 341f7d9..ef203ed 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -43,6 +43,7 @@ message Event { PlayerRegisterChannelEvent player_register_channel = 28; PlayerUnregisterChannelEvent player_unregister_channel = 29; PlayerCommandSendEvent player_command_send = 30; + PlayerDropItemEvent player_drop_item = 31; } } diff --git a/proto/patchbukkit/events/player_events.proto b/proto/patchbukkit/events/player_events.proto index f416de0..ae8ebde 100644 --- a/proto/patchbukkit/events/player_events.proto +++ b/proto/patchbukkit/events/player_events.proto @@ -65,6 +65,13 @@ message PlayerCommandSendEvent { repeated string commands = 2; } +message PlayerDropItemEvent { + patchbukkit.common.UUID player_uuid = 1; + patchbukkit.common.UUID item_uuid = 2; + string item_key = 3; + int32 item_amount = 4; +} + message AsyncPlayerPreLoginEvent { string name = 1; patchbukkit.common.UUID player_uuid = 2; diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index 540cc0e..d3ea438 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -7,9 +7,11 @@ use pumpkin::plugin::{BoxFuture, Cancellable, EventHandler, Payload}; use pumpkin::server::Server; use pumpkin_api_macros::with_runtime; use pumpkin_data::{Block, BlockDirection}; +use pumpkin_data::item::Item; use pumpkin_util::Hand; use pumpkin_util::math::vector3::Vector3; use pumpkin_util::text::TextComponent; +use pumpkin_world::item::ItemStack; use tokio::sync::{mpsc, oneshot}; use crate::java::jvm::commands::JvmCommand; @@ -25,7 +27,7 @@ use crate::proto::patchbukkit::events::{ PlayerBedEnterEvent, PlayerBedLeaveEvent, PlayerBucketEmptyEvent, PlayerBucketFillEvent, PlayerBucketEntityEvent, PlayerChangedMainHandEvent, - PlayerRegisterChannelEvent, PlayerUnregisterChannelEvent, + PlayerRegisterChannelEvent, PlayerUnregisterChannelEvent, PlayerDropItemEvent, }; pub struct EventContext { @@ -875,6 +877,60 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_command_send::PlayerCo } } +impl PatchBukkitEvent for pumpkin::plugin::player::player_drop_item::PlayerDropItemEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerDropItem(PlayerDropItemEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + item_uuid: Some(Uuid { + value: self.item_uuid.to_string(), + }), + item_key: item_to_key(self.item_stack.item), + item_amount: i32::from(self.item_stack.item_count), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerDropItem(event) => { + if let Some(uuid) = event.item_uuid { + if let Ok(item_uuid) = uuid::Uuid::from_str(&uuid.value) { + self.item_uuid = item_uuid; + } + } + let mut key = if event.item_key.is_empty() { + None + } else { + Some(event.item_key) + }; + let mut amount = if event.item_amount > 0 { + Some(event.item_amount as u8) + } else { + None + }; + + if key.is_some() || amount.is_some() { + let fallback_key = item_to_key(self.item_stack.item); + let key = key.take().unwrap_or(fallback_key); + let count = amount.take().unwrap_or(self.item_stack.item_count); + self.item_stack = item_stack_from_key(&key, count); + } + } + _ => {} + } + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::player::player_interact_event::PlayerInteractEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { let world_uuid = self.player.world().uuid; @@ -1167,6 +1223,16 @@ fn block_to_key(block: &Block) -> String { format!("minecraft:{}", block.name) } +fn item_to_key(item: &Item) -> String { + format!("minecraft:{}", item.registry_key) +} + +fn item_stack_from_key(key: &str, amount: u8) -> ItemStack { + let trimmed = key.strip_prefix("minecraft:").unwrap_or(key); + let item = Item::from_registry_key(trimmed).unwrap_or(&Item::AIR); + ItemStack::new(amount, item) +} + fn interact_action_to_bukkit(action: &pumpkin::plugin::player::player_interact_event::InteractAction) -> String { match action { pumpkin::plugin::player::player_interact_event::InteractAction::LeftClickBlock => { diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index 2142eb9..2889823 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -6,6 +6,7 @@ use pumpkin::plugin::block::block_place::BlockPlaceEvent; use pumpkin::plugin::player::player_chat::PlayerChatEvent; use pumpkin::plugin::player::player_command_preprocess::PlayerCommandPreprocessEvent; use pumpkin::plugin::player::player_command_send::PlayerCommandSendEvent; +use pumpkin::plugin::player::player_drop_item::PlayerDropItemEvent; use pumpkin::plugin::player::player_interact_event::{InteractAction, PlayerInteractEvent}; use pumpkin::plugin::player::player_join::PlayerJoinEvent; use pumpkin::plugin::player::player_login::PlayerLoginEvent; @@ -428,6 +429,23 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.player.PlayerDropItemEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_drop_item::PlayerDropItemEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_drop_item::PlayerDropItemEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.player.PlayerInteractEvent" => { context .register_event::< @@ -913,6 +931,21 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let uuid = + uuid::Uuid::parse_str(&player_drop_item_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let item_uuid = + uuid::Uuid::parse_str(&player_drop_item_event_data.item_uuid?.value).ok()?; + let item_stack = item_stack_from_key( + &player_drop_item_event_data.item_key, + player_drop_item_event_data.item_amount, + ); + let pumpkin_event = + PlayerDropItemEvent::new(player, item_uuid, item_stack); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } Data::PlayerInteract(player_interact_event_data) => { let uuid = uuid::Uuid::parse_str(&player_interact_event_data.player_uuid?.value).ok()?; @@ -1072,6 +1105,13 @@ fn item_from_key(key: &str) -> ItemStack { ItemStack::new(1, item) } +fn item_stack_from_key(key: &str, amount: i32) -> ItemStack { + let trimmed = key.strip_prefix("minecraft:").unwrap_or(key); + let item = Item::from_registry_key(trimmed).unwrap_or(&Item::AIR); + let count = amount.clamp(0, u8::MAX as i32) as u8; + ItemStack::new(count, item) +} + fn bukkit_block_face_to_direction(face: &str) -> Option { match face { "UP" => Some(BlockDirection::Up), From 1801529affa02b8b5e79b5c38b142265935684af Mon Sep 17 00:00:00 2001 From: yunuservices Date: Wed, 4 Feb 2026 23:08:59 +0300 Subject: [PATCH 16/56] Add PlayerEditBookEvent --- .../events/PatchBukkitEventFactory.java | 39 ++++++++++++++++++ .../events/PatchBukkitEventManager.java | 19 +++++++++ proto/patchbukkit/events/event.proto | 1 + proto/patchbukkit/events/player_events.proto | 8 ++++ rust/src/events/handler.rs | 40 +++++++++++++++++++ rust/src/java/native_callbacks/events.rs | 37 +++++++++++++++++ 6 files changed, 144 insertions(+) diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index 45d8ce4..c5551d3 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -31,6 +31,7 @@ import org.bukkit.event.player.PlayerRegisterChannelEvent; import org.bukkit.event.player.PlayerUnregisterChannelEvent; import org.bukkit.event.player.PlayerDropItemEvent; +import org.bukkit.event.player.PlayerEditBookEvent; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.server.BroadcastMessageEvent; @@ -53,6 +54,7 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.MainHand; +import org.bukkit.inventory.meta.BookMeta; import org.bukkit.block.Block; import org.bukkit.Material; import org.bukkit.GameMode; @@ -434,6 +436,22 @@ public static org.bukkit.event.Event createEvent(@NotNull Event event) { PatchBukkitItem item = new PatchBukkitItem(itemUuid, stack); yield new PlayerDropItemEvent(player, item); } + case PLAYER_EDIT_BOOK -> { + patchbukkit.events.PlayerEditBookEvent editEvent = event.getPlayerEditBook(); + Player player = getPlayer(editEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + boolean isSigning = editEvent.getIsSigning(); + ItemStack item = new ItemStack(isSigning ? Material.WRITTEN_BOOK : Material.WRITABLE_BOOK); + BookMeta previousMeta = (BookMeta) item.getItemMeta(); + BookMeta newMeta = (BookMeta) item.getItemMeta(); + if (newMeta != null) { + newMeta.setPages(editEvent.getPagesList()); + if (!editEvent.getTitle().isEmpty()) { + newMeta.setTitle(editEvent.getTitle()); + } + } + yield new PlayerEditBookEvent(player, editEvent.getSlot(), previousMeta, newMeta, isSigning); + } case PLAYER_INTERACT -> { patchbukkit.events.PlayerInteractEvent interactEvent = event.getPlayerInteract(); Player player = getPlayer(interactEvent.getPlayerUuid().getValue()); @@ -886,6 +904,27 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .setItemAmount(itemAmount) .build() ); + } else if (event instanceof PlayerEditBookEvent editEvent) { + BookMeta newMeta = editEvent.getNewBookMeta(); + String title = ""; + java.util.List pages = java.util.Collections.emptyList(); + if (newMeta != null) { + pages = newMeta.getPages(); + if (newMeta.hasTitle()) { + title = newMeta.getTitle(); + } + } + eventBuilder.setPlayerEditBook( + patchbukkit.events.PlayerEditBookEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(editEvent.getPlayer().getUniqueId().toString()) + .build()) + .setSlot(editEvent.getSlot()) + .addAllPages(pages) + .setTitle(title) + .setIsSigning(editEvent.isSigning()) + .build() + ); } else if (event instanceof PlayerInteractEvent interactEvent) { var block = interactEvent.getClickedBlock(); var location = block != null ? block.getLocation() : null; 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 7ef644d..2d7e9b1 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -408,6 +408,25 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.player.PlayerEditBookEvent": + var editEvent = (org.bukkit.event.player.PlayerEditBookEvent) event; + var editBuilder = patchbukkit.events.PlayerEditBookEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(editEvent.getPlayer().getUniqueId())) + .setSlot(editEvent.getSlot()) + .setIsSigning(editEvent.isSigning()); + var newMeta = editEvent.getNewBookMeta(); + if (newMeta != null) { + editBuilder.addAllPages(newMeta.getPages()); + if (newMeta.hasTitle()) { + editBuilder.setTitle(newMeta.getTitle()); + } + } + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerEditBook( + editBuilder.build() + ).build() + ); + break; case "org.bukkit.event.player.PlayerInteractEvent": var interactEvent = (org.bukkit.event.player.PlayerInteractEvent) event; var clicked = interactEvent.getClickedBlock(); diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index ef203ed..8dc9013 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -44,6 +44,7 @@ message Event { PlayerUnregisterChannelEvent player_unregister_channel = 29; PlayerCommandSendEvent player_command_send = 30; PlayerDropItemEvent player_drop_item = 31; + PlayerEditBookEvent player_edit_book = 32; } } diff --git a/proto/patchbukkit/events/player_events.proto b/proto/patchbukkit/events/player_events.proto index ae8ebde..d9a88d7 100644 --- a/proto/patchbukkit/events/player_events.proto +++ b/proto/patchbukkit/events/player_events.proto @@ -72,6 +72,14 @@ message PlayerDropItemEvent { int32 item_amount = 4; } +message PlayerEditBookEvent { + patchbukkit.common.UUID player_uuid = 1; + int32 slot = 2; + repeated string pages = 3; + string title = 4; + bool is_signing = 5; +} + message AsyncPlayerPreLoginEvent { string name = 1; patchbukkit.common.UUID player_uuid = 2; diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index d3ea438..6d3b38c 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -28,6 +28,7 @@ use crate::proto::patchbukkit::events::{ PlayerBucketEmptyEvent, PlayerBucketFillEvent, PlayerBucketEntityEvent, PlayerChangedMainHandEvent, PlayerRegisterChannelEvent, PlayerUnregisterChannelEvent, PlayerDropItemEvent, + PlayerEditBookEvent, }; pub struct EventContext { @@ -931,6 +932,45 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_drop_item::PlayerDropI } } +impl PatchBukkitEvent for pumpkin::plugin::player::player_edit_book::PlayerEditBookEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerEditBook(PlayerEditBookEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + slot: self.slot, + pages: self.pages.clone(), + title: self.title.clone().unwrap_or_default(), + is_signing: self.is_signing, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerEditBook(event) => { + self.slot = event.slot; + self.pages = event.pages; + self.is_signing = event.is_signing; + self.title = if event.title.is_empty() { + None + } else { + Some(event.title) + }; + } + _ => {} + } + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::player::player_interact_event::PlayerInteractEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { let world_uuid = self.player.world().uuid; diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index 2889823..25ee029 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -7,6 +7,7 @@ use pumpkin::plugin::player::player_chat::PlayerChatEvent; use pumpkin::plugin::player::player_command_preprocess::PlayerCommandPreprocessEvent; use pumpkin::plugin::player::player_command_send::PlayerCommandSendEvent; use pumpkin::plugin::player::player_drop_item::PlayerDropItemEvent; +use pumpkin::plugin::player::player_edit_book::PlayerEditBookEvent; use pumpkin::plugin::player::player_interact_event::{InteractAction, PlayerInteractEvent}; use pumpkin::plugin::player::player_join::PlayerJoinEvent; use pumpkin::plugin::player::player_login::PlayerLoginEvent; @@ -446,6 +447,23 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.player.PlayerEditBookEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_edit_book::PlayerEditBookEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_edit_book::PlayerEditBookEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.player.PlayerInteractEvent" => { context .register_event::< @@ -946,6 +964,25 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let uuid = + uuid::Uuid::parse_str(&player_edit_book_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let title = if player_edit_book_event_data.title.is_empty() { + None + } else { + Some(player_edit_book_event_data.title) + }; + let pumpkin_event = PlayerEditBookEvent::new( + player, + player_edit_book_event_data.slot, + player_edit_book_event_data.pages, + title, + player_edit_book_event_data.is_signing, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } Data::PlayerInteract(player_interact_event_data) => { let uuid = uuid::Uuid::parse_str(&player_interact_event_data.player_uuid?.value).ok()?; From 7507781230c84fa44f7af83b8cf994df4a706211 Mon Sep 17 00:00:00 2001 From: yunuservices Date: Wed, 4 Feb 2026 23:19:45 +0300 Subject: [PATCH 17/56] Add PlayerEggThrowEvent --- .../patchbukkit/entity/PatchBukkitEgg.java | 31 +++++++ .../entity/PatchBukkitProjectile.java | 84 +++++++++++++++++++ .../events/PatchBukkitEventFactory.java | 48 +++++++++++ .../events/PatchBukkitEventManager.java | 19 +++++ proto/patchbukkit/events/event.proto | 1 + proto/patchbukkit/events/player_events.proto | 8 ++ rust/src/events/handler.rs | 47 ++++++++++- rust/src/java/native_callbacks/events.rs | 34 ++++++++ 8 files changed, 271 insertions(+), 1 deletion(-) create mode 100644 java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitEgg.java create mode 100644 java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitProjectile.java diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitEgg.java b/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitEgg.java new file mode 100644 index 0000000..d108c28 --- /dev/null +++ b/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitEgg.java @@ -0,0 +1,31 @@ +package org.patchbukkit.entity; + +import java.util.UUID; + +import org.bukkit.Material; +import org.bukkit.entity.Egg; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +public class PatchBukkitEgg extends PatchBukkitProjectile implements Egg { + private ItemStack itemStack; + + public PatchBukkitEgg(@NotNull UUID uuid) { + this(uuid, new ItemStack(Material.EGG)); + } + + public PatchBukkitEgg(@NotNull UUID uuid, @NotNull ItemStack itemStack) { + super(uuid, "EGG"); + this.itemStack = itemStack; + } + + @Override + public @NotNull ItemStack getItem() { + return itemStack; + } + + @Override + public void setItem(@NotNull ItemStack itemStack) { + this.itemStack = itemStack; + } +} diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitProjectile.java b/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitProjectile.java new file mode 100644 index 0000000..28b083b --- /dev/null +++ b/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitProjectile.java @@ -0,0 +1,84 @@ +package org.patchbukkit.entity; + +import java.util.UUID; + +import org.bukkit.entity.Entity; +import org.bukkit.entity.Projectile; +import org.bukkit.projectiles.ProjectileSource; +import org.bukkit.util.Vector; +import org.jetbrains.annotations.Nullable; + +public class PatchBukkitProjectile extends PatchBukkitEntity implements Projectile { + private ProjectileSource shooter; + private boolean bounce; + private boolean hasLeftShooter; + private boolean hasBeenShot; + private UUID ownerUuid; + + public PatchBukkitProjectile(UUID uuid, String name) { + super(uuid, name); + } + + @Override + public @Nullable ProjectileSource getShooter() { + return shooter; + } + + @Override + public void setShooter(@Nullable ProjectileSource shooter) { + this.shooter = shooter; + if (shooter instanceof Entity entity) { + this.ownerUuid = entity.getUniqueId(); + } + } + + @Override + public boolean doesBounce() { + return bounce; + } + + @Override + public void setBounce(boolean bounce) { + this.bounce = bounce; + } + + @Override + public boolean hasLeftShooter() { + return hasLeftShooter; + } + + @Override + public void setHasLeftShooter(boolean hasLeftShooter) { + this.hasLeftShooter = hasLeftShooter; + } + + @Override + public boolean hasBeenShot() { + return hasBeenShot; + } + + @Override + public void setHasBeenShot(boolean hasBeenShot) { + this.hasBeenShot = hasBeenShot; + } + + @Override + public boolean canHitEntity(Entity entity) { + return true; + } + + @Override + public void hitEntity(Entity entity) { + // No-op + } + + @Override + public void hitEntity(Entity entity, Vector vector) { + // No-op + } + + @Override + public UUID getOwnerUniqueId() { + return ownerUuid; + } +} diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index c5551d3..299af66 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -32,6 +32,7 @@ import org.bukkit.event.player.PlayerUnregisterChannelEvent; import org.bukkit.event.player.PlayerDropItemEvent; import org.bukkit.event.player.PlayerEditBookEvent; +import org.bukkit.event.player.PlayerEggThrowEvent; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.server.BroadcastMessageEvent; @@ -50,6 +51,7 @@ import org.patchbukkit.entity.PatchBukkitLivingEntity; import org.patchbukkit.entity.PatchBukkitArmorStand; import org.patchbukkit.entity.PatchBukkitItem; +import org.patchbukkit.entity.PatchBukkitEgg; import org.bukkit.block.BlockFace; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.EquipmentSlot; @@ -452,6 +454,33 @@ public static org.bukkit.event.Event createEvent(@NotNull Event event) { } yield new PlayerEditBookEvent(player, editEvent.getSlot(), previousMeta, newMeta, isSigning); } + case PLAYER_EGG_THROW -> { + patchbukkit.events.PlayerEggThrowEvent eggEvent = event.getPlayerEggThrow(); + Player player = getPlayer(eggEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + java.util.UUID eggUuid; + try { + eggUuid = java.util.UUID.fromString(eggEvent.getEggUuid().getValue()); + } catch (IllegalArgumentException e) { + yield null; + } + PatchBukkitEgg egg = new PatchBukkitEgg(eggUuid, new ItemStack(Material.EGG)); + org.bukkit.entity.EntityType hatchingType = org.bukkit.entity.EntityType.CHICKEN; + if (!eggEvent.getHatchingType().isEmpty()) { + try { + hatchingType = org.bukkit.entity.EntityType.valueOf(eggEvent.getHatchingType()); + } catch (IllegalArgumentException ignored) { + hatchingType = org.bukkit.entity.EntityType.CHICKEN; + } + } + yield new PlayerEggThrowEvent( + player, + egg, + eggEvent.getHatching(), + (byte) Math.max(0, Math.min(eggEvent.getNumHatches(), 127)), + hatchingType + ); + } case PLAYER_INTERACT -> { patchbukkit.events.PlayerInteractEvent interactEvent = event.getPlayerInteract(); Player player = getPlayer(interactEvent.getPlayerUuid().getValue()); @@ -925,6 +954,25 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .setIsSigning(editEvent.isSigning()) .build() ); + } else if (event instanceof PlayerEggThrowEvent eggEvent) { + var hatchingType = eggEvent.getHatchingType() != null + ? eggEvent.getHatchingType().name() + : "CHICKEN"; + var egg = eggEvent.getEgg(); + var eggUuid = egg != null ? egg.getUniqueId().toString() : java.util.UUID.randomUUID().toString(); + eventBuilder.setPlayerEggThrow( + patchbukkit.events.PlayerEggThrowEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(eggEvent.getPlayer().getUniqueId().toString()) + .build()) + .setEggUuid(UUID.newBuilder() + .setValue(eggUuid) + .build()) + .setHatching(eggEvent.isHatching()) + .setNumHatches(eggEvent.getNumHatches()) + .setHatchingType(hatchingType) + .build() + ); } else if (event instanceof PlayerInteractEvent interactEvent) { var block = interactEvent.getClickedBlock(); var location = block != null ? block.getLocation() : null; 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 2d7e9b1..0330b60 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -427,6 +427,25 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.player.PlayerEggThrowEvent": + var eggEvent = (org.bukkit.event.player.PlayerEggThrowEvent) event; + var egg = eggEvent.getEgg(); + var eggUuid = egg != null ? egg.getUniqueId() : java.util.UUID.randomUUID(); + var hatchingType = eggEvent.getHatchingType() != null + ? eggEvent.getHatchingType().name() + : "CHICKEN"; + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerEggThrow( + patchbukkit.events.PlayerEggThrowEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(eggEvent.getPlayer().getUniqueId())) + .setEggUuid(BridgeUtils.convertUuid(eggUuid)) + .setHatching(eggEvent.isHatching()) + .setNumHatches(eggEvent.getNumHatches()) + .setHatchingType(hatchingType) + .build() + ).build() + ); + break; case "org.bukkit.event.player.PlayerInteractEvent": var interactEvent = (org.bukkit.event.player.PlayerInteractEvent) event; var clicked = interactEvent.getClickedBlock(); diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index 8dc9013..f63a259 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -45,6 +45,7 @@ message Event { PlayerCommandSendEvent player_command_send = 30; PlayerDropItemEvent player_drop_item = 31; PlayerEditBookEvent player_edit_book = 32; + PlayerEggThrowEvent player_egg_throw = 33; } } diff --git a/proto/patchbukkit/events/player_events.proto b/proto/patchbukkit/events/player_events.proto index d9a88d7..3293573 100644 --- a/proto/patchbukkit/events/player_events.proto +++ b/proto/patchbukkit/events/player_events.proto @@ -80,6 +80,14 @@ message PlayerEditBookEvent { bool is_signing = 5; } +message PlayerEggThrowEvent { + patchbukkit.common.UUID player_uuid = 1; + patchbukkit.common.UUID egg_uuid = 2; + bool hatching = 3; + int32 num_hatches = 4; + string hatching_type = 5; +} + message AsyncPlayerPreLoginEvent { string name = 1; patchbukkit.common.UUID player_uuid = 2; diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index 6d3b38c..efa8e67 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -28,7 +28,7 @@ use crate::proto::patchbukkit::events::{ PlayerBucketEmptyEvent, PlayerBucketFillEvent, PlayerBucketEntityEvent, PlayerChangedMainHandEvent, PlayerRegisterChannelEvent, PlayerUnregisterChannelEvent, PlayerDropItemEvent, - PlayerEditBookEvent, + PlayerEditBookEvent, PlayerEggThrowEvent, }; pub struct EventContext { @@ -971,6 +971,51 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_edit_book::PlayerEditB } } +impl PatchBukkitEvent for pumpkin::plugin::player::player_egg_throw::PlayerEggThrowEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerEggThrow(PlayerEggThrowEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + egg_uuid: Some(Uuid { + value: self.egg_uuid.to_string(), + }), + hatching: self.hatching, + num_hatches: i32::from(self.num_hatches), + hatching_type: self.hatching_type.clone(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerEggThrow(event) => { + if let Some(uuid) = event.egg_uuid { + if let Ok(egg_uuid) = uuid::Uuid::from_str(&uuid.value) { + self.egg_uuid = egg_uuid; + } + } + self.hatching = event.hatching; + if event.num_hatches >= 0 { + self.num_hatches = event.num_hatches.min(u8::MAX as i32) as u8; + } + if !event.hatching_type.is_empty() { + self.hatching_type = event.hatching_type; + } + } + _ => {} + } + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::player::player_interact_event::PlayerInteractEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { let world_uuid = self.player.world().uuid; diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index 25ee029..e89a133 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -8,6 +8,7 @@ use pumpkin::plugin::player::player_command_preprocess::PlayerCommandPreprocessE use pumpkin::plugin::player::player_command_send::PlayerCommandSendEvent; use pumpkin::plugin::player::player_drop_item::PlayerDropItemEvent; use pumpkin::plugin::player::player_edit_book::PlayerEditBookEvent; +use pumpkin::plugin::player::player_egg_throw::PlayerEggThrowEvent; use pumpkin::plugin::player::player_interact_event::{InteractAction, PlayerInteractEvent}; use pumpkin::plugin::player::player_join::PlayerJoinEvent; use pumpkin::plugin::player::player_login::PlayerLoginEvent; @@ -464,6 +465,23 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.player.PlayerEggThrowEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_egg_throw::PlayerEggThrowEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_egg_throw::PlayerEggThrowEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.player.PlayerInteractEvent" => { context .register_event::< @@ -983,6 +1001,22 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let uuid = + uuid::Uuid::parse_str(&player_egg_throw_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let egg_uuid = + uuid::Uuid::parse_str(&player_egg_throw_event_data.egg_uuid?.value).ok()?; + let pumpkin_event = PlayerEggThrowEvent::new( + player, + egg_uuid, + player_egg_throw_event_data.hatching, + player_egg_throw_event_data.num_hatches.min(u8::MAX as i32) as u8, + player_egg_throw_event_data.hatching_type, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } Data::PlayerInteract(player_interact_event_data) => { let uuid = uuid::Uuid::parse_str(&player_interact_event_data.player_uuid?.value).ok()?; From 585a412f4559cc1c12f0ac0902e5f4f18768ae7a Mon Sep 17 00:00:00 2001 From: yunuservices Date: Wed, 4 Feb 2026 23:23:56 +0300 Subject: [PATCH 18/56] Add PlayerExpChangeEvent --- .../events/PatchBukkitEventFactory.java | 16 ++++++++++ .../events/PatchBukkitEventManager.java | 11 +++++++ proto/patchbukkit/events/event.proto | 1 + proto/patchbukkit/events/player_events.proto | 5 +++ rust/src/events/handler.rs | 31 ++++++++++++++++++- rust/src/java/native_callbacks/events.rs | 27 ++++++++++++++++ 6 files changed, 90 insertions(+), 1 deletion(-) diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index 299af66..664a26f 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -33,6 +33,7 @@ import org.bukkit.event.player.PlayerDropItemEvent; import org.bukkit.event.player.PlayerEditBookEvent; import org.bukkit.event.player.PlayerEggThrowEvent; +import org.bukkit.event.player.PlayerExpChangeEvent; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.server.BroadcastMessageEvent; @@ -481,6 +482,12 @@ yield new PlayerEggThrowEvent( hatchingType ); } + case PLAYER_EXP_CHANGE -> { + patchbukkit.events.PlayerExpChangeEvent expEvent = event.getPlayerExpChange(); + Player player = getPlayer(expEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + yield new PlayerExpChangeEvent(player, expEvent.getAmount()); + } case PLAYER_INTERACT -> { patchbukkit.events.PlayerInteractEvent interactEvent = event.getPlayerInteract(); Player player = getPlayer(interactEvent.getPlayerUuid().getValue()); @@ -973,6 +980,15 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .setHatchingType(hatchingType) .build() ); + } else if (event instanceof PlayerExpChangeEvent expEvent) { + eventBuilder.setPlayerExpChange( + patchbukkit.events.PlayerExpChangeEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(expEvent.getPlayer().getUniqueId().toString()) + .build()) + .setAmount(expEvent.getAmount()) + .build() + ); } else if (event instanceof PlayerInteractEvent interactEvent) { var block = interactEvent.getClickedBlock(); var location = block != null ? block.getLocation() : null; 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 0330b60..bb04f90 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -446,6 +446,17 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.player.PlayerExpChangeEvent": + var expEvent = (org.bukkit.event.player.PlayerExpChangeEvent) event; + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerExpChange( + patchbukkit.events.PlayerExpChangeEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(expEvent.getPlayer().getUniqueId())) + .setAmount(expEvent.getAmount()) + .build() + ).build() + ); + break; case "org.bukkit.event.player.PlayerInteractEvent": var interactEvent = (org.bukkit.event.player.PlayerInteractEvent) event; var clicked = interactEvent.getClickedBlock(); diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index f63a259..8300f69 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -46,6 +46,7 @@ message Event { PlayerDropItemEvent player_drop_item = 31; PlayerEditBookEvent player_edit_book = 32; PlayerEggThrowEvent player_egg_throw = 33; + PlayerExpChangeEvent player_exp_change = 34; } } diff --git a/proto/patchbukkit/events/player_events.proto b/proto/patchbukkit/events/player_events.proto index 3293573..126c10d 100644 --- a/proto/patchbukkit/events/player_events.proto +++ b/proto/patchbukkit/events/player_events.proto @@ -88,6 +88,11 @@ message PlayerEggThrowEvent { string hatching_type = 5; } +message PlayerExpChangeEvent { + patchbukkit.common.UUID player_uuid = 1; + int32 amount = 2; +} + message AsyncPlayerPreLoginEvent { string name = 1; patchbukkit.common.UUID player_uuid = 2; diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index efa8e67..6bfa8c7 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -28,7 +28,7 @@ use crate::proto::patchbukkit::events::{ PlayerBucketEmptyEvent, PlayerBucketFillEvent, PlayerBucketEntityEvent, PlayerChangedMainHandEvent, PlayerRegisterChannelEvent, PlayerUnregisterChannelEvent, PlayerDropItemEvent, - PlayerEditBookEvent, PlayerEggThrowEvent, + PlayerEditBookEvent, PlayerEggThrowEvent, PlayerExpChangeEvent, }; pub struct EventContext { @@ -1016,6 +1016,35 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_egg_throw::PlayerEggTh } } +impl PatchBukkitEvent for pumpkin::plugin::player::player_exp_change::PlayerExpChangeEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerExpChange(PlayerExpChangeEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + amount: self.amount, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerExpChange(event) => { + self.amount = event.amount; + } + _ => {} + } + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::player::player_interact_event::PlayerInteractEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { let world_uuid = self.player.world().uuid; diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index e89a133..e8fbe81 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -9,6 +9,7 @@ use pumpkin::plugin::player::player_command_send::PlayerCommandSendEvent; use pumpkin::plugin::player::player_drop_item::PlayerDropItemEvent; use pumpkin::plugin::player::player_edit_book::PlayerEditBookEvent; use pumpkin::plugin::player::player_egg_throw::PlayerEggThrowEvent; +use pumpkin::plugin::player::player_exp_change::PlayerExpChangeEvent; use pumpkin::plugin::player::player_interact_event::{InteractAction, PlayerInteractEvent}; use pumpkin::plugin::player::player_join::PlayerJoinEvent; use pumpkin::plugin::player::player_login::PlayerLoginEvent; @@ -482,6 +483,23 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.player.PlayerExpChangeEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_exp_change::PlayerExpChangeEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_exp_change::PlayerExpChangeEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.player.PlayerInteractEvent" => { context .register_event::< @@ -1017,6 +1035,15 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let uuid = + uuid::Uuid::parse_str(&player_exp_change_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let pumpkin_event = + PlayerExpChangeEvent::new(player, player_exp_change_event_data.amount); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } Data::PlayerInteract(player_interact_event_data) => { let uuid = uuid::Uuid::parse_str(&player_interact_event_data.player_uuid?.value).ok()?; From 87e6d23a6c38d126f8ca7b458cf55ce7baf39753 Mon Sep 17 00:00:00 2001 From: yunuservices Date: Wed, 4 Feb 2026 23:32:20 +0300 Subject: [PATCH 19/56] Add PlayerFishEvent --- .../entity/PatchBukkitFishHook.java | 210 ++++++++++++++++++ .../events/PatchBukkitEventFactory.java | 65 ++++++ .../events/PatchBukkitEventManager.java | 22 ++ proto/patchbukkit/events/event.proto | 1 + proto/patchbukkit/events/player_events.proto | 10 + rust/src/events/handler.rs | 57 ++++- rust/src/java/native_callbacks/events.rs | 39 ++++ 7 files changed, 403 insertions(+), 1 deletion(-) create mode 100644 java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitFishHook.java diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitFishHook.java b/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitFishHook.java new file mode 100644 index 0000000..d46d0f4 --- /dev/null +++ b/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitFishHook.java @@ -0,0 +1,210 @@ +package org.patchbukkit.entity; + +import java.util.UUID; + +import org.bukkit.entity.Entity; +import org.bukkit.entity.FishHook; +import org.bukkit.inventory.EquipmentSlot; +import org.jetbrains.annotations.Nullable; + +public class PatchBukkitFishHook extends PatchBukkitProjectile implements FishHook { + private int minWaitTime = 100; + private int maxWaitTime = 600; + private int minLureTime = 20; + private int maxLureTime = 80; + private float minLureAngle = 0.0f; + private float maxLureAngle = 360.0f; + private boolean applyLure = true; + private double biteChance = 0.0; + private boolean inOpenWater = false; + private Entity hookedEntity; + private boolean skyInfluenced = true; + private boolean rainInfluenced = true; + private HookState hookState = HookState.UNHOOKED; + private int waitTime = 0; + private int timeUntilBite = 0; + + public PatchBukkitFishHook(UUID uuid) { + super(uuid, "FISHING_BOBBER"); + } + + @Override + public int getMinWaitTime() { + return minWaitTime; + } + + @Override + public void setMinWaitTime(int minWaitTime) { + this.minWaitTime = minWaitTime; + } + + @Override + public int getMaxWaitTime() { + return maxWaitTime; + } + + @Override + public void setMaxWaitTime(int maxWaitTime) { + this.maxWaitTime = maxWaitTime; + } + + @Override + public void setWaitTime(int minWaitTime, int maxWaitTime) { + this.minWaitTime = minWaitTime; + this.maxWaitTime = maxWaitTime; + } + + @Override + public int getMinLureTime() { + return minLureTime; + } + + @Override + public void setMinLureTime(int minLureTime) { + this.minLureTime = minLureTime; + } + + @Override + public int getMaxLureTime() { + return maxLureTime; + } + + @Override + public void setMaxLureTime(int maxLureTime) { + this.maxLureTime = maxLureTime; + } + + @Override + public void setLureTime(int minLureTime, int maxLureTime) { + this.minLureTime = minLureTime; + this.maxLureTime = maxLureTime; + } + + @Override + public float getMinLureAngle() { + return minLureAngle; + } + + @Override + public void setMinLureAngle(float minLureAngle) { + this.minLureAngle = minLureAngle; + } + + @Override + public float getMaxLureAngle() { + return maxLureAngle; + } + + @Override + public void setMaxLureAngle(float maxLureAngle) { + this.maxLureAngle = maxLureAngle; + } + + @Override + public void setLureAngle(float minLureAngle, float maxLureAngle) { + this.minLureAngle = minLureAngle; + this.maxLureAngle = maxLureAngle; + } + + @Override + public boolean getApplyLure() { + return applyLure; + } + + @Override + public void setApplyLure(boolean applyLure) { + this.applyLure = applyLure; + } + + @Override + public double getBiteChance() { + return biteChance; + } + + @Override + public void setBiteChance(double biteChance) throws IllegalArgumentException { + if (biteChance < 0.0 || biteChance > 1.0) { + throw new IllegalArgumentException("Bite chance must be between 0.0 and 1.0"); + } + this.biteChance = biteChance; + } + + @Override + public boolean isInOpenWater() { + return inOpenWater; + } + + @Override + public @Nullable Entity getHookedEntity() { + return hookedEntity; + } + + @Override + public void setHookedEntity(@Nullable Entity entity) { + this.hookedEntity = entity; + } + + @Override + public boolean pullHookedEntity() { + return hookedEntity != null; + } + + @Override + public boolean isSkyInfluenced() { + return skyInfluenced; + } + + @Override + public void setSkyInfluenced(boolean skyInfluenced) { + this.skyInfluenced = skyInfluenced; + } + + @Override + public boolean isRainInfluenced() { + return rainInfluenced; + } + + @Override + public void setRainInfluenced(boolean rainInfluenced) { + this.rainInfluenced = rainInfluenced; + } + + @Override + public HookState getState() { + return hookState; + } + + @Override + public int getWaitTime() { + return waitTime; + } + + @Override + public void setWaitTime(int waitTime) { + this.waitTime = waitTime; + } + + @Override + public int getTimeUntilBite() { + return timeUntilBite; + } + + @Override + public void setTimeUntilBite(int timeUntilBite) throws IllegalArgumentException { + if (timeUntilBite < 0) { + throw new IllegalArgumentException("Time until bite cannot be negative"); + } + this.timeUntilBite = timeUntilBite; + } + + @Override + public void resetFishingState() { + hookState = HookState.UNHOOKED; + timeUntilBite = 0; + } + + @Override + public int retrieve(EquipmentSlot hand) { + return 0; + } +} diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index 664a26f..bbca93d 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -34,6 +34,7 @@ import org.bukkit.event.player.PlayerEditBookEvent; import org.bukkit.event.player.PlayerEggThrowEvent; import org.bukkit.event.player.PlayerExpChangeEvent; +import org.bukkit.event.player.PlayerFishEvent; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.server.BroadcastMessageEvent; @@ -53,6 +54,7 @@ import org.patchbukkit.entity.PatchBukkitArmorStand; import org.patchbukkit.entity.PatchBukkitItem; import org.patchbukkit.entity.PatchBukkitEgg; +import org.patchbukkit.entity.PatchBukkitFishHook; import org.bukkit.block.BlockFace; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.EquipmentSlot; @@ -488,6 +490,46 @@ yield new PlayerEggThrowEvent( if (player == null) yield null; yield new PlayerExpChangeEvent(player, expEvent.getAmount()); } + case PLAYER_FISH -> { + patchbukkit.events.PlayerFishEvent fishEvent = event.getPlayerFish(); + Player player = getPlayer(fishEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + java.util.UUID hookUuid; + try { + hookUuid = java.util.UUID.fromString(fishEvent.getHookUuid().getValue()); + } catch (IllegalArgumentException e) { + yield null; + } + PatchBukkitFishHook hook = new PatchBukkitFishHook(hookUuid); + org.bukkit.entity.Entity caught = null; + if (fishEvent.hasCaughtUuid()) { + try { + java.util.UUID caughtUuid = java.util.UUID.fromString(fishEvent.getCaughtUuid().getValue()); + caught = new PatchBukkitEntity(caughtUuid, fishEvent.getCaughtType()); + } catch (IllegalArgumentException ignored) { + caught = null; + } + } + PlayerFishEvent.State state = PlayerFishEvent.State.FISHING; + if (!fishEvent.getState().isEmpty()) { + try { + state = PlayerFishEvent.State.valueOf(fishEvent.getState()); + } catch (IllegalArgumentException ignored) { + state = PlayerFishEvent.State.FISHING; + } + } + EquipmentSlot hand = EquipmentSlot.HAND; + if (!fishEvent.getHand().isEmpty()) { + try { + hand = EquipmentSlot.valueOf(fishEvent.getHand()); + } catch (IllegalArgumentException ignored) { + hand = EquipmentSlot.HAND; + } + } + PlayerFishEvent playerFishEvent = new PlayerFishEvent(player, caught, hook, hand, state); + playerFishEvent.setExpToDrop(fishEvent.getExpToDrop()); + yield playerFishEvent; + } case PLAYER_INTERACT -> { patchbukkit.events.PlayerInteractEvent interactEvent = event.getPlayerInteract(); Player player = getPlayer(interactEvent.getPlayerUuid().getValue()); @@ -989,6 +1031,29 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .setAmount(expEvent.getAmount()) .build() ); + } else if (event instanceof PlayerFishEvent fishEvent) { + var hook = fishEvent.getHook(); + var hookUuid = hook != null ? hook.getUniqueId().toString() : java.util.UUID.randomUUID().toString(); + var caught = fishEvent.getCaught(); + var fishBuilder = patchbukkit.events.PlayerFishEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(fishEvent.getPlayer().getUniqueId().toString()) + .build()) + .setHookUuid(UUID.newBuilder() + .setValue(hookUuid) + .build()) + .setState(fishEvent.getState().name()) + .setExpToDrop(fishEvent.getExpToDrop()); + if (fishEvent.getHand() != null) { + fishBuilder.setHand(fishEvent.getHand().name()); + } + if (caught != null) { + fishBuilder.setCaughtUuid(UUID.newBuilder() + .setValue(caught.getUniqueId().toString()) + .build()); + fishBuilder.setCaughtType(caught.getType().name()); + } + eventBuilder.setPlayerFish(fishBuilder.build()); } else if (event instanceof PlayerInteractEvent interactEvent) { var block = interactEvent.getClickedBlock(); var location = block != null ? block.getLocation() : null; 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 bb04f90..a8efeb7 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -457,6 +457,28 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.player.PlayerFishEvent": + var fishEvent = (org.bukkit.event.player.PlayerFishEvent) event; + var fishBuilder = patchbukkit.events.PlayerFishEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(fishEvent.getPlayer().getUniqueId())) + .setState(fishEvent.getState().name()) + .setExpToDrop(fishEvent.getExpToDrop()); + if (fishEvent.getHand() != null) { + fishBuilder.setHand(fishEvent.getHand().name()); + } + if (fishEvent.getHook() != null) { + fishBuilder.setHookUuid(BridgeUtils.convertUuid(fishEvent.getHook().getUniqueId())); + } + if (fishEvent.getCaught() != null) { + fishBuilder.setCaughtUuid(BridgeUtils.convertUuid(fishEvent.getCaught().getUniqueId())); + fishBuilder.setCaughtType(fishEvent.getCaught().getType().name()); + } + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerFish( + fishBuilder.build() + ).build() + ); + break; case "org.bukkit.event.player.PlayerInteractEvent": var interactEvent = (org.bukkit.event.player.PlayerInteractEvent) event; var clicked = interactEvent.getClickedBlock(); diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index 8300f69..deb666d 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -47,6 +47,7 @@ message Event { PlayerEditBookEvent player_edit_book = 32; PlayerEggThrowEvent player_egg_throw = 33; PlayerExpChangeEvent player_exp_change = 34; + PlayerFishEvent player_fish = 35; } } diff --git a/proto/patchbukkit/events/player_events.proto b/proto/patchbukkit/events/player_events.proto index 126c10d..69405d9 100644 --- a/proto/patchbukkit/events/player_events.proto +++ b/proto/patchbukkit/events/player_events.proto @@ -93,6 +93,16 @@ message PlayerExpChangeEvent { int32 amount = 2; } +message PlayerFishEvent { + patchbukkit.common.UUID player_uuid = 1; + patchbukkit.common.UUID caught_uuid = 2; + string caught_type = 3; + patchbukkit.common.UUID hook_uuid = 4; + string state = 5; + string hand = 6; + int32 exp_to_drop = 7; +} + message AsyncPlayerPreLoginEvent { string name = 1; patchbukkit.common.UUID player_uuid = 2; diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index 6bfa8c7..71bfb4c 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -28,7 +28,7 @@ use crate::proto::patchbukkit::events::{ PlayerBucketEmptyEvent, PlayerBucketFillEvent, PlayerBucketEntityEvent, PlayerChangedMainHandEvent, PlayerRegisterChannelEvent, PlayerUnregisterChannelEvent, PlayerDropItemEvent, - PlayerEditBookEvent, PlayerEggThrowEvent, PlayerExpChangeEvent, + PlayerEditBookEvent, PlayerEggThrowEvent, PlayerExpChangeEvent, PlayerFishEvent, }; pub struct EventContext { @@ -1045,6 +1045,61 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_exp_change::PlayerExpC } } +impl PatchBukkitEvent for pumpkin::plugin::player::player_fish::PlayerFishEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerFish(PlayerFishEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + caught_uuid: self.caught_uuid.map(|uuid| Uuid { + value: uuid.to_string(), + }), + caught_type: self.caught_type.clone(), + hook_uuid: Some(Uuid { + value: self.hook_uuid.to_string(), + }), + state: self.state.clone(), + hand: self.hand.clone(), + exp_to_drop: self.exp_to_drop, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerFish(event) => { + self.caught_uuid = event + .caught_uuid + .and_then(|uuid| uuid::Uuid::from_str(&uuid.value).ok()); + if !event.caught_type.is_empty() { + self.caught_type = event.caught_type; + } + if let Some(uuid) = event.hook_uuid { + if let Ok(hook_uuid) = uuid::Uuid::from_str(&uuid.value) { + self.hook_uuid = hook_uuid; + } + } + if !event.state.is_empty() { + self.state = event.state; + } + if !event.hand.is_empty() { + self.hand = event.hand; + } + self.exp_to_drop = event.exp_to_drop; + } + _ => {} + } + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::player::player_interact_event::PlayerInteractEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { let world_uuid = self.player.world().uuid; diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index e8fbe81..5acf859 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -10,6 +10,7 @@ use pumpkin::plugin::player::player_drop_item::PlayerDropItemEvent; use pumpkin::plugin::player::player_edit_book::PlayerEditBookEvent; use pumpkin::plugin::player::player_egg_throw::PlayerEggThrowEvent; use pumpkin::plugin::player::player_exp_change::PlayerExpChangeEvent; +use pumpkin::plugin::player::player_fish::PlayerFishEvent; use pumpkin::plugin::player::player_interact_event::{InteractAction, PlayerInteractEvent}; use pumpkin::plugin::player::player_join::PlayerJoinEvent; use pumpkin::plugin::player::player_login::PlayerLoginEvent; @@ -500,6 +501,23 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.player.PlayerFishEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_fish::PlayerFishEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_fish::PlayerFishEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.player.PlayerInteractEvent" => { context .register_event::< @@ -1044,6 +1062,27 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let uuid = + uuid::Uuid::parse_str(&player_fish_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let caught_uuid = player_fish_event_data + .caught_uuid + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()); + let hook_uuid = + uuid::Uuid::parse_str(&player_fish_event_data.hook_uuid?.value).ok()?; + let pumpkin_event = PlayerFishEvent::new( + player, + caught_uuid, + hook_uuid, + player_fish_event_data.caught_type, + player_fish_event_data.state, + player_fish_event_data.hand, + player_fish_event_data.exp_to_drop, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } Data::PlayerInteract(player_interact_event_data) => { let uuid = uuid::Uuid::parse_str(&player_interact_event_data.player_uuid?.value).ok()?; From b2dbd984db67af9620ac9fbad78e009f41729c6f Mon Sep 17 00:00:00 2001 From: yunuservices Date: Wed, 4 Feb 2026 23:39:36 +0300 Subject: [PATCH 20/56] Add player entity interaction events --- .../events/PatchBukkitEventFactory.java | 85 +++++++++++++++++ .../events/PatchBukkitEventManager.java | 40 ++++++++ proto/patchbukkit/events/event.proto | 2 + proto/patchbukkit/events/player_events.proto | 15 +++ rust/src/events/handler.rs | 95 +++++++++++++++++++ rust/src/java/native_callbacks/events.rs | 71 ++++++++++++++ 6 files changed, 308 insertions(+) diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index bbca93d..2e967e5 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -35,6 +35,8 @@ import org.bukkit.event.player.PlayerEggThrowEvent; import org.bukkit.event.player.PlayerExpChangeEvent; import org.bukkit.event.player.PlayerFishEvent; +import org.bukkit.event.player.PlayerInteractEntityEvent; +import org.bukkit.event.player.PlayerInteractAtEntityEvent; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.server.BroadcastMessageEvent; @@ -60,6 +62,7 @@ import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.MainHand; import org.bukkit.inventory.meta.BookMeta; +import org.bukkit.util.Vector; import org.bukkit.block.Block; import org.bukkit.Material; import org.bukkit.GameMode; @@ -530,6 +533,52 @@ yield new PlayerEggThrowEvent( playerFishEvent.setExpToDrop(fishEvent.getExpToDrop()); yield playerFishEvent; } + case PLAYER_INTERACT_ENTITY -> { + patchbukkit.events.PlayerInteractEntityEvent interactEvent = event.getPlayerInteractEntity(); + Player player = getPlayer(interactEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + java.util.UUID entityUuid; + try { + entityUuid = java.util.UUID.fromString(interactEvent.getEntityUuid().getValue()); + } catch (IllegalArgumentException e) { + yield null; + } + PatchBukkitEntity entity = new PatchBukkitEntity(entityUuid, interactEvent.getEntityType()); + EquipmentSlot slot = EquipmentSlot.HAND; + if (!interactEvent.getHand().isEmpty()) { + try { + slot = EquipmentSlot.valueOf(interactEvent.getHand()); + } catch (IllegalArgumentException ignored) { + slot = EquipmentSlot.HAND; + } + } + yield new PlayerInteractEntityEvent(player, entity, slot); + } + case PLAYER_INTERACT_AT_ENTITY -> { + patchbukkit.events.PlayerInteractAtEntityEvent interactEvent = event.getPlayerInteractAtEntity(); + Player player = getPlayer(interactEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + java.util.UUID entityUuid; + try { + entityUuid = java.util.UUID.fromString(interactEvent.getEntityUuid().getValue()); + } catch (IllegalArgumentException e) { + yield null; + } + PatchBukkitEntity entity = new PatchBukkitEntity(entityUuid, interactEvent.getEntityType()); + EquipmentSlot slot = EquipmentSlot.HAND; + if (!interactEvent.getHand().isEmpty()) { + try { + slot = EquipmentSlot.valueOf(interactEvent.getHand()); + } catch (IllegalArgumentException ignored) { + slot = EquipmentSlot.HAND; + } + } + var pos = interactEvent.getClickedPosition(); + Vector clickedPos = pos != null + ? new Vector(pos.getX(), pos.getY(), pos.getZ()) + : new Vector(); + yield new PlayerInteractAtEntityEvent(player, entity, clickedPos, slot); + } case PLAYER_INTERACT -> { patchbukkit.events.PlayerInteractEvent interactEvent = event.getPlayerInteract(); Player player = getPlayer(interactEvent.getPlayerUuid().getValue()); @@ -1054,6 +1103,42 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) fishBuilder.setCaughtType(caught.getType().name()); } eventBuilder.setPlayerFish(fishBuilder.build()); + } else if (event instanceof PlayerInteractAtEntityEvent interactEvent) { + var entity = interactEvent.getRightClicked(); + var pos = interactEvent.getClickedPosition(); + var builder = patchbukkit.events.PlayerInteractAtEntityEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(interactEvent.getPlayer().getUniqueId().toString()) + .build()) + .setEntityUuid(UUID.newBuilder() + .setValue(entity.getUniqueId().toString()) + .build()) + .setEntityType(entity.getType().name()); + if (interactEvent.getHand() != null) { + builder.setHand(interactEvent.getHand().name()); + } + if (pos != null) { + builder.setClickedPosition(patchbukkit.common.Vec3.newBuilder() + .setX(pos.getX()) + .setY(pos.getY()) + .setZ(pos.getZ()) + .build()); + } + eventBuilder.setPlayerInteractAtEntity(builder.build()); + } else if (event instanceof PlayerInteractEntityEvent interactEvent) { + var entity = interactEvent.getRightClicked(); + var builder = patchbukkit.events.PlayerInteractEntityEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(interactEvent.getPlayer().getUniqueId().toString()) + .build()) + .setEntityUuid(UUID.newBuilder() + .setValue(entity.getUniqueId().toString()) + .build()) + .setEntityType(entity.getType().name()); + if (interactEvent.getHand() != null) { + builder.setHand(interactEvent.getHand().name()); + } + eventBuilder.setPlayerInteractEntity(builder.build()); } else if (event instanceof PlayerInteractEvent interactEvent) { var block = interactEvent.getClickedBlock(); var location = block != null ? block.getLocation() : null; 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 a8efeb7..d7ccce2 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -479,6 +479,46 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.player.PlayerInteractAtEntityEvent": + var interactAtEvent = (org.bukkit.event.player.PlayerInteractAtEntityEvent) event; + var clickedEntity = interactAtEvent.getRightClicked(); + var pos = interactAtEvent.getClickedPosition(); + var interactAtBuilder = patchbukkit.events.PlayerInteractAtEntityEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(interactAtEvent.getPlayer().getUniqueId())) + .setEntityUuid(BridgeUtils.convertUuid(clickedEntity.getUniqueId())) + .setEntityType(clickedEntity.getType().name()); + if (interactAtEvent.getHand() != null) { + interactAtBuilder.setHand(interactAtEvent.getHand().name()); + } + if (pos != null) { + interactAtBuilder.setClickedPosition(patchbukkit.common.Vec3.newBuilder() + .setX(pos.getX()) + .setY(pos.getY()) + .setZ(pos.getZ()) + .build()); + } + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerInteractAtEntity( + interactAtBuilder.build() + ).build() + ); + break; + case "org.bukkit.event.player.PlayerInteractEntityEvent": + var interactEntityEvent = (org.bukkit.event.player.PlayerInteractEntityEvent) event; + var rightClicked = interactEntityEvent.getRightClicked(); + var interactEntityBuilder = patchbukkit.events.PlayerInteractEntityEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(interactEntityEvent.getPlayer().getUniqueId())) + .setEntityUuid(BridgeUtils.convertUuid(rightClicked.getUniqueId())) + .setEntityType(rightClicked.getType().name()); + if (interactEntityEvent.getHand() != null) { + interactEntityBuilder.setHand(interactEntityEvent.getHand().name()); + } + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerInteractEntity( + interactEntityBuilder.build() + ).build() + ); + break; case "org.bukkit.event.player.PlayerInteractEvent": var interactEvent = (org.bukkit.event.player.PlayerInteractEvent) event; var clicked = interactEvent.getClickedBlock(); diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index deb666d..7c1deeb 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -48,6 +48,8 @@ message Event { PlayerEggThrowEvent player_egg_throw = 33; PlayerExpChangeEvent player_exp_change = 34; PlayerFishEvent player_fish = 35; + PlayerInteractEntityEvent player_interact_entity = 36; + PlayerInteractAtEntityEvent player_interact_at_entity = 37; } } diff --git a/proto/patchbukkit/events/player_events.proto b/proto/patchbukkit/events/player_events.proto index 69405d9..bf12f3f 100644 --- a/proto/patchbukkit/events/player_events.proto +++ b/proto/patchbukkit/events/player_events.proto @@ -103,6 +103,21 @@ message PlayerFishEvent { int32 exp_to_drop = 7; } +message PlayerInteractEntityEvent { + patchbukkit.common.UUID player_uuid = 1; + patchbukkit.common.UUID entity_uuid = 2; + string entity_type = 3; + string hand = 4; +} + +message PlayerInteractAtEntityEvent { + patchbukkit.common.UUID player_uuid = 1; + patchbukkit.common.UUID entity_uuid = 2; + string entity_type = 3; + string hand = 4; + patchbukkit.common.Vec3 clicked_position = 5; +} + message AsyncPlayerPreLoginEvent { string name = 1; patchbukkit.common.UUID player_uuid = 2; diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index 71bfb4c..8119920 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -29,6 +29,7 @@ use crate::proto::patchbukkit::events::{ PlayerChangedMainHandEvent, PlayerRegisterChannelEvent, PlayerUnregisterChannelEvent, PlayerDropItemEvent, PlayerEditBookEvent, PlayerEggThrowEvent, PlayerExpChangeEvent, PlayerFishEvent, + PlayerInteractEntityEvent, PlayerInteractAtEntityEvent, }; pub struct EventContext { @@ -1100,6 +1101,100 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_fish::PlayerFishEvent } } +impl PatchBukkitEvent for pumpkin::plugin::player::player_interact_entity::PlayerInteractEntityEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerInteractEntity(PlayerInteractEntityEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + entity_uuid: Some(Uuid { + value: self.entity_uuid.to_string(), + }), + entity_type: self.entity_type.clone(), + hand: self.hand.clone(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerInteractEntity(event) => { + if let Some(uuid) = event.entity_uuid { + if let Ok(entity_uuid) = uuid::Uuid::from_str(&uuid.value) { + self.entity_uuid = entity_uuid; + } + } + if !event.entity_type.is_empty() { + self.entity_type = event.entity_type; + } + if !event.hand.is_empty() { + self.hand = event.hand; + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_interact_at_entity::PlayerInteractAtEntityEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerInteractAtEntity(PlayerInteractAtEntityEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + entity_uuid: Some(Uuid { + value: self.entity_uuid.to_string(), + }), + entity_type: self.entity_type.clone(), + hand: self.hand.clone(), + clicked_position: Some(Vec3 { + x: f64::from(self.clicked_position.x), + y: f64::from(self.clicked_position.y), + z: f64::from(self.clicked_position.z), + }), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerInteractAtEntity(event) => { + if let Some(uuid) = event.entity_uuid { + if let Ok(entity_uuid) = uuid::Uuid::from_str(&uuid.value) { + self.entity_uuid = entity_uuid; + } + } + if !event.entity_type.is_empty() { + self.entity_type = event.entity_type; + } + if !event.hand.is_empty() { + self.hand = event.hand; + } + if let Some(pos) = event.clicked_position { + self.clicked_position = Vector3::new(pos.x as f32, pos.y as f32, pos.z as f32); + } + } + _ => {} + } + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::player::player_interact_event::PlayerInteractEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { let world_uuid = self.player.world().uuid; diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index 5acf859..265a5fa 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -11,6 +11,8 @@ use pumpkin::plugin::player::player_edit_book::PlayerEditBookEvent; use pumpkin::plugin::player::player_egg_throw::PlayerEggThrowEvent; use pumpkin::plugin::player::player_exp_change::PlayerExpChangeEvent; use pumpkin::plugin::player::player_fish::PlayerFishEvent; +use pumpkin::plugin::player::player_interact_entity::PlayerInteractEntityEvent; +use pumpkin::plugin::player::player_interact_at_entity::PlayerInteractAtEntityEvent; use pumpkin::plugin::player::player_interact_event::{InteractAction, PlayerInteractEvent}; use pumpkin::plugin::player::player_join::PlayerJoinEvent; use pumpkin::plugin::player::player_login::PlayerLoginEvent; @@ -518,6 +520,40 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.player.PlayerInteractEntityEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_interact_entity::PlayerInteractEntityEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_interact_entity::PlayerInteractEntityEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerInteractAtEntityEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_interact_at_entity::PlayerInteractAtEntityEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_interact_at_entity::PlayerInteractAtEntityEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.player.PlayerInteractEvent" => { context .register_event::< @@ -1083,6 +1119,41 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let uuid = + uuid::Uuid::parse_str(&player_interact_entity_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let entity_uuid = + uuid::Uuid::parse_str(&player_interact_entity_event_data.entity_uuid?.value).ok()?; + let pumpkin_event = PlayerInteractEntityEvent::new( + player, + entity_uuid, + player_interact_entity_event_data.entity_type, + player_interact_entity_event_data.hand, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerInteractAtEntity(player_interact_at_entity_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_interact_at_entity_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let entity_uuid = + uuid::Uuid::parse_str(&player_interact_at_entity_event_data.entity_uuid?.value).ok()?; + let position = player_interact_at_entity_event_data + .clicked_position + .map(|pos| Vector3::new(pos.x as f32, pos.y as f32, pos.z as f32)) + .unwrap_or_else(|| Vector3::new(0.0, 0.0, 0.0)); + let pumpkin_event = PlayerInteractAtEntityEvent::new( + player, + entity_uuid, + player_interact_at_entity_event_data.entity_type, + player_interact_at_entity_event_data.hand, + position, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } Data::PlayerInteract(player_interact_event_data) => { let uuid = uuid::Uuid::parse_str(&player_interact_event_data.player_uuid?.value).ok()?; From d485ab7bb7668a3668adb052f70b51b959c7cf89 Mon Sep 17 00:00:00 2001 From: yunuservices Date: Wed, 4 Feb 2026 23:46:06 +0300 Subject: [PATCH 21/56] Add PlayerItemHeldEvent bridge --- .../events/PatchBukkitEventFactory.java | 17 ++++++++++ .../events/PatchBukkitEventManager.java | 12 +++++++ proto/patchbukkit/events/event.proto | 1 + proto/patchbukkit/events/player_events.proto | 6 ++++ rust/src/events/handler.rs | 33 ++++++++++++++++++- rust/src/java/native_callbacks/events.rs | 30 +++++++++++++++++ 6 files changed, 98 insertions(+), 1 deletion(-) diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index 2e967e5..825f134 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -37,6 +37,7 @@ import org.bukkit.event.player.PlayerFishEvent; import org.bukkit.event.player.PlayerInteractEntityEvent; import org.bukkit.event.player.PlayerInteractAtEntityEvent; +import org.bukkit.event.player.PlayerItemHeldEvent; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.server.BroadcastMessageEvent; @@ -579,6 +580,12 @@ yield new PlayerEggThrowEvent( : new Vector(); yield new PlayerInteractAtEntityEvent(player, entity, clickedPos, slot); } + case PLAYER_ITEM_HELD -> { + patchbukkit.events.PlayerItemHeldEvent heldEvent = event.getPlayerItemHeld(); + Player player = getPlayer(heldEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + yield new PlayerItemHeldEvent(player, heldEvent.getPreviousSlot(), heldEvent.getNewSlot()); + } case PLAYER_INTERACT -> { patchbukkit.events.PlayerInteractEvent interactEvent = event.getPlayerInteract(); Player player = getPlayer(interactEvent.getPlayerUuid().getValue()); @@ -979,6 +986,16 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .setChannel(unregisterChannelEvent.getChannel()) .build() ); + } else if (event instanceof PlayerItemHeldEvent heldEvent) { + eventBuilder.setPlayerItemHeld( + patchbukkit.events.PlayerItemHeldEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(heldEvent.getPlayer().getUniqueId().toString()) + .build()) + .setPreviousSlot(heldEvent.getPreviousSlot()) + .setNewSlot(heldEvent.getNewSlot()) + .build() + ); } else if (event instanceof AsyncPlayerChatEvent chatEvent) { var playerEventBuilder = patchbukkit.events.PlayerChatEvent.newBuilder() .setPlayerUuid(UUID.newBuilder() 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 d7ccce2..5d83e53 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -519,6 +519,18 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.player.PlayerItemHeldEvent": + var heldEvent = (org.bukkit.event.player.PlayerItemHeldEvent) event; + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerItemHeld( + patchbukkit.events.PlayerItemHeldEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(heldEvent.getPlayer().getUniqueId())) + .setPreviousSlot(heldEvent.getPreviousSlot()) + .setNewSlot(heldEvent.getNewSlot()) + .build() + ).build() + ); + break; case "org.bukkit.event.player.PlayerInteractEvent": var interactEvent = (org.bukkit.event.player.PlayerInteractEvent) event; var clicked = interactEvent.getClickedBlock(); diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index 7c1deeb..3e3dc0a 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -50,6 +50,7 @@ message Event { PlayerFishEvent player_fish = 35; PlayerInteractEntityEvent player_interact_entity = 36; PlayerInteractAtEntityEvent player_interact_at_entity = 37; + PlayerItemHeldEvent player_item_held = 38; } } diff --git a/proto/patchbukkit/events/player_events.proto b/proto/patchbukkit/events/player_events.proto index bf12f3f..5a55b5c 100644 --- a/proto/patchbukkit/events/player_events.proto +++ b/proto/patchbukkit/events/player_events.proto @@ -118,6 +118,12 @@ message PlayerInteractAtEntityEvent { patchbukkit.common.Vec3 clicked_position = 5; } +message PlayerItemHeldEvent { + patchbukkit.common.UUID player_uuid = 1; + int32 previous_slot = 2; + int32 new_slot = 3; +} + message AsyncPlayerPreLoginEvent { string name = 1; patchbukkit.common.UUID player_uuid = 2; diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index 8119920..65dcc79 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -29,7 +29,7 @@ use crate::proto::patchbukkit::events::{ PlayerChangedMainHandEvent, PlayerRegisterChannelEvent, PlayerUnregisterChannelEvent, PlayerDropItemEvent, PlayerEditBookEvent, PlayerEggThrowEvent, PlayerExpChangeEvent, PlayerFishEvent, - PlayerInteractEntityEvent, PlayerInteractAtEntityEvent, + PlayerInteractEntityEvent, PlayerInteractAtEntityEvent, PlayerItemHeldEvent, }; pub struct EventContext { @@ -1195,6 +1195,37 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_interact_at_entity::Pl } } +impl PatchBukkitEvent for pumpkin::plugin::player::player_item_held::PlayerItemHeldEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerItemHeld(PlayerItemHeldEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + previous_slot: self.previous_slot, + new_slot: self.new_slot, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerItemHeld(event) => { + self.previous_slot = event.previous_slot; + self.new_slot = event.new_slot; + } + _ => {} + } + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::player::player_interact_event::PlayerInteractEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { let world_uuid = self.player.world().uuid; diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index 265a5fa..075eeb9 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -13,6 +13,7 @@ use pumpkin::plugin::player::player_exp_change::PlayerExpChangeEvent; use pumpkin::plugin::player::player_fish::PlayerFishEvent; use pumpkin::plugin::player::player_interact_entity::PlayerInteractEntityEvent; use pumpkin::plugin::player::player_interact_at_entity::PlayerInteractAtEntityEvent; +use pumpkin::plugin::player::player_item_held::PlayerItemHeldEvent; use pumpkin::plugin::player::player_interact_event::{InteractAction, PlayerInteractEvent}; use pumpkin::plugin::player::player_join::PlayerJoinEvent; use pumpkin::plugin::player::player_login::PlayerLoginEvent; @@ -554,6 +555,23 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.player.PlayerItemHeldEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_item_held::PlayerItemHeldEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_item_held::PlayerItemHeldEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.player.PlayerInteractEvent" => { context .register_event::< @@ -1154,6 +1172,18 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let uuid = + uuid::Uuid::parse_str(&player_item_held_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let pumpkin_event = PlayerItemHeldEvent::new( + player, + player_item_held_event_data.previous_slot, + player_item_held_event_data.new_slot, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } Data::PlayerInteract(player_interact_event_data) => { let uuid = uuid::Uuid::parse_str(&player_interact_event_data.player_uuid?.value).ok()?; From bba9d21323b46664a34fca5a0cd2aa29316c8e83 Mon Sep 17 00:00:00 2001 From: yunuservices Date: Thu, 5 Feb 2026 00:13:13 +0300 Subject: [PATCH 22/56] Add player item damage/consume/mend events --- .../entity/PatchBukkitExperienceOrb.java | 65 +++++ .../events/PatchBukkitEventFactory.java | 119 +++++++++ .../events/PatchBukkitEventManager.java | 83 ++++++ proto/patchbukkit/events/event.proto | 4 + proto/patchbukkit/events/player_events.proto | 29 +++ rust/src/events/handler.rs | 242 ++++++++++++++++++ rust/src/java/native_callbacks/events.rs | 163 ++++++++++++ 7 files changed, 705 insertions(+) create mode 100644 java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitExperienceOrb.java diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitExperienceOrb.java b/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitExperienceOrb.java new file mode 100644 index 0000000..57f6b42 --- /dev/null +++ b/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitExperienceOrb.java @@ -0,0 +1,65 @@ +package org.patchbukkit.entity; + +import java.util.UUID; + +import org.bukkit.entity.ExperienceOrb; +import org.jetbrains.annotations.Nullable; + +public class PatchBukkitExperienceOrb extends PatchBukkitEntity implements ExperienceOrb { + private int experience = 0; + private int count = 1; + private UUID triggerEntityId; + private UUID sourceEntityId; + private SpawnReason spawnReason = SpawnReason.UNKNOWN; + + public PatchBukkitExperienceOrb(UUID uuid) { + super(uuid, "EXPERIENCE_ORB"); + } + + @Override + public int getExperience() { + return experience; + } + + @Override + public void setExperience(int experience) { + this.experience = experience; + } + + @Override + public int getCount() { + return count; + } + + @Override + public void setCount(int count) { + this.count = count; + } + + @Override + public @Nullable UUID getTriggerEntityId() { + return triggerEntityId; + } + + @Override + public @Nullable UUID getSourceEntityId() { + return sourceEntityId; + } + + @Override + public SpawnReason getSpawnReason() { + return spawnReason; + } + + public void setTriggerEntityId(@Nullable UUID triggerEntityId) { + this.triggerEntityId = triggerEntityId; + } + + public void setSourceEntityId(@Nullable UUID sourceEntityId) { + this.sourceEntityId = sourceEntityId; + } + + public void setSpawnReason(SpawnReason spawnReason) { + this.spawnReason = spawnReason != null ? spawnReason : SpawnReason.UNKNOWN; + } +} diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index 825f134..4fdb592 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -38,6 +38,10 @@ import org.bukkit.event.player.PlayerInteractEntityEvent; import org.bukkit.event.player.PlayerInteractAtEntityEvent; import org.bukkit.event.player.PlayerItemHeldEvent; +import org.bukkit.event.player.PlayerItemDamageEvent; +import org.bukkit.event.player.PlayerItemBreakEvent; +import org.bukkit.event.player.PlayerItemConsumeEvent; +import org.bukkit.event.player.PlayerItemMendEvent; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.server.BroadcastMessageEvent; @@ -58,6 +62,7 @@ import org.patchbukkit.entity.PatchBukkitItem; import org.patchbukkit.entity.PatchBukkitEgg; import org.patchbukkit.entity.PatchBukkitFishHook; +import org.patchbukkit.entity.PatchBukkitExperienceOrb; import org.bukkit.block.BlockFace; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.EquipmentSlot; @@ -586,6 +591,59 @@ yield new PlayerEggThrowEvent( if (player == null) yield null; yield new PlayerItemHeldEvent(player, heldEvent.getPreviousSlot(), heldEvent.getNewSlot()); } + case PLAYER_ITEM_DAMAGE -> { + patchbukkit.events.PlayerItemDamageEvent damageEvent = event.getPlayerItemDamage(); + Player player = getPlayer(damageEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + ItemStack item = materialToItem(damageEvent.getItemKey(), damageEvent.getItemAmount()); + yield new PlayerItemDamageEvent(player, item, damageEvent.getDamage()); + } + case PLAYER_ITEM_BREAK -> { + patchbukkit.events.PlayerItemBreakEvent breakEvent = event.getPlayerItemBreak(); + Player player = getPlayer(breakEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + ItemStack item = materialToItem(breakEvent.getItemKey(), breakEvent.getItemAmount()); + yield new PlayerItemBreakEvent(player, item); + } + case PLAYER_ITEM_CONSUME -> { + patchbukkit.events.PlayerItemConsumeEvent consumeEvent = event.getPlayerItemConsume(); + Player player = getPlayer(consumeEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + ItemStack item = materialToItem(consumeEvent.getItemKey(), consumeEvent.getItemAmount()); + EquipmentSlot hand = EquipmentSlot.HAND; + if (!consumeEvent.getHand().isEmpty()) { + try { + hand = EquipmentSlot.valueOf(consumeEvent.getHand()); + } catch (IllegalArgumentException ignored) { + hand = EquipmentSlot.HAND; + } + } + yield new PlayerItemConsumeEvent(player, item, hand); + } + case PLAYER_ITEM_MEND -> { + patchbukkit.events.PlayerItemMendEvent mendEvent = event.getPlayerItemMend(); + Player player = getPlayer(mendEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + ItemStack item = materialToItem(mendEvent.getItemKey(), mendEvent.getItemAmount()); + EquipmentSlot slot = EquipmentSlot.HAND; + if (!mendEvent.getSlot().isEmpty()) { + try { + slot = EquipmentSlot.valueOf(mendEvent.getSlot()); + } catch (IllegalArgumentException ignored) { + slot = EquipmentSlot.HAND; + } + } + java.util.UUID orbUuid = java.util.UUID.randomUUID(); + if (mendEvent.hasOrbUuid()) { + try { + orbUuid = java.util.UUID.fromString(mendEvent.getOrbUuid().getValue()); + } catch (IllegalArgumentException ignored) { + orbUuid = java.util.UUID.randomUUID(); + } + } + PatchBukkitExperienceOrb orb = new PatchBukkitExperienceOrb(orbUuid); + yield new PlayerItemMendEvent(player, item, slot, orb, mendEvent.getRepairAmount()); + } case PLAYER_INTERACT -> { patchbukkit.events.PlayerInteractEvent interactEvent = event.getPlayerInteract(); Player player = getPlayer(interactEvent.getPlayerUuid().getValue()); @@ -996,6 +1054,67 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .setNewSlot(heldEvent.getNewSlot()) .build() ); + } else if (event instanceof PlayerItemDamageEvent damageEvent) { + ItemStack item = damageEvent.getItem(); + String itemKey = item != null ? item.getType().getKey().toString() : "minecraft:air"; + int itemAmount = item != null ? item.getAmount() : 0; + eventBuilder.setPlayerItemDamage( + patchbukkit.events.PlayerItemDamageEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(damageEvent.getPlayer().getUniqueId().toString()) + .build()) + .setItemKey(itemKey) + .setItemAmount(itemAmount) + .setDamage(damageEvent.getDamage()) + .build() + ); + } else if (event instanceof PlayerItemBreakEvent breakEvent) { + ItemStack item = breakEvent.getBrokenItem(); + String itemKey = item != null ? item.getType().getKey().toString() : "minecraft:air"; + int itemAmount = item != null ? item.getAmount() : 0; + eventBuilder.setPlayerItemBreak( + patchbukkit.events.PlayerItemBreakEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(breakEvent.getPlayer().getUniqueId().toString()) + .build()) + .setItemKey(itemKey) + .setItemAmount(itemAmount) + .build() + ); + } else if (event instanceof PlayerItemConsumeEvent consumeEvent) { + ItemStack item = consumeEvent.getItem(); + String itemKey = item != null ? item.getType().getKey().toString() : "minecraft:air"; + int itemAmount = item != null ? item.getAmount() : 0; + String hand = consumeEvent.getHand() != null ? consumeEvent.getHand().name() : "HAND"; + eventBuilder.setPlayerItemConsume( + patchbukkit.events.PlayerItemConsumeEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(consumeEvent.getPlayer().getUniqueId().toString()) + .build()) + .setItemKey(itemKey) + .setItemAmount(itemAmount) + .setHand(hand) + .build() + ); + } else if (event instanceof PlayerItemMendEvent mendEvent) { + ItemStack item = mendEvent.getItem(); + String itemKey = item != null ? item.getType().getKey().toString() : "minecraft:air"; + int itemAmount = item != null ? item.getAmount() : 0; + String slot = mendEvent.getSlot() != null ? mendEvent.getSlot().name() : "HAND"; + var builder = patchbukkit.events.PlayerItemMendEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(mendEvent.getPlayer().getUniqueId().toString()) + .build()) + .setItemKey(itemKey) + .setItemAmount(itemAmount) + .setSlot(slot) + .setRepairAmount(mendEvent.getRepairAmount()); + if (mendEvent.getExperienceOrb() != null) { + builder.setOrbUuid(UUID.newBuilder() + .setValue(mendEvent.getExperienceOrb().getUniqueId().toString()) + .build()); + } + eventBuilder.setPlayerItemMend(builder.build()); } else if (event instanceof AsyncPlayerChatEvent chatEvent) { var playerEventBuilder = patchbukkit.events.PlayerChatEvent.newBuilder() .setPlayerUuid(UUID.newBuilder() 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 5d83e53..7c1ab25 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -531,6 +531,89 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.player.PlayerItemDamageEvent": + var damageEvent = (org.bukkit.event.player.PlayerItemDamageEvent) event; + var damageItem = damageEvent.getItem(); + String damageKey = damageItem != null + ? damageItem.getType().getKey().toString() + : "minecraft:air"; + int damageAmount = damageItem != null ? damageItem.getAmount() : 0; + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerItemDamage( + patchbukkit.events.PlayerItemDamageEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(damageEvent.getPlayer().getUniqueId())) + .setItemKey(damageKey) + .setItemAmount(damageAmount) + .setDamage(damageEvent.getDamage()) + .build() + ).build() + ); + break; + case "org.bukkit.event.player.PlayerItemBreakEvent": + var breakEvent = (org.bukkit.event.player.PlayerItemBreakEvent) event; + var brokenItem = breakEvent.getBrokenItem(); + String breakKey = brokenItem != null + ? brokenItem.getType().getKey().toString() + : "minecraft:air"; + int breakAmount = brokenItem != null ? brokenItem.getAmount() : 0; + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerItemBreak( + patchbukkit.events.PlayerItemBreakEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(breakEvent.getPlayer().getUniqueId())) + .setItemKey(breakKey) + .setItemAmount(breakAmount) + .build() + ).build() + ); + break; + case "org.bukkit.event.player.PlayerItemConsumeEvent": + var consumeEvent = (org.bukkit.event.player.PlayerItemConsumeEvent) event; + var consumeItem = consumeEvent.getItem(); + String consumeKey = consumeItem != null + ? consumeItem.getType().getKey().toString() + : "minecraft:air"; + int consumeAmount = consumeItem != null ? consumeItem.getAmount() : 0; + String consumeHand = consumeEvent.getHand() != null + ? consumeEvent.getHand().name() + : "HAND"; + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerItemConsume( + patchbukkit.events.PlayerItemConsumeEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(consumeEvent.getPlayer().getUniqueId())) + .setItemKey(consumeKey) + .setItemAmount(consumeAmount) + .setHand(consumeHand) + .build() + ).build() + ); + break; + case "org.bukkit.event.player.PlayerItemMendEvent": + var mendEvent = (org.bukkit.event.player.PlayerItemMendEvent) event; + var mendItem = mendEvent.getItem(); + String mendKey = mendItem != null + ? mendItem.getType().getKey().toString() + : "minecraft:air"; + int mendAmount = mendItem != null ? mendItem.getAmount() : 0; + String mendSlot = mendEvent.getSlot() != null + ? mendEvent.getSlot().name() + : "HAND"; + var mendBuilder = patchbukkit.events.PlayerItemMendEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(mendEvent.getPlayer().getUniqueId())) + .setItemKey(mendKey) + .setItemAmount(mendAmount) + .setSlot(mendSlot) + .setRepairAmount(mendEvent.getRepairAmount()); + if (mendEvent.getExperienceOrb() != null) { + mendBuilder.setOrbUuid( + BridgeUtils.convertUuid(mendEvent.getExperienceOrb().getUniqueId()) + ); + } + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerItemMend( + mendBuilder.build() + ).build() + ); + break; case "org.bukkit.event.player.PlayerInteractEvent": var interactEvent = (org.bukkit.event.player.PlayerInteractEvent) event; var clicked = interactEvent.getClickedBlock(); diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index 3e3dc0a..7abf153 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -51,6 +51,10 @@ message Event { PlayerInteractEntityEvent player_interact_entity = 36; PlayerInteractAtEntityEvent player_interact_at_entity = 37; PlayerItemHeldEvent player_item_held = 38; + PlayerItemDamageEvent player_item_damage = 39; + PlayerItemBreakEvent player_item_break = 40; + PlayerItemConsumeEvent player_item_consume = 41; + PlayerItemMendEvent player_item_mend = 42; } } diff --git a/proto/patchbukkit/events/player_events.proto b/proto/patchbukkit/events/player_events.proto index 5a55b5c..717db50 100644 --- a/proto/patchbukkit/events/player_events.proto +++ b/proto/patchbukkit/events/player_events.proto @@ -124,6 +124,35 @@ message PlayerItemHeldEvent { int32 new_slot = 3; } +message PlayerItemDamageEvent { + patchbukkit.common.UUID player_uuid = 1; + string item_key = 2; + int32 item_amount = 3; + int32 damage = 4; +} + +message PlayerItemBreakEvent { + patchbukkit.common.UUID player_uuid = 1; + string item_key = 2; + int32 item_amount = 3; +} + +message PlayerItemConsumeEvent { + patchbukkit.common.UUID player_uuid = 1; + string item_key = 2; + int32 item_amount = 3; + string hand = 4; +} + +message PlayerItemMendEvent { + patchbukkit.common.UUID player_uuid = 1; + string item_key = 2; + int32 item_amount = 3; + string slot = 4; + int32 repair_amount = 5; + patchbukkit.common.UUID orb_uuid = 6; +} + message AsyncPlayerPreLoginEvent { string name = 1; patchbukkit.common.UUID player_uuid = 2; diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index 65dcc79..a42af34 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -6,6 +6,7 @@ use pumpkin::entity::player::Player; use pumpkin::plugin::{BoxFuture, Cancellable, EventHandler, Payload}; use pumpkin::server::Server; use pumpkin_api_macros::with_runtime; +use pumpkin_data::data_component_impl::EquipmentSlot; use pumpkin_data::{Block, BlockDirection}; use pumpkin_data::item::Item; use pumpkin_util::Hand; @@ -30,6 +31,7 @@ use crate::proto::patchbukkit::events::{ PlayerRegisterChannelEvent, PlayerUnregisterChannelEvent, PlayerDropItemEvent, PlayerEditBookEvent, PlayerEggThrowEvent, PlayerExpChangeEvent, PlayerFishEvent, PlayerInteractEntityEvent, PlayerInteractAtEntityEvent, PlayerItemHeldEvent, + PlayerItemDamageEvent, PlayerItemBreakEvent, PlayerItemConsumeEvent, PlayerItemMendEvent, }; pub struct EventContext { @@ -1226,6 +1228,219 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_item_held::PlayerItemH } } +impl PatchBukkitEvent for pumpkin::plugin::player::player_item_damage::PlayerItemDamageEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerItemDamage(PlayerItemDamageEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + item_key: item_to_key(self.item_stack.item), + item_amount: i32::from(self.item_stack.item_count), + damage: self.damage, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerItemDamage(event) => { + self.damage = event.damage; + let mut key = if event.item_key.is_empty() { + None + } else { + Some(event.item_key) + }; + let mut amount = if event.item_amount > 0 { + Some(event.item_amount as u8) + } else { + None + }; + + if key.is_some() || amount.is_some() { + let fallback_key = item_to_key(self.item_stack.item); + let key = key.take().unwrap_or(fallback_key); + let count = amount.take().unwrap_or(self.item_stack.item_count); + self.item_stack = item_stack_from_key(&key, count); + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_item_break::PlayerItemBreakEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerItemBreak(PlayerItemBreakEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + item_key: item_to_key(self.item_stack.item), + item_amount: i32::from(self.item_stack.item_count), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerItemBreak(event) => { + let mut key = if event.item_key.is_empty() { + None + } else { + Some(event.item_key) + }; + let mut amount = if event.item_amount > 0 { + Some(event.item_amount as u8) + } else { + None + }; + + if key.is_some() || amount.is_some() { + let fallback_key = item_to_key(self.item_stack.item); + let key = key.take().unwrap_or(fallback_key); + let count = amount.take().unwrap_or(self.item_stack.item_count); + self.item_stack = item_stack_from_key(&key, count); + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_item_consume::PlayerItemConsumeEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let hand = match self.hand { + Hand::Left => "OFF_HAND", + Hand::Right => "HAND", + }; + JvmEventPayload { + event: Event { + data: Some(Data::PlayerItemConsume(PlayerItemConsumeEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + item_key: item_to_key(self.item_stack.item), + item_amount: i32::from(self.item_stack.item_count), + hand: hand.to_string(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerItemConsume(event) => { + if !event.hand.is_empty() { + self.hand = if event.hand == "OFF_HAND" { + Hand::Left + } else { + Hand::Right + }; + } + + let mut key = if event.item_key.is_empty() { + None + } else { + Some(event.item_key) + }; + let mut amount = if event.item_amount > 0 { + Some(event.item_amount as u8) + } else { + None + }; + + if key.is_some() || amount.is_some() { + let fallback_key = item_to_key(self.item_stack.item); + let key = key.take().unwrap_or(fallback_key); + let count = amount.take().unwrap_or(self.item_stack.item_count); + self.item_stack = item_stack_from_key(&key, count); + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_item_mend::PlayerItemMendEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerItemMend(PlayerItemMendEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + item_key: item_to_key(self.item_stack.item), + item_amount: i32::from(self.item_stack.item_count), + slot: equipment_slot_to_bukkit(&self.slot), + repair_amount: self.repair_amount, + orb_uuid: self.orb_uuid.map(|id| Uuid { value: id.to_string() }), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerItemMend(event) => { + self.repair_amount = event.repair_amount; + if !event.slot.is_empty() { + if let Some(slot) = equipment_slot_from_bukkit(&event.slot) { + self.slot = slot; + } + } + if let Some(uuid) = event.orb_uuid { + if let Ok(orb_uuid) = uuid::Uuid::from_str(&uuid.value) { + self.orb_uuid = Some(orb_uuid); + } + } + let mut key = if event.item_key.is_empty() { + None + } else { + Some(event.item_key) + }; + let mut amount = if event.item_amount > 0 { + Some(event.item_amount as u8) + } else { + None + }; + + if key.is_some() || amount.is_some() { + let fallback_key = item_to_key(self.item_stack.item); + let key = key.take().unwrap_or(fallback_key); + let count = amount.take().unwrap_or(self.item_stack.item_count); + self.item_stack = item_stack_from_key(&key, count); + } + } + _ => {} + } + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::player::player_interact_event::PlayerInteractEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { let world_uuid = self.player.world().uuid; @@ -1528,6 +1743,33 @@ fn item_stack_from_key(key: &str, amount: u8) -> ItemStack { ItemStack::new(amount, item) } +fn equipment_slot_to_bukkit(slot: &EquipmentSlot) -> String { + match slot { + EquipmentSlot::MainHand(_) => "HAND".to_string(), + EquipmentSlot::OffHand(_) => "OFF_HAND".to_string(), + EquipmentSlot::Feet(_) => "FEET".to_string(), + EquipmentSlot::Legs(_) => "LEGS".to_string(), + EquipmentSlot::Chest(_) => "CHEST".to_string(), + EquipmentSlot::Head(_) => "HEAD".to_string(), + EquipmentSlot::Body(_) => "BODY".to_string(), + EquipmentSlot::Saddle(_) => "SADDLE".to_string(), + } +} + +fn equipment_slot_from_bukkit(slot: &str) -> Option { + match slot { + "HAND" => Some(EquipmentSlot::MAIN_HAND), + "OFF_HAND" => Some(EquipmentSlot::OFF_HAND), + "FEET" => Some(EquipmentSlot::FEET), + "LEGS" => Some(EquipmentSlot::LEGS), + "CHEST" => Some(EquipmentSlot::CHEST), + "HEAD" => Some(EquipmentSlot::HEAD), + "BODY" => Some(EquipmentSlot::BODY), + "SADDLE" => Some(EquipmentSlot::SADDLE), + _ => None, + } +} + fn interact_action_to_bukkit(action: &pumpkin::plugin::player::player_interact_event::InteractAction) -> String { match action { pumpkin::plugin::player::player_interact_event::InteractAction::LeftClickBlock => { diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index 075eeb9..0453e21 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -14,6 +14,10 @@ use pumpkin::plugin::player::player_fish::PlayerFishEvent; use pumpkin::plugin::player::player_interact_entity::PlayerInteractEntityEvent; use pumpkin::plugin::player::player_interact_at_entity::PlayerInteractAtEntityEvent; use pumpkin::plugin::player::player_item_held::PlayerItemHeldEvent; +use pumpkin::plugin::player::player_item_damage::PlayerItemDamageEvent; +use pumpkin::plugin::player::player_item_break::PlayerItemBreakEvent; +use pumpkin::plugin::player::player_item_consume::PlayerItemConsumeEvent; +use pumpkin::plugin::player::player_item_mend::PlayerItemMendEvent; use pumpkin::plugin::player::player_interact_event::{InteractAction, PlayerInteractEvent}; use pumpkin::plugin::player::player_join::PlayerJoinEvent; use pumpkin::plugin::player::player_login::PlayerLoginEvent; @@ -38,6 +42,7 @@ use pumpkin::plugin::server::server_broadcast::ServerBroadcastEvent; use pumpkin::plugin::server::server_command::ServerCommandEvent; use pumpkin_data::Block; use pumpkin_data::BlockDirection; +use pumpkin_data::data_component_impl::EquipmentSlot; use pumpkin_data::item::Item; use pumpkin_world::item::ItemStack; use pumpkin_util::math::vector3::Vector3; @@ -572,6 +577,74 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.player.PlayerItemDamageEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_item_damage::PlayerItemDamageEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_item_damage::PlayerItemDamageEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerItemBreakEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_item_break::PlayerItemBreakEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_item_break::PlayerItemBreakEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerItemConsumeEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_item_consume::PlayerItemConsumeEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_item_consume::PlayerItemConsumeEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerItemMendEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_item_mend::PlayerItemMendEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_item_mend::PlayerItemMendEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.player.PlayerInteractEvent" => { context .register_event::< @@ -1184,6 +1257,82 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let uuid = + uuid::Uuid::parse_str(&player_item_damage_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let key = if player_item_damage_event_data.item_key.is_empty() { + "minecraft:air" + } else { + player_item_damage_event_data.item_key.as_str() + }; + let item = item_stack_from_key(key, player_item_damage_event_data.item_amount); + let pumpkin_event = PlayerItemDamageEvent::new( + player, + item, + player_item_damage_event_data.damage, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerItemBreak(player_item_break_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_item_break_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let key = if player_item_break_event_data.item_key.is_empty() { + "minecraft:air" + } else { + player_item_break_event_data.item_key.as_str() + }; + let item = item_stack_from_key(key, player_item_break_event_data.item_amount); + let pumpkin_event = PlayerItemBreakEvent::new(player, item); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerItemConsume(player_item_consume_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_item_consume_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let key = if player_item_consume_event_data.item_key.is_empty() { + "minecraft:air" + } else { + player_item_consume_event_data.item_key.as_str() + }; + let item = item_stack_from_key(key, player_item_consume_event_data.item_amount); + let hand = if player_item_consume_event_data.hand == "OFF_HAND" { + Hand::Left + } else { + Hand::Right + }; + let pumpkin_event = PlayerItemConsumeEvent::new(player, item, hand); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerItemMend(player_item_mend_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_item_mend_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let key = if player_item_mend_event_data.item_key.is_empty() { + "minecraft:air" + } else { + player_item_mend_event_data.item_key.as_str() + }; + let item = item_stack_from_key(key, player_item_mend_event_data.item_amount); + let slot = equipment_slot_from_bukkit(&player_item_mend_event_data.slot) + .unwrap_or(EquipmentSlot::MAIN_HAND); + let orb_uuid = player_item_mend_event_data + .orb_uuid + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()); + let pumpkin_event = PlayerItemMendEvent::new( + player, + item, + slot, + player_item_mend_event_data.repair_amount, + orb_uuid, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } Data::PlayerInteract(player_interact_event_data) => { let uuid = uuid::Uuid::parse_str(&player_interact_event_data.player_uuid?.value).ok()?; @@ -1350,6 +1499,20 @@ fn item_stack_from_key(key: &str, amount: i32) -> ItemStack { ItemStack::new(count, item) } +fn equipment_slot_from_bukkit(slot: &str) -> Option { + match slot { + "HAND" => Some(EquipmentSlot::MAIN_HAND), + "OFF_HAND" => Some(EquipmentSlot::OFF_HAND), + "FEET" => Some(EquipmentSlot::FEET), + "LEGS" => Some(EquipmentSlot::LEGS), + "CHEST" => Some(EquipmentSlot::CHEST), + "HEAD" => Some(EquipmentSlot::HEAD), + "BODY" => Some(EquipmentSlot::BODY), + "SADDLE" => Some(EquipmentSlot::SADDLE), + _ => None, + } +} + fn bukkit_block_face_to_direction(face: &str) -> Option { match face { "UP" => Some(BlockDirection::Up), From a4005b5979519e603dbffcc22a8fd8e47039c929 Mon Sep 17 00:00:00 2001 From: yunuservices Date: Thu, 5 Feb 2026 00:25:06 +0300 Subject: [PATCH 23/56] Add player kick and level change events --- .../events/PatchBukkitEventFactory.java | 52 +++++++++++++ .../events/PatchBukkitEventManager.java | 28 +++++++ proto/patchbukkit/events/event.proto | 2 + proto/patchbukkit/events/player_events.proto | 13 ++++ rust/src/events/handler.rs | 75 +++++++++++++++++++ rust/src/java/native_callbacks/events.rs | 66 ++++++++++++++++ 6 files changed, 236 insertions(+) diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index 4fdb592..8e0a590 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -42,6 +42,8 @@ import org.bukkit.event.player.PlayerItemBreakEvent; import org.bukkit.event.player.PlayerItemConsumeEvent; import org.bukkit.event.player.PlayerItemMendEvent; +import org.bukkit.event.player.PlayerKickEvent; +import org.bukkit.event.player.PlayerLevelChangeEvent; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.server.BroadcastMessageEvent; @@ -644,6 +646,32 @@ yield new PlayerEggThrowEvent( PatchBukkitExperienceOrb orb = new PatchBukkitExperienceOrb(orbUuid); yield new PlayerItemMendEvent(player, item, slot, orb, mendEvent.getRepairAmount()); } + case PLAYER_LEVEL_CHANGE -> { + patchbukkit.events.PlayerLevelChangeEvent levelEvent = event.getPlayerLevelChange(); + Player player = getPlayer(levelEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + yield new PlayerLevelChangeEvent(player, levelEvent.getOldLevel(), levelEvent.getNewLevel()); + } + case PLAYER_KICK -> { + patchbukkit.events.PlayerKickEvent kickEvent = event.getPlayerKick(); + Player player = getPlayer(kickEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + Component reason = kickEvent.getReason().isEmpty() + ? Component.text("") + : GsonComponentSerializer.gson().deserialize(kickEvent.getReason()); + Component leaveMessage = kickEvent.getLeaveMessage().isEmpty() + ? Component.text("") + : GsonComponentSerializer.gson().deserialize(kickEvent.getLeaveMessage()); + PlayerKickEvent.Cause cause = PlayerKickEvent.Cause.UNKNOWN; + if (!kickEvent.getCause().isEmpty()) { + try { + cause = PlayerKickEvent.Cause.valueOf(kickEvent.getCause()); + } catch (IllegalArgumentException ignored) { + cause = PlayerKickEvent.Cause.UNKNOWN; + } + } + yield new PlayerKickEvent(player, reason, leaveMessage, cause); + } case PLAYER_INTERACT -> { patchbukkit.events.PlayerInteractEvent interactEvent = event.getPlayerInteract(); Player player = getPlayer(interactEvent.getPlayerUuid().getValue()); @@ -1115,6 +1143,30 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .build()); } eventBuilder.setPlayerItemMend(builder.build()); + } else if (event instanceof PlayerLevelChangeEvent levelEvent) { + eventBuilder.setPlayerLevelChange( + patchbukkit.events.PlayerLevelChangeEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(levelEvent.getPlayer().getUniqueId().toString()) + .build()) + .setOldLevel(levelEvent.getOldLevel()) + .setNewLevel(levelEvent.getNewLevel()) + .build() + ); + } else if (event instanceof PlayerKickEvent kickEvent) { + String reason = GsonComponentSerializer.gson().serialize(kickEvent.reason()); + String leaveMessage = GsonComponentSerializer.gson().serialize(kickEvent.leaveMessage()); + String cause = kickEvent.getCause() != null ? kickEvent.getCause().name() : "UNKNOWN"; + eventBuilder.setPlayerKick( + patchbukkit.events.PlayerKickEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(kickEvent.getPlayer().getUniqueId().toString()) + .build()) + .setReason(reason) + .setLeaveMessage(leaveMessage) + .setCause(cause) + .build() + ); } else if (event instanceof AsyncPlayerChatEvent chatEvent) { var playerEventBuilder = patchbukkit.events.PlayerChatEvent.newBuilder() .setPlayerUuid(UUID.newBuilder() 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 7c1ab25..be75f01 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -614,6 +614,34 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.player.PlayerLevelChangeEvent": + var levelEvent = (org.bukkit.event.player.PlayerLevelChangeEvent) event; + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerLevelChange( + patchbukkit.events.PlayerLevelChangeEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(levelEvent.getPlayer().getUniqueId())) + .setOldLevel(levelEvent.getOldLevel()) + .setNewLevel(levelEvent.getNewLevel()) + .build() + ).build() + ); + break; + case "org.bukkit.event.player.PlayerKickEvent": + var kickEvent = (org.bukkit.event.player.PlayerKickEvent) event; + String reason = GsonComponentSerializer.gson().serialize(kickEvent.reason()); + String leaveMessage = GsonComponentSerializer.gson().serialize(kickEvent.leaveMessage()); + String cause = kickEvent.getCause() != null ? kickEvent.getCause().name() : "UNKNOWN"; + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerKick( + patchbukkit.events.PlayerKickEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(kickEvent.getPlayer().getUniqueId())) + .setReason(reason) + .setLeaveMessage(leaveMessage) + .setCause(cause) + .build() + ).build() + ); + break; case "org.bukkit.event.player.PlayerInteractEvent": var interactEvent = (org.bukkit.event.player.PlayerInteractEvent) event; var clicked = interactEvent.getClickedBlock(); diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index 7abf153..51cb684 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -55,6 +55,8 @@ message Event { PlayerItemBreakEvent player_item_break = 40; PlayerItemConsumeEvent player_item_consume = 41; PlayerItemMendEvent player_item_mend = 42; + PlayerLevelChangeEvent player_level_change = 43; + PlayerKickEvent player_kick = 44; } } diff --git a/proto/patchbukkit/events/player_events.proto b/proto/patchbukkit/events/player_events.proto index 717db50..38a66fe 100644 --- a/proto/patchbukkit/events/player_events.proto +++ b/proto/patchbukkit/events/player_events.proto @@ -153,6 +153,19 @@ message PlayerItemMendEvent { patchbukkit.common.UUID orb_uuid = 6; } +message PlayerLevelChangeEvent { + patchbukkit.common.UUID player_uuid = 1; + int32 old_level = 2; + int32 new_level = 3; +} + +message PlayerKickEvent { + patchbukkit.common.UUID player_uuid = 1; + string reason = 2; + string leave_message = 3; + string cause = 4; +} + message AsyncPlayerPreLoginEvent { string name = 1; patchbukkit.common.UUID player_uuid = 2; diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index a42af34..087c879 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -32,6 +32,7 @@ use crate::proto::patchbukkit::events::{ PlayerEditBookEvent, PlayerEggThrowEvent, PlayerExpChangeEvent, PlayerFishEvent, PlayerInteractEntityEvent, PlayerInteractAtEntityEvent, PlayerItemHeldEvent, PlayerItemDamageEvent, PlayerItemBreakEvent, PlayerItemConsumeEvent, PlayerItemMendEvent, + PlayerLevelChangeEvent, PlayerKickEvent, }; pub struct EventContext { @@ -1441,6 +1442,80 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_item_mend::PlayerItemM } } +impl PatchBukkitEvent for pumpkin::plugin::player::player_level_change::PlayerLevelChangeEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerLevelChange(PlayerLevelChangeEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + old_level: self.old_level, + new_level: self.new_level, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerLevelChange(event) => { + self.old_level = event.old_level; + self.new_level = event.new_level; + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_kick::PlayerKickEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerKick(PlayerKickEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + reason: serde_json::to_string(&self.reason).unwrap_or_default(), + leave_message: serde_json::to_string(&self.leave_message).unwrap_or_default(), + cause: self.cause.clone(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerKick(event) => { + if !event.reason.is_empty() { + if let Ok(reason) = serde_json::from_str(&event.reason) { + self.reason = reason; + } + } + if !event.leave_message.is_empty() { + if let Ok(msg) = serde_json::from_str(&event.leave_message) { + self.leave_message = msg; + } + } + if !event.cause.is_empty() { + self.cause = event.cause; + } + } + _ => {} + } + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::player::player_interact_event::PlayerInteractEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { let world_uuid = self.player.world().uuid; diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index 0453e21..5ab61aa 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -18,6 +18,8 @@ use pumpkin::plugin::player::player_item_damage::PlayerItemDamageEvent; use pumpkin::plugin::player::player_item_break::PlayerItemBreakEvent; use pumpkin::plugin::player::player_item_consume::PlayerItemConsumeEvent; use pumpkin::plugin::player::player_item_mend::PlayerItemMendEvent; +use pumpkin::plugin::player::player_level_change::PlayerLevelChangeEvent; +use pumpkin::plugin::player::player_kick::PlayerKickEvent; use pumpkin::plugin::player::player_interact_event::{InteractAction, PlayerInteractEvent}; use pumpkin::plugin::player::player_join::PlayerJoinEvent; use pumpkin::plugin::player::player_login::PlayerLoginEvent; @@ -645,6 +647,40 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.player.PlayerLevelChangeEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_level_change::PlayerLevelChangeEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_level_change::PlayerLevelChangeEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerKickEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_kick::PlayerKickEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_kick::PlayerKickEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.player.PlayerInteractEvent" => { context .register_event::< @@ -1333,6 +1369,36 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let uuid = + uuid::Uuid::parse_str(&player_level_change_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let pumpkin_event = PlayerLevelChangeEvent::new( + player, + player_level_change_event_data.old_level, + player_level_change_event_data.new_level, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerKick(player_kick_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_kick_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let reason = serde_json::from_str(&player_kick_event_data.reason) + .unwrap_or_else(|_| TextComponent::text(&player_kick_event_data.reason)); + let leave_message = serde_json::from_str(&player_kick_event_data.leave_message) + .unwrap_or_else(|_| TextComponent::text(&player_kick_event_data.leave_message)); + let cause = if player_kick_event_data.cause.is_empty() { + "UNKNOWN".to_string() + } else { + player_kick_event_data.cause + }; + let pumpkin_event = + PlayerKickEvent::new(player, reason, leave_message, cause); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } Data::PlayerInteract(player_interact_event_data) => { let uuid = uuid::Uuid::parse_str(&player_interact_event_data.player_uuid?.value).ok()?; From 1e73933728f42accf308ead340c1f5e1e36252c6 Mon Sep 17 00:00:00 2001 From: yunuservices Date: Thu, 5 Feb 2026 00:36:28 +0300 Subject: [PATCH 24/56] Add player toggle and swap hand events --- .../events/PatchBukkitEventFactory.java | 75 +++++++++ .../events/PatchBukkitEventManager.java | 53 +++++++ proto/patchbukkit/events/event.proto | 4 + proto/patchbukkit/events/player_events.proto | 23 +++ rust/src/events/handler.rs | 146 ++++++++++++++++++ rust/src/java/native_callbacks/events.rs | 131 ++++++++++++++++ 6 files changed, 432 insertions(+) diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index 8e0a590..a8f5a2d 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -44,6 +44,10 @@ import org.bukkit.event.player.PlayerItemMendEvent; import org.bukkit.event.player.PlayerKickEvent; import org.bukkit.event.player.PlayerLevelChangeEvent; +import org.bukkit.event.player.PlayerToggleSneakEvent; +import org.bukkit.event.player.PlayerToggleSprintEvent; +import org.bukkit.event.player.PlayerToggleFlightEvent; +import org.bukkit.event.player.PlayerSwapHandItemsEvent; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.server.BroadcastMessageEvent; @@ -672,6 +676,32 @@ yield new PlayerEggThrowEvent( } yield new PlayerKickEvent(player, reason, leaveMessage, cause); } + case PLAYER_TOGGLE_SNEAK -> { + patchbukkit.events.PlayerToggleSneakEvent toggleEvent = event.getPlayerToggleSneak(); + Player player = getPlayer(toggleEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + yield new PlayerToggleSneakEvent(player, toggleEvent.getIsSneaking()); + } + case PLAYER_TOGGLE_SPRINT -> { + patchbukkit.events.PlayerToggleSprintEvent toggleEvent = event.getPlayerToggleSprint(); + Player player = getPlayer(toggleEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + yield new PlayerToggleSprintEvent(player, toggleEvent.getIsSprinting()); + } + case PLAYER_TOGGLE_FLIGHT -> { + patchbukkit.events.PlayerToggleFlightEvent toggleEvent = event.getPlayerToggleFlight(); + Player player = getPlayer(toggleEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + yield new PlayerToggleFlightEvent(player, toggleEvent.getIsFlying()); + } + case PLAYER_SWAP_HAND_ITEMS -> { + patchbukkit.events.PlayerSwapHandItemsEvent swapEvent = event.getPlayerSwapHandItems(); + Player player = getPlayer(swapEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + ItemStack mainHand = materialToItem(swapEvent.getMainHandItemKey(), swapEvent.getMainHandItemAmount()); + ItemStack offHand = materialToItem(swapEvent.getOffHandItemKey(), swapEvent.getOffHandItemAmount()); + yield new PlayerSwapHandItemsEvent(player, mainHand, offHand); + } case PLAYER_INTERACT -> { patchbukkit.events.PlayerInteractEvent interactEvent = event.getPlayerInteract(); Player player = getPlayer(interactEvent.getPlayerUuid().getValue()); @@ -1167,6 +1197,51 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .setCause(cause) .build() ); + } else if (event instanceof PlayerToggleSneakEvent toggleEvent) { + eventBuilder.setPlayerToggleSneak( + patchbukkit.events.PlayerToggleSneakEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(toggleEvent.getPlayer().getUniqueId().toString()) + .build()) + .setIsSneaking(toggleEvent.isSneaking()) + .build() + ); + } else if (event instanceof PlayerToggleSprintEvent toggleEvent) { + eventBuilder.setPlayerToggleSprint( + patchbukkit.events.PlayerToggleSprintEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(toggleEvent.getPlayer().getUniqueId().toString()) + .build()) + .setIsSprinting(toggleEvent.isSprinting()) + .build() + ); + } else if (event instanceof PlayerToggleFlightEvent toggleEvent) { + eventBuilder.setPlayerToggleFlight( + patchbukkit.events.PlayerToggleFlightEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(toggleEvent.getPlayer().getUniqueId().toString()) + .build()) + .setIsFlying(toggleEvent.isFlying()) + .build() + ); + } else if (event instanceof PlayerSwapHandItemsEvent swapEvent) { + ItemStack mainHand = swapEvent.getMainHandItem(); + ItemStack offHand = swapEvent.getOffHandItem(); + String mainKey = mainHand != null ? mainHand.getType().getKey().toString() : "minecraft:air"; + int mainAmount = mainHand != null ? mainHand.getAmount() : 0; + String offKey = offHand != null ? offHand.getType().getKey().toString() : "minecraft:air"; + int offAmount = offHand != null ? offHand.getAmount() : 0; + eventBuilder.setPlayerSwapHandItems( + patchbukkit.events.PlayerSwapHandItemsEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(swapEvent.getPlayer().getUniqueId().toString()) + .build()) + .setMainHandItemKey(mainKey) + .setMainHandItemAmount(mainAmount) + .setOffHandItemKey(offKey) + .setOffHandItemAmount(offAmount) + .build() + ); } else if (event instanceof AsyncPlayerChatEvent chatEvent) { var playerEventBuilder = patchbukkit.events.PlayerChatEvent.newBuilder() .setPlayerUuid(UUID.newBuilder() 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 be75f01..b40d8be 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -642,6 +642,59 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.player.PlayerToggleSneakEvent": + var toggleSneakEvent = (org.bukkit.event.player.PlayerToggleSneakEvent) event; + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerToggleSneak( + patchbukkit.events.PlayerToggleSneakEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(toggleSneakEvent.getPlayer().getUniqueId())) + .setIsSneaking(toggleSneakEvent.isSneaking()) + .build() + ).build() + ); + break; + case "org.bukkit.event.player.PlayerToggleSprintEvent": + var toggleSprintEvent = (org.bukkit.event.player.PlayerToggleSprintEvent) event; + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerToggleSprint( + patchbukkit.events.PlayerToggleSprintEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(toggleSprintEvent.getPlayer().getUniqueId())) + .setIsSprinting(toggleSprintEvent.isSprinting()) + .build() + ).build() + ); + break; + case "org.bukkit.event.player.PlayerToggleFlightEvent": + var toggleFlightEvent = (org.bukkit.event.player.PlayerToggleFlightEvent) event; + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerToggleFlight( + patchbukkit.events.PlayerToggleFlightEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(toggleFlightEvent.getPlayer().getUniqueId())) + .setIsFlying(toggleFlightEvent.isFlying()) + .build() + ).build() + ); + break; + case "org.bukkit.event.player.PlayerSwapHandItemsEvent": + var swapEvent = (org.bukkit.event.player.PlayerSwapHandItemsEvent) event; + var mainHand = swapEvent.getMainHandItem(); + var offHand = swapEvent.getOffHandItem(); + String mainKey = mainHand != null ? mainHand.getType().getKey().toString() : "minecraft:air"; + int mainAmount = mainHand != null ? mainHand.getAmount() : 0; + String offKey = offHand != null ? offHand.getType().getKey().toString() : "minecraft:air"; + int offAmount = offHand != null ? offHand.getAmount() : 0; + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerSwapHandItems( + patchbukkit.events.PlayerSwapHandItemsEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(swapEvent.getPlayer().getUniqueId())) + .setMainHandItemKey(mainKey) + .setMainHandItemAmount(mainAmount) + .setOffHandItemKey(offKey) + .setOffHandItemAmount(offAmount) + .build() + ).build() + ); + break; case "org.bukkit.event.player.PlayerInteractEvent": var interactEvent = (org.bukkit.event.player.PlayerInteractEvent) event; var clicked = interactEvent.getClickedBlock(); diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index 51cb684..b14b9e8 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -57,6 +57,10 @@ message Event { PlayerItemMendEvent player_item_mend = 42; PlayerLevelChangeEvent player_level_change = 43; PlayerKickEvent player_kick = 44; + PlayerToggleSneakEvent player_toggle_sneak = 45; + PlayerToggleSprintEvent player_toggle_sprint = 46; + PlayerToggleFlightEvent player_toggle_flight = 47; + PlayerSwapHandItemsEvent player_swap_hand_items = 48; } } diff --git a/proto/patchbukkit/events/player_events.proto b/proto/patchbukkit/events/player_events.proto index 38a66fe..88de27f 100644 --- a/proto/patchbukkit/events/player_events.proto +++ b/proto/patchbukkit/events/player_events.proto @@ -166,6 +166,29 @@ message PlayerKickEvent { string cause = 4; } +message PlayerToggleSneakEvent { + patchbukkit.common.UUID player_uuid = 1; + bool is_sneaking = 2; +} + +message PlayerToggleSprintEvent { + patchbukkit.common.UUID player_uuid = 1; + bool is_sprinting = 2; +} + +message PlayerToggleFlightEvent { + patchbukkit.common.UUID player_uuid = 1; + bool is_flying = 2; +} + +message PlayerSwapHandItemsEvent { + patchbukkit.common.UUID player_uuid = 1; + string main_hand_item_key = 2; + int32 main_hand_item_amount = 3; + string off_hand_item_key = 4; + int32 off_hand_item_amount = 5; +} + message AsyncPlayerPreLoginEvent { string name = 1; patchbukkit.common.UUID player_uuid = 2; diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index 087c879..426da86 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -33,6 +33,8 @@ use crate::proto::patchbukkit::events::{ PlayerInteractEntityEvent, PlayerInteractAtEntityEvent, PlayerItemHeldEvent, PlayerItemDamageEvent, PlayerItemBreakEvent, PlayerItemConsumeEvent, PlayerItemMendEvent, PlayerLevelChangeEvent, PlayerKickEvent, + PlayerToggleSneakEvent, PlayerToggleSprintEvent, PlayerToggleFlightEvent, + PlayerSwapHandItemsEvent, }; pub struct EventContext { @@ -1516,6 +1518,150 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_kick::PlayerKickEvent } } +impl PatchBukkitEvent for pumpkin::plugin::player::player_toggle_sneak::PlayerToggleSneakEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerToggleSneak(PlayerToggleSneakEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + is_sneaking: self.is_sneaking, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerToggleSneak(event) => { + self.is_sneaking = event.is_sneaking; + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_toggle_sprint::PlayerToggleSprintEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerToggleSprint(PlayerToggleSprintEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + is_sprinting: self.is_sprinting, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerToggleSprint(event) => { + self.is_sprinting = event.is_sprinting; + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_toggle_flight::PlayerToggleFlightEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerToggleFlight(PlayerToggleFlightEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + is_flying: self.is_flying, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerToggleFlight(event) => { + self.is_flying = event.is_flying; + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_swap_hand_items::PlayerSwapHandItemsEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerSwapHandItems(PlayerSwapHandItemsEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + main_hand_item_key: item_to_key(self.main_hand_item.item), + main_hand_item_amount: i32::from(self.main_hand_item.item_count), + off_hand_item_key: item_to_key(self.off_hand_item.item), + off_hand_item_amount: i32::from(self.off_hand_item.item_count), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerSwapHandItems(event) => { + if !event.main_hand_item_key.is_empty() || event.main_hand_item_amount > 0 { + let key = if event.main_hand_item_key.is_empty() { + item_to_key(self.main_hand_item.item) + } else { + event.main_hand_item_key + }; + let count = if event.main_hand_item_amount > 0 { + event.main_hand_item_amount as u8 + } else { + self.main_hand_item.item_count + }; + self.main_hand_item = item_stack_from_key(&key, count); + } + if !event.off_hand_item_key.is_empty() || event.off_hand_item_amount > 0 { + let key = if event.off_hand_item_key.is_empty() { + item_to_key(self.off_hand_item.item) + } else { + event.off_hand_item_key + }; + let count = if event.off_hand_item_amount > 0 { + event.off_hand_item_amount as u8 + } else { + self.off_hand_item.item_count + }; + self.off_hand_item = item_stack_from_key(&key, count); + } + } + _ => {} + } + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::player::player_interact_event::PlayerInteractEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { let world_uuid = self.player.world().uuid; diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index 5ab61aa..3b9e7f2 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -20,6 +20,10 @@ use pumpkin::plugin::player::player_item_consume::PlayerItemConsumeEvent; use pumpkin::plugin::player::player_item_mend::PlayerItemMendEvent; use pumpkin::plugin::player::player_level_change::PlayerLevelChangeEvent; use pumpkin::plugin::player::player_kick::PlayerKickEvent; +use pumpkin::plugin::player::player_toggle_sneak::PlayerToggleSneakEvent; +use pumpkin::plugin::player::player_toggle_sprint::PlayerToggleSprintEvent; +use pumpkin::plugin::player::player_toggle_flight::PlayerToggleFlightEvent; +use pumpkin::plugin::player::player_swap_hand_items::PlayerSwapHandItemsEvent; use pumpkin::plugin::player::player_interact_event::{InteractAction, PlayerInteractEvent}; use pumpkin::plugin::player::player_join::PlayerJoinEvent; use pumpkin::plugin::player::player_login::PlayerLoginEvent; @@ -681,6 +685,74 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.player.PlayerToggleSneakEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_toggle_sneak::PlayerToggleSneakEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_toggle_sneak::PlayerToggleSneakEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerToggleSprintEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_toggle_sprint::PlayerToggleSprintEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_toggle_sprint::PlayerToggleSprintEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerToggleFlightEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_toggle_flight::PlayerToggleFlightEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_toggle_flight::PlayerToggleFlightEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerSwapHandItemsEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_swap_hand_items::PlayerSwapHandItemsEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_swap_hand_items::PlayerSwapHandItemsEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.player.PlayerInteractEvent" => { context .register_event::< @@ -1399,6 +1471,65 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let uuid = + uuid::Uuid::parse_str(&player_toggle_sneak_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let pumpkin_event = PlayerToggleSneakEvent::new( + player, + player_toggle_sneak_event_data.is_sneaking, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerToggleSprint(player_toggle_sprint_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_toggle_sprint_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let pumpkin_event = PlayerToggleSprintEvent::new( + player, + player_toggle_sprint_event_data.is_sprinting, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerToggleFlight(player_toggle_flight_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_toggle_flight_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let pumpkin_event = PlayerToggleFlightEvent::new( + player, + player_toggle_flight_event_data.is_flying, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerSwapHandItems(player_swap_hand_items_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_swap_hand_items_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let main_key = if player_swap_hand_items_event_data.main_hand_item_key.is_empty() { + "minecraft:air" + } else { + player_swap_hand_items_event_data.main_hand_item_key.as_str() + }; + let off_key = if player_swap_hand_items_event_data.off_hand_item_key.is_empty() { + "minecraft:air" + } else { + player_swap_hand_items_event_data.off_hand_item_key.as_str() + }; + let main_item = item_stack_from_key( + main_key, + player_swap_hand_items_event_data.main_hand_item_amount, + ); + let off_item = item_stack_from_key( + off_key, + player_swap_hand_items_event_data.off_hand_item_amount, + ); + let pumpkin_event = PlayerSwapHandItemsEvent::new(player, main_item, off_item); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } Data::PlayerInteract(player_interact_event_data) => { let uuid = uuid::Uuid::parse_str(&player_interact_event_data.player_uuid?.value).ok()?; From 8b12bef2deb27a39fc52dfabc7dcdc78b270bf94 Mon Sep 17 00:00:00 2001 From: yunuservices Date: Thu, 5 Feb 2026 00:54:13 +0300 Subject: [PATCH 25/56] Add resource pack status and respawn events --- .../events/PatchBukkitEventFactory.java | 120 ++++++++++++++++++ .../events/PatchBukkitEventManager.java | 34 +++++ proto/patchbukkit/events/event.proto | 2 + proto/patchbukkit/events/player_events.proto | 16 +++ rust/src/events/handler.rs | 104 ++++++++++++++- rust/src/java/native_callbacks/events.rs | 80 ++++++++++++ 6 files changed, 355 insertions(+), 1 deletion(-) diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index a8f5a2d..1c824f7 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -48,6 +48,8 @@ import org.bukkit.event.player.PlayerToggleSprintEvent; import org.bukkit.event.player.PlayerToggleFlightEvent; import org.bukkit.event.player.PlayerSwapHandItemsEvent; +import org.bukkit.event.player.PlayerResourcePackStatusEvent; +import org.bukkit.event.player.PlayerRespawnEvent; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.server.BroadcastMessageEvent; @@ -702,6 +704,54 @@ yield new PlayerEggThrowEvent( ItemStack offHand = materialToItem(swapEvent.getOffHandItemKey(), swapEvent.getOffHandItemAmount()); yield new PlayerSwapHandItemsEvent(player, mainHand, offHand); } + case PLAYER_RESOURCE_PACK_STATUS -> { + patchbukkit.events.PlayerResourcePackStatusEvent packEvent = event.getPlayerResourcePackStatus(); + Player player = getPlayer(packEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + java.util.UUID packUuid; + try { + packUuid = java.util.UUID.fromString(packEvent.getPackUuid().getValue()); + } catch (IllegalArgumentException e) { + packUuid = java.util.UUID.randomUUID(); + } + PlayerResourcePackStatusEvent.Status status = PlayerResourcePackStatusEvent.Status.FAILED_DOWNLOAD; + if (!packEvent.getStatus().isEmpty()) { + try { + status = PlayerResourcePackStatusEvent.Status.valueOf(packEvent.getStatus()); + } catch (IllegalArgumentException ignored) { + status = PlayerResourcePackStatusEvent.Status.FAILED_DOWNLOAD; + } + } + PlayerResourcePackStatusEvent statusEvent = + new PlayerResourcePackStatusEvent(player, packUuid, status); + if (!packEvent.getHash().isEmpty()) { + statusEvent.setHash(packEvent.getHash()); + } + yield statusEvent; + } + case PLAYER_RESPAWN -> { + patchbukkit.events.PlayerRespawnEvent respawnEvent = event.getPlayerRespawn(); + Player player = getPlayer(respawnEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + Location location = BridgeUtils.convertLocation(respawnEvent.getRespawnLocation()); + if (location == null) yield null; + PlayerRespawnEvent.RespawnReason reason = PlayerRespawnEvent.RespawnReason.DEATH; + if (!respawnEvent.getRespawnReason().isEmpty()) { + try { + reason = PlayerRespawnEvent.RespawnReason.valueOf(respawnEvent.getRespawnReason()); + } catch (IllegalArgumentException ignored) { + reason = PlayerRespawnEvent.RespawnReason.DEATH; + } + } + yield new PlayerRespawnEvent( + player, + location, + respawnEvent.getIsBedSpawn(), + respawnEvent.getIsAnchorSpawn(), + respawnEvent.getIsMissingRespawnBlock(), + reason + ); + } case PLAYER_INTERACT -> { patchbukkit.events.PlayerInteractEvent interactEvent = event.getPlayerInteract(); Player player = getPlayer(interactEvent.getPlayerUuid().getValue()); @@ -1242,6 +1292,39 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .setOffHandItemAmount(offAmount) .build() ); + } else if (event instanceof PlayerResourcePackStatusEvent packEvent) { + java.util.UUID packUuid = resolveResourcePackId(packEvent); + String status = packEvent.getStatus() != null ? packEvent.getStatus().name() : "FAILED_DOWNLOAD"; + String hash = packEvent.getHash() != null ? packEvent.getHash() : ""; + eventBuilder.setPlayerResourcePackStatus( + patchbukkit.events.PlayerResourcePackStatusEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(packEvent.getPlayer().getUniqueId().toString()) + .build()) + .setPackUuid(UUID.newBuilder() + .setValue(packUuid.toString()) + .build()) + .setStatus(status) + .setHash(hash) + .build() + ); + } else if (event instanceof PlayerRespawnEvent respawnEvent) { + Location location = respawnEvent.getRespawnLocation(); + String reason = respawnEvent.getRespawnReason() != null + ? respawnEvent.getRespawnReason().name() + : "DEATH"; + eventBuilder.setPlayerRespawn( + patchbukkit.events.PlayerRespawnEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(respawnEvent.getPlayer().getUniqueId().toString()) + .build()) + .setRespawnLocation(BridgeUtils.convertLocation(location)) + .setIsBedSpawn(respawnEvent.isBedSpawn()) + .setIsAnchorSpawn(respawnEvent.isAnchorSpawn()) + .setIsMissingRespawnBlock(respawnEvent.isMissingRespawnBlock()) + .setRespawnReason(reason) + .build() + ); } else if (event instanceof AsyncPlayerChatEvent chatEvent) { var playerEventBuilder = patchbukkit.events.PlayerChatEvent.newBuilder() .setPlayerUuid(UUID.newBuilder() @@ -1524,6 +1607,43 @@ private static Player getPlayer(@NotNull String uuidStr) { } } + @NotNull + static java.util.UUID resolveResourcePackId(@NotNull PlayerResourcePackStatusEvent event) { + java.util.UUID packUuid = null; + try { + java.lang.reflect.Method method = event.getClass().getMethod("getPackId"); + Object value = method.invoke(event); + if (value instanceof java.util.UUID uuid) { + packUuid = uuid; + } + } catch (ReflectiveOperationException ignored) { + // Fallback to alternative method names + } + if (packUuid == null) { + try { + java.lang.reflect.Method method = event.getClass().getMethod("getID"); + Object value = method.invoke(event); + if (value instanceof java.util.UUID uuid) { + packUuid = uuid; + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + } + if (packUuid == null) { + try { + java.lang.reflect.Method method = event.getClass().getMethod("getId"); + Object value = method.invoke(event); + if (value instanceof java.util.UUID uuid) { + packUuid = uuid; + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + } + return packUuid != null ? packUuid : java.util.UUID.randomUUID(); + } + @Nullable private static PlayerLoginEvent createLoginEvent(@NotNull Player player) { try { 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 b40d8be..625f1a9 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -695,6 +695,40 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.player.PlayerResourcePackStatusEvent": + var packEvent = (org.bukkit.event.player.PlayerResourcePackStatusEvent) event; + var packUuid = PatchBukkitEventFactory.resolveResourcePackId(packEvent); + String status = packEvent.getStatus() != null ? packEvent.getStatus().name() : "FAILED_DOWNLOAD"; + String hash = packEvent.getHash() != null ? packEvent.getHash() : ""; + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerResourcePackStatus( + patchbukkit.events.PlayerResourcePackStatusEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(packEvent.getPlayer().getUniqueId())) + .setPackUuid(BridgeUtils.convertUuid(packUuid)) + .setStatus(status) + .setHash(hash) + .build() + ).build() + ); + break; + case "org.bukkit.event.player.PlayerRespawnEvent": + var respawnEvent = (org.bukkit.event.player.PlayerRespawnEvent) event; + String reason = respawnEvent.getRespawnReason() != null + ? respawnEvent.getRespawnReason().name() + : "DEATH"; + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerRespawn( + patchbukkit.events.PlayerRespawnEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(respawnEvent.getPlayer().getUniqueId())) + .setRespawnLocation(BridgeUtils.convertLocation(respawnEvent.getRespawnLocation())) + .setIsBedSpawn(respawnEvent.isBedSpawn()) + .setIsAnchorSpawn(respawnEvent.isAnchorSpawn()) + .setIsMissingRespawnBlock(respawnEvent.isMissingRespawnBlock()) + .setRespawnReason(reason) + .build() + ).build() + ); + break; case "org.bukkit.event.player.PlayerInteractEvent": var interactEvent = (org.bukkit.event.player.PlayerInteractEvent) event; var clicked = interactEvent.getClickedBlock(); diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index b14b9e8..594c82f 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -61,6 +61,8 @@ message Event { PlayerToggleSprintEvent player_toggle_sprint = 46; PlayerToggleFlightEvent player_toggle_flight = 47; PlayerSwapHandItemsEvent player_swap_hand_items = 48; + PlayerResourcePackStatusEvent player_resource_pack_status = 49; + PlayerRespawnEvent player_respawn = 50; } } diff --git a/proto/patchbukkit/events/player_events.proto b/proto/patchbukkit/events/player_events.proto index 88de27f..2391ec6 100644 --- a/proto/patchbukkit/events/player_events.proto +++ b/proto/patchbukkit/events/player_events.proto @@ -189,6 +189,22 @@ message PlayerSwapHandItemsEvent { int32 off_hand_item_amount = 5; } +message PlayerResourcePackStatusEvent { + patchbukkit.common.UUID player_uuid = 1; + patchbukkit.common.UUID pack_uuid = 2; + string status = 3; + string hash = 4; +} + +message PlayerRespawnEvent { + patchbukkit.common.UUID player_uuid = 1; + patchbukkit.common.Location respawn_location = 2; + bool is_bed_spawn = 3; + bool is_anchor_spawn = 4; + bool is_missing_respawn_block = 5; + string respawn_reason = 6; +} + message AsyncPlayerPreLoginEvent { string name = 1; patchbukkit.common.UUID player_uuid = 2; diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index 426da86..14d97f2 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -34,7 +34,7 @@ use crate::proto::patchbukkit::events::{ PlayerItemDamageEvent, PlayerItemBreakEvent, PlayerItemConsumeEvent, PlayerItemMendEvent, PlayerLevelChangeEvent, PlayerKickEvent, PlayerToggleSneakEvent, PlayerToggleSprintEvent, PlayerToggleFlightEvent, - PlayerSwapHandItemsEvent, + PlayerSwapHandItemsEvent, PlayerResourcePackStatusEvent, PlayerRespawnEvent, }; pub struct EventContext { @@ -1662,6 +1662,108 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_swap_hand_items::Playe } } +impl PatchBukkitEvent for pumpkin::plugin::player::player_resource_pack_status::PlayerResourcePackStatusEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerResourcePackStatus(PlayerResourcePackStatusEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + pack_uuid: Some(Uuid { + value: self.pack_uuid.to_string(), + }), + status: self.status.clone(), + hash: self.pack_hash.clone(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerResourcePackStatus(event) => { + if let Some(uuid) = event.pack_uuid { + if let Ok(pack_uuid) = uuid::Uuid::from_str(&uuid.value) { + self.pack_uuid = pack_uuid; + } + } + if !event.status.is_empty() { + self.status = event.status; + } + if !event.hash.is_empty() { + self.pack_hash = event.hash; + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_respawn::PlayerRespawnEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let yaw = self.player.living_entity.entity.yaw.load(); + let pitch = self.player.living_entity.entity.pitch.load(); + JvmEventPayload { + event: Event { + data: Some(Data::PlayerRespawn(PlayerRespawnEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + respawn_location: Some(build_location( + self.world_uuid, + &Vector3::new( + self.respawn_position.x, + self.respawn_position.y, + self.respawn_position.z, + ), + yaw, + pitch, + )), + is_bed_spawn: self.is_bed_spawn, + is_anchor_spawn: self.is_anchor_spawn, + is_missing_respawn_block: self.is_missing_respawn_block, + respawn_reason: self.reason.clone(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerRespawn(event) => { + if let Some(loc) = event.respawn_location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.respawn_position = pos; + } + if let Some(world) = loc.world.and_then(|w| w.uuid) { + if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { + self.world_uuid = uuid; + } + } + } + self.is_bed_spawn = event.is_bed_spawn; + self.is_anchor_spawn = event.is_anchor_spawn; + self.is_missing_respawn_block = event.is_missing_respawn_block; + if !event.respawn_reason.is_empty() { + self.reason = event.respawn_reason; + } + } + _ => {} + } + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::player::player_interact_event::PlayerInteractEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { let world_uuid = self.player.world().uuid; diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index 3b9e7f2..0219bd9 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -24,6 +24,8 @@ use pumpkin::plugin::player::player_toggle_sneak::PlayerToggleSneakEvent; use pumpkin::plugin::player::player_toggle_sprint::PlayerToggleSprintEvent; use pumpkin::plugin::player::player_toggle_flight::PlayerToggleFlightEvent; use pumpkin::plugin::player::player_swap_hand_items::PlayerSwapHandItemsEvent; +use pumpkin::plugin::player::player_resource_pack_status::PlayerResourcePackStatusEvent; +use pumpkin::plugin::player::player_respawn::PlayerRespawnEvent; use pumpkin::plugin::player::player_interact_event::{InteractAction, PlayerInteractEvent}; use pumpkin::plugin::player::player_join::PlayerJoinEvent; use pumpkin::plugin::player::player_login::PlayerLoginEvent; @@ -753,6 +755,40 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.player.PlayerResourcePackStatusEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_resource_pack_status::PlayerResourcePackStatusEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_resource_pack_status::PlayerResourcePackStatusEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerRespawnEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_respawn::PlayerRespawnEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_respawn::PlayerRespawnEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.player.PlayerInteractEvent" => { context .register_event::< @@ -1530,6 +1566,50 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let uuid = + uuid::Uuid::parse_str(&player_resource_pack_status_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let pack_uuid = player_resource_pack_status_event_data + .pack_uuid + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) + .unwrap_or_else(uuid::Uuid::new_v4); + let pumpkin_event = PlayerResourcePackStatusEvent::new( + player, + pack_uuid, + player_resource_pack_status_event_data.hash, + player_resource_pack_status_event_data.status, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerRespawn(player_respawn_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_respawn_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let (world_uuid, pos) = if let Some(loc) = player_respawn_event_data.respawn_location { + let world_uuid = loc + .world + .and_then(|w| w.uuid) + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) + .unwrap_or_else(|| player.world().uuid); + let pos = location_to_vec3(loc).unwrap_or_else(|| player.position()); + (world_uuid, pos) + } else { + (player.world().uuid, player.position()) + }; + let pumpkin_event = PlayerRespawnEvent::new( + player, + pos, + world_uuid, + player_respawn_event_data.is_bed_spawn, + player_respawn_event_data.is_anchor_spawn, + player_respawn_event_data.is_missing_respawn_block, + player_respawn_event_data.respawn_reason, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } Data::PlayerInteract(player_interact_event_data) => { let uuid = uuid::Uuid::parse_str(&player_interact_event_data.player_uuid?.value).ok()?; From a56249bcb47d4019c78117a431ce84711935c46e Mon Sep 17 00:00:00 2001 From: yunuservices Date: Thu, 5 Feb 2026 01:24:07 +0300 Subject: [PATCH 26/56] Add portal, velocity, and misc player events --- .../entity/PatchBukkitAbstractArrow.java | 128 ++++++ .../events/PatchBukkitEventFactory.java | 341 +++++++++++++++ .../events/PatchBukkitEventManager.java | 169 ++++++++ proto/patchbukkit/events/event.proto | 8 + proto/patchbukkit/events/player_events.proto | 59 +++ rust/src/events/handler.rs | 396 ++++++++++++++++++ rust/src/java/native_callbacks/events.rs | 322 ++++++++++++++ 7 files changed, 1423 insertions(+) create mode 100644 java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitAbstractArrow.java diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitAbstractArrow.java b/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitAbstractArrow.java new file mode 100644 index 0000000..85683c2 --- /dev/null +++ b/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitAbstractArrow.java @@ -0,0 +1,128 @@ +package org.patchbukkit.entity; + +import java.util.UUID; + +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.block.Block; +import org.bukkit.entity.AbstractArrow; +import org.bukkit.inventory.ItemStack; + +public class PatchBukkitAbstractArrow extends PatchBukkitProjectile implements AbstractArrow { + private PickupStatus pickupStatus = PickupStatus.ALLOWED; + private double damage = 2.0; + private int knockbackStrength = 0; + private int pierceLevel = 0; + private boolean critical = false; + private boolean inBlock = false; + private boolean shotFromCrossbow = false; + private boolean noPhysics = false; + private int lifetimeTicks = 0; + private ItemStack item = new ItemStack(Material.ARROW, 1); + private ItemStack weapon = null; + private Sound hitSound = Sound.ENTITY_ARROW_HIT; + + public PatchBukkitAbstractArrow(UUID uuid, String name) { + super(uuid, name); + } + + public Block getAttachedBlock() { + return null; + } + + public double getDamage() { + return damage; + } + + public void setDamage(double damage) { + this.damage = damage; + } + + public int getKnockbackStrength() { + return knockbackStrength; + } + + public void setKnockbackStrength(int knockbackStrength) { + this.knockbackStrength = knockbackStrength; + } + + public PickupStatus getPickupStatus() { + return pickupStatus; + } + + public void setPickupStatus(PickupStatus status) { + this.pickupStatus = status; + } + + public int getPierceLevel() { + return pierceLevel; + } + + public void setPierceLevel(int pierceLevel) { + this.pierceLevel = pierceLevel; + } + + public boolean isCritical() { + return critical; + } + + public void setCritical(boolean critical) { + this.critical = critical; + } + + public boolean isInBlock() { + return inBlock; + } + + public boolean isShotFromCrossbow() { + return shotFromCrossbow; + } + + public void setShotFromCrossbow(boolean shotFromCrossbow) { + this.shotFromCrossbow = shotFromCrossbow; + } + + public ItemStack getItem() { + return item; + } + + public void setItem(ItemStack item) { + if (item != null) { + this.item = item; + } + } + + public ItemStack getWeapon() { + return weapon != null ? weapon : item; + } + + public void setWeapon(ItemStack weapon) { + this.weapon = weapon; + } + + public Sound getHitSound() { + return hitSound; + } + + public void setHitSound(Sound sound) { + if (sound != null) { + this.hitSound = sound; + } + } + + public boolean hasNoPhysics() { + return noPhysics; + } + + public void setNoPhysics(boolean noPhysics) { + this.noPhysics = noPhysics; + } + + public int getLifetimeTicks() { + return lifetimeTicks; + } + + public void setLifetimeTicks(int ticks) { + this.lifetimeTicks = ticks; + } +} diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index 1c824f7..d74ae9a 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -50,6 +50,14 @@ import org.bukkit.event.player.PlayerSwapHandItemsEvent; import org.bukkit.event.player.PlayerResourcePackStatusEvent; import org.bukkit.event.player.PlayerRespawnEvent; +import org.bukkit.event.player.PlayerPickupArrowEvent; +import org.bukkit.event.player.PlayerPortalEvent; +import org.bukkit.event.player.PlayerRecipeDiscoverEvent; +import org.bukkit.event.player.PlayerRiptideEvent; +import org.bukkit.event.player.PlayerShearEntityEvent; +import org.bukkit.event.player.PlayerStatisticIncrementEvent; +import org.bukkit.event.player.PlayerVelocityEvent; +import org.spigotmc.event.player.PlayerSpawnLocationEvent; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.server.BroadcastMessageEvent; @@ -71,6 +79,7 @@ import org.patchbukkit.entity.PatchBukkitEgg; import org.patchbukkit.entity.PatchBukkitFishHook; import org.patchbukkit.entity.PatchBukkitExperienceOrb; +import org.patchbukkit.entity.PatchBukkitAbstractArrow; import org.bukkit.block.BlockFace; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.EquipmentSlot; @@ -81,6 +90,8 @@ import org.bukkit.Material; import org.bukkit.GameMode; import org.bukkit.NamespacedKey; +import org.bukkit.Statistic; +import org.bukkit.entity.EntityType; import java.net.InetAddress; import patchbukkit.common.UUID; import patchbukkit.events.Event; @@ -752,6 +763,176 @@ yield new PlayerRespawnEvent( reason ); } + case PLAYER_PICKUP_ARROW -> { + patchbukkit.events.PlayerPickupArrowEvent pickupEvent = event.getPlayerPickupArrow(); + Player player = getPlayer(pickupEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + java.util.UUID arrowUuid; + try { + arrowUuid = java.util.UUID.fromString(pickupEvent.getArrowUuid().getValue()); + } catch (IllegalArgumentException e) { + arrowUuid = java.util.UUID.randomUUID(); + } + java.util.UUID itemUuid; + try { + itemUuid = java.util.UUID.fromString(pickupEvent.getItemUuid().getValue()); + } catch (IllegalArgumentException e) { + itemUuid = java.util.UUID.randomUUID(); + } + ItemStack stack = materialToItem(pickupEvent.getItemKey(), pickupEvent.getItemAmount()); + PatchBukkitItem item = new PatchBukkitItem(itemUuid, stack); + PatchBukkitAbstractArrow arrow = new PatchBukkitAbstractArrow(arrowUuid, "Arrow"); + yield new PlayerPickupArrowEvent(player, item, arrow); + } + case PLAYER_PORTAL -> { + patchbukkit.events.PlayerPortalEvent portalEvent = event.getPlayerPortal(); + Player player = getPlayer(portalEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + Location from = BridgeUtils.convertLocation(portalEvent.getFrom()); + Location to = BridgeUtils.convertLocation(portalEvent.getTo()); + if (from == null || to == null) yield null; + PlayerTeleportEvent.TeleportCause cause = PlayerTeleportEvent.TeleportCause.UNKNOWN; + if (!portalEvent.getCause().isEmpty()) { + try { + cause = PlayerTeleportEvent.TeleportCause.valueOf(portalEvent.getCause()); + } catch (IllegalArgumentException ignored) { + cause = PlayerTeleportEvent.TeleportCause.UNKNOWN; + } + } + PlayerPortalEvent eventObj = new PlayerPortalEvent(player, from, to, cause); + try { + var method = PlayerPortalEvent.class.getMethod("setSearchRadius", int.class); + method.invoke(eventObj, portalEvent.getSearchRadius()); + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + var method = PlayerPortalEvent.class.getMethod("setCanCreatePortal", boolean.class); + method.invoke(eventObj, portalEvent.getCanCreatePortal()); + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + var method = PlayerPortalEvent.class.getMethod("setCreationRadius", int.class); + method.invoke(eventObj, portalEvent.getCreationRadius()); + } catch (ReflectiveOperationException ignored) { + // ignore + } + yield eventObj; + } + case PLAYER_RECIPE_DISCOVER -> { + patchbukkit.events.PlayerRecipeDiscoverEvent recipeEvent = event.getPlayerRecipeDiscover(); + Player player = getPlayer(recipeEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + if (recipeEvent.getRecipeKey().isEmpty()) yield null; + NamespacedKey key = NamespacedKey.fromString(recipeEvent.getRecipeKey()); + if (key == null) yield null; + yield new PlayerRecipeDiscoverEvent(player, key); + } + case PLAYER_RIPTIDE -> { + patchbukkit.events.PlayerRiptideEvent riptideEvent = event.getPlayerRiptide(); + Player player = getPlayer(riptideEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + ItemStack item = materialToItem(riptideEvent.getItemKey(), riptideEvent.getItemAmount()); + Vector velocity = new Vector(); + if (riptideEvent.getVelocity() != null) { + velocity = new Vector( + riptideEvent.getVelocity().getX(), + riptideEvent.getVelocity().getY(), + riptideEvent.getVelocity().getZ() + ); + } + yield new PlayerRiptideEvent(player, item, velocity); + } + case PLAYER_SHEAR_ENTITY -> { + patchbukkit.events.PlayerShearEntityEvent shearEvent = event.getPlayerShearEntity(); + Player player = getPlayer(shearEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + java.util.UUID entityUuid; + try { + entityUuid = java.util.UUID.fromString(shearEvent.getEntityUuid().getValue()); + } catch (IllegalArgumentException e) { + entityUuid = java.util.UUID.randomUUID(); + } + PatchBukkitEntity entity = new PatchBukkitEntity(entityUuid, shearEvent.getEntityType()); + ItemStack item = materialToItem(shearEvent.getItemKey(), shearEvent.getItemAmount()); + EquipmentSlot slot = EquipmentSlot.HAND; + if (!shearEvent.getHand().isEmpty()) { + try { + slot = EquipmentSlot.valueOf(shearEvent.getHand()); + } catch (IllegalArgumentException ignored) { + slot = EquipmentSlot.HAND; + } + } + yield new PlayerShearEntityEvent(player, entity, item, slot); + } + case PLAYER_SPAWN_LOCATION -> { + patchbukkit.events.PlayerSpawnLocationEvent spawnEvent = event.getPlayerSpawnLocation(); + Player player = getPlayer(spawnEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + Location location = BridgeUtils.convertLocation(spawnEvent.getSpawnLocation()); + if (location == null) yield null; + yield new PlayerSpawnLocationEvent(player, location); + } + case PLAYER_STATISTIC_INCREMENT -> { + patchbukkit.events.PlayerStatisticIncrementEvent statEvent = event.getPlayerStatisticIncrement(); + Player player = getPlayer(statEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + Statistic statistic; + try { + statistic = Statistic.valueOf(statEvent.getStatistic()); + } catch (IllegalArgumentException e) { + yield null; + } + if (!statEvent.getEntityType().isEmpty()) { + try { + EntityType entityType = EntityType.valueOf(statEvent.getEntityType()); + yield new PlayerStatisticIncrementEvent( + player, + statistic, + statEvent.getInitialValue(), + statEvent.getNewValue(), + entityType + ); + } catch (IllegalArgumentException ignored) { + yield null; + } + } + if (!statEvent.getMaterialKey().isEmpty()) { + Material material = Material.matchMaterial(statEvent.getMaterialKey()); + if (material == null) { + material = Material.matchMaterial("minecraft:" + statEvent.getMaterialKey()); + } + if (material == null) yield null; + yield new PlayerStatisticIncrementEvent( + player, + statistic, + statEvent.getInitialValue(), + statEvent.getNewValue(), + material + ); + } + yield new PlayerStatisticIncrementEvent( + player, + statistic, + statEvent.getInitialValue(), + statEvent.getNewValue() + ); + } + case PLAYER_VELOCITY -> { + patchbukkit.events.PlayerVelocityEvent velocityEvent = event.getPlayerVelocity(); + Player player = getPlayer(velocityEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + Vector velocity = new Vector(); + if (velocityEvent.getVelocity() != null) { + velocity = new Vector( + velocityEvent.getVelocity().getX(), + velocityEvent.getVelocity().getY(), + velocityEvent.getVelocity().getZ() + ); + } + yield new PlayerVelocityEvent(player, velocity); + } case PLAYER_INTERACT -> { patchbukkit.events.PlayerInteractEvent interactEvent = event.getPlayerInteract(); Player player = getPlayer(interactEvent.getPlayerUuid().getValue()); @@ -1325,6 +1506,166 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .setRespawnReason(reason) .build() ); + } else if (event instanceof PlayerPickupArrowEvent pickupEvent) { + var item = pickupEvent.getItem(); + String itemKey = "minecraft:air"; + int itemAmount = 0; + if (item != null && item.getItemStack() != null) { + itemKey = item.getItemStack().getType().getKey().toString(); + itemAmount = item.getItemStack().getAmount(); + } + eventBuilder.setPlayerPickupArrow( + patchbukkit.events.PlayerPickupArrowEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(pickupEvent.getPlayer().getUniqueId().toString()) + .build()) + .setArrowUuid(UUID.newBuilder() + .setValue(pickupEvent.getArrow().getUniqueId().toString()) + .build()) + .setItemUuid(UUID.newBuilder() + .setValue(item != null ? item.getUniqueId().toString() : java.util.UUID.randomUUID().toString()) + .build()) + .setItemKey(itemKey) + .setItemAmount(itemAmount) + .setRemaining(pickupEvent.getRemaining()) + .build() + ); + } else if (event instanceof PlayerPortalEvent portalEvent) { + String cause = portalEvent.getCause() != null ? portalEvent.getCause().name() : ""; + int searchRadius = 0; + boolean canCreatePortal = false; + int creationRadius = 0; + try { + var method = PlayerPortalEvent.class.getMethod("getSearchRadius"); + Object value = method.invoke(portalEvent); + if (value instanceof Integer i) { + searchRadius = i; + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + var method = PlayerPortalEvent.class.getMethod("getCanCreatePortal"); + Object value = method.invoke(portalEvent); + if (value instanceof Boolean b) { + canCreatePortal = b; + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + var method = PlayerPortalEvent.class.getMethod("getCreationRadius"); + Object value = method.invoke(portalEvent); + if (value instanceof Integer i) { + creationRadius = i; + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + eventBuilder.setPlayerPortal( + patchbukkit.events.PlayerPortalEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(portalEvent.getPlayer().getUniqueId().toString()) + .build()) + .setFrom(BridgeUtils.convertLocation(portalEvent.getFrom())) + .setTo(BridgeUtils.convertLocation(portalEvent.getTo())) + .setCause(cause) + .setSearchRadius(searchRadius) + .setCanCreatePortal(canCreatePortal) + .setCreationRadius(creationRadius) + .build() + ); + } else if (event instanceof PlayerRecipeDiscoverEvent recipeEvent) { + String key = recipeEvent.getRecipe() != null + ? recipeEvent.getRecipe().toString() + : ""; + eventBuilder.setPlayerRecipeDiscover( + patchbukkit.events.PlayerRecipeDiscoverEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(recipeEvent.getPlayer().getUniqueId().toString()) + .build()) + .setRecipeKey(key) + .build() + ); + } else if (event instanceof PlayerRiptideEvent riptideEvent) { + ItemStack item = riptideEvent.getItem(); + String itemKey = item != null ? item.getType().getKey().toString() : "minecraft:air"; + int itemAmount = item != null ? item.getAmount() : 0; + Vector velocity = riptideEvent.getVelocity(); + patchbukkit.common.Vec3 vec = patchbukkit.common.Vec3.newBuilder() + .setX(velocity.getX()) + .setY(velocity.getY()) + .setZ(velocity.getZ()) + .build(); + eventBuilder.setPlayerRiptide( + patchbukkit.events.PlayerRiptideEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(riptideEvent.getPlayer().getUniqueId().toString()) + .build()) + .setItemKey(itemKey) + .setItemAmount(itemAmount) + .setVelocity(vec) + .build() + ); + } else if (event instanceof PlayerShearEntityEvent shearEvent) { + ItemStack item = shearEvent.getItem(); + String itemKey = item != null ? item.getType().getKey().toString() : "minecraft:air"; + int itemAmount = item != null ? item.getAmount() : 0; + String hand = shearEvent.getHand() != null ? shearEvent.getHand().name() : "HAND"; + eventBuilder.setPlayerShearEntity( + patchbukkit.events.PlayerShearEntityEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(shearEvent.getPlayer().getUniqueId().toString()) + .build()) + .setEntityUuid(UUID.newBuilder() + .setValue(shearEvent.getEntity().getUniqueId().toString()) + .build()) + .setEntityType(shearEvent.getEntity().getType().name()) + .setItemKey(itemKey) + .setItemAmount(itemAmount) + .setHand(hand) + .build() + ); + } else if (event instanceof PlayerSpawnLocationEvent spawnEvent) { + eventBuilder.setPlayerSpawnLocation( + patchbukkit.events.PlayerSpawnLocationEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(spawnEvent.getPlayer().getUniqueId().toString()) + .build()) + .setSpawnLocation(BridgeUtils.convertLocation(spawnEvent.getSpawnLocation())) + .build() + ); + } else if (event instanceof PlayerStatisticIncrementEvent statEvent) { + String statistic = statEvent.getStatistic().name(); + String entityType = statEvent.getEntityType() != null ? statEvent.getEntityType().name() : ""; + String materialKey = statEvent.getMaterial() != null ? statEvent.getMaterial().getKey().toString() : ""; + eventBuilder.setPlayerStatisticIncrement( + patchbukkit.events.PlayerStatisticIncrementEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(statEvent.getPlayer().getUniqueId().toString()) + .build()) + .setStatistic(statistic) + .setInitialValue(statEvent.getPreviousValue()) + .setNewValue(statEvent.getNewValue()) + .setEntityType(entityType) + .setMaterialKey(materialKey) + .build() + ); + } else if (event instanceof PlayerVelocityEvent velocityEvent) { + Vector velocity = velocityEvent.getVelocity(); + patchbukkit.common.Vec3 vec = patchbukkit.common.Vec3.newBuilder() + .setX(velocity.getX()) + .setY(velocity.getY()) + .setZ(velocity.getZ()) + .build(); + eventBuilder.setPlayerVelocity( + patchbukkit.events.PlayerVelocityEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(velocityEvent.getPlayer().getUniqueId().toString()) + .build()) + .setVelocity(vec) + .build() + ); } else if (event instanceof AsyncPlayerChatEvent chatEvent) { var playerEventBuilder = patchbukkit.events.PlayerChatEvent.newBuilder() .setPlayerUuid(UUID.newBuilder() 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 625f1a9..96f158e 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,8 @@ import org.bukkit.plugin.IllegalPluginAccessException; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.RegisteredListener; +import org.bukkit.inventory.ItemStack; +import org.bukkit.util.Vector; import org.patchbukkit.bridge.BridgeUtils; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; @@ -729,6 +731,173 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.player.PlayerPickupArrowEvent": + var pickupEvent = (org.bukkit.event.player.PlayerPickupArrowEvent) event; + var item = pickupEvent.getItem(); + String itemKey = "minecraft:air"; + int itemAmount = 0; + if (item != null && item.getItemStack() != null) { + itemKey = item.getItemStack().getType().getKey().toString(); + itemAmount = item.getItemStack().getAmount(); + } + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerPickupArrow( + patchbukkit.events.PlayerPickupArrowEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(pickupEvent.getPlayer().getUniqueId())) + .setArrowUuid(BridgeUtils.convertUuid(pickupEvent.getArrow().getUniqueId())) + .setItemUuid(BridgeUtils.convertUuid(item != null ? item.getUniqueId() : java.util.UUID.randomUUID())) + .setItemKey(itemKey) + .setItemAmount(itemAmount) + .setRemaining(pickupEvent.getRemaining()) + .build() + ).build() + ); + break; + case "org.bukkit.event.player.PlayerPortalEvent": + var portalEvent = (org.bukkit.event.player.PlayerPortalEvent) event; + String portalCause = portalEvent.getCause() != null ? portalEvent.getCause().name() : ""; + int searchRadius = 0; + boolean canCreatePortal = false; + int creationRadius = 0; + try { + var method = org.bukkit.event.player.PlayerPortalEvent.class.getMethod("getSearchRadius"); + Object value = method.invoke(portalEvent); + if (value instanceof Integer i) { + searchRadius = i; + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + var method = org.bukkit.event.player.PlayerPortalEvent.class.getMethod("getCanCreatePortal"); + Object value = method.invoke(portalEvent); + if (value instanceof Boolean b) { + canCreatePortal = b; + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + var method = org.bukkit.event.player.PlayerPortalEvent.class.getMethod("getCreationRadius"); + Object value = method.invoke(portalEvent); + if (value instanceof Integer i) { + creationRadius = i; + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerPortal( + patchbukkit.events.PlayerPortalEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(portalEvent.getPlayer().getUniqueId())) + .setFrom(BridgeUtils.convertLocation(portalEvent.getFrom())) + .setTo(BridgeUtils.convertLocation(portalEvent.getTo())) + .setCause(portalCause) + .setSearchRadius(searchRadius) + .setCanCreatePortal(canCreatePortal) + .setCreationRadius(creationRadius) + .build() + ).build() + ); + break; + case "org.bukkit.event.player.PlayerRecipeDiscoverEvent": + var recipeEvent = (org.bukkit.event.player.PlayerRecipeDiscoverEvent) event; + String recipeKey = recipeEvent.getRecipe() != null + ? recipeEvent.getRecipe().toString() + : ""; + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerRecipeDiscover( + patchbukkit.events.PlayerRecipeDiscoverEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(recipeEvent.getPlayer().getUniqueId())) + .setRecipeKey(recipeKey) + .build() + ).build() + ); + break; + case "org.bukkit.event.player.PlayerRiptideEvent": + var riptideEvent = (org.bukkit.event.player.PlayerRiptideEvent) event; + var riptideItem = riptideEvent.getItem(); + String riptideKey = riptideItem != null ? riptideItem.getType().getKey().toString() : "minecraft:air"; + int riptideAmount = riptideItem != null ? riptideItem.getAmount() : 0; + Vector riptideVelocity = riptideEvent.getVelocity(); + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerRiptide( + patchbukkit.events.PlayerRiptideEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(riptideEvent.getPlayer().getUniqueId())) + .setItemKey(riptideKey) + .setItemAmount(riptideAmount) + .setVelocity(patchbukkit.common.Vec3.newBuilder() + .setX(riptideVelocity.getX()) + .setY(riptideVelocity.getY()) + .setZ(riptideVelocity.getZ()) + .build()) + .build() + ).build() + ); + break; + case "org.bukkit.event.player.PlayerShearEntityEvent": + var shearEvent = (org.bukkit.event.player.PlayerShearEntityEvent) event; + ItemStack shearItem = shearEvent.getItem(); + String shearKey = shearItem != null ? shearItem.getType().getKey().toString() : "minecraft:air"; + int shearAmount = shearItem != null ? shearItem.getAmount() : 0; + String shearHand = shearEvent.getHand() != null ? shearEvent.getHand().name() : "HAND"; + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerShearEntity( + patchbukkit.events.PlayerShearEntityEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(shearEvent.getPlayer().getUniqueId())) + .setEntityUuid(BridgeUtils.convertUuid(shearEvent.getEntity().getUniqueId())) + .setEntityType(shearEvent.getEntity().getType().name()) + .setItemKey(shearKey) + .setItemAmount(shearAmount) + .setHand(shearHand) + .build() + ).build() + ); + break; + case "org.spigotmc.event.player.PlayerSpawnLocationEvent": + var spawnEvent = (org.spigotmc.event.player.PlayerSpawnLocationEvent) event; + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerSpawnLocation( + patchbukkit.events.PlayerSpawnLocationEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(spawnEvent.getPlayer().getUniqueId())) + .setSpawnLocation(BridgeUtils.convertLocation(spawnEvent.getSpawnLocation())) + .build() + ).build() + ); + break; + case "org.bukkit.event.player.PlayerStatisticIncrementEvent": + var statEvent = (org.bukkit.event.player.PlayerStatisticIncrementEvent) event; + String statEntityType = statEvent.getEntityType() != null ? statEvent.getEntityType().name() : ""; + String statMaterial = statEvent.getMaterial() != null ? statEvent.getMaterial().getKey().toString() : ""; + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerStatisticIncrement( + patchbukkit.events.PlayerStatisticIncrementEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(statEvent.getPlayer().getUniqueId())) + .setStatistic(statEvent.getStatistic().name()) + .setInitialValue(statEvent.getPreviousValue()) + .setNewValue(statEvent.getNewValue()) + .setEntityType(statEntityType) + .setMaterialKey(statMaterial) + .build() + ).build() + ); + break; + case "org.bukkit.event.player.PlayerVelocityEvent": + var velocityEvent = (org.bukkit.event.player.PlayerVelocityEvent) event; + Vector velocity = velocityEvent.getVelocity(); + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerVelocity( + patchbukkit.events.PlayerVelocityEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(velocityEvent.getPlayer().getUniqueId())) + .setVelocity(patchbukkit.common.Vec3.newBuilder() + .setX(velocity.getX()) + .setY(velocity.getY()) + .setZ(velocity.getZ()) + .build()) + .build() + ).build() + ); + break; case "org.bukkit.event.player.PlayerInteractEvent": var interactEvent = (org.bukkit.event.player.PlayerInteractEvent) event; var clicked = interactEvent.getClickedBlock(); diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index 594c82f..dfc5a21 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -63,6 +63,14 @@ message Event { PlayerSwapHandItemsEvent player_swap_hand_items = 48; PlayerResourcePackStatusEvent player_resource_pack_status = 49; PlayerRespawnEvent player_respawn = 50; + PlayerPickupArrowEvent player_pickup_arrow = 51; + PlayerPortalEvent player_portal = 52; + PlayerRecipeDiscoverEvent player_recipe_discover = 53; + PlayerRiptideEvent player_riptide = 54; + PlayerShearEntityEvent player_shear_entity = 55; + PlayerSpawnLocationEvent player_spawn_location = 56; + PlayerStatisticIncrementEvent player_statistic_increment = 57; + PlayerVelocityEvent player_velocity = 58; } } diff --git a/proto/patchbukkit/events/player_events.proto b/proto/patchbukkit/events/player_events.proto index 2391ec6..30b6bde 100644 --- a/proto/patchbukkit/events/player_events.proto +++ b/proto/patchbukkit/events/player_events.proto @@ -205,6 +205,65 @@ message PlayerRespawnEvent { string respawn_reason = 6; } +message PlayerPickupArrowEvent { + patchbukkit.common.UUID player_uuid = 1; + patchbukkit.common.UUID arrow_uuid = 2; + patchbukkit.common.UUID item_uuid = 3; + string item_key = 4; + int32 item_amount = 5; + int32 remaining = 6; +} + +message PlayerPortalEvent { + patchbukkit.common.UUID player_uuid = 1; + patchbukkit.common.Location from = 2; + patchbukkit.common.Location to = 3; + string cause = 4; + int32 search_radius = 5; + bool can_create_portal = 6; + int32 creation_radius = 7; +} + +message PlayerRecipeDiscoverEvent { + patchbukkit.common.UUID player_uuid = 1; + string recipe_key = 2; +} + +message PlayerRiptideEvent { + patchbukkit.common.UUID player_uuid = 1; + string item_key = 2; + int32 item_amount = 3; + patchbukkit.common.Vec3 velocity = 4; +} + +message PlayerShearEntityEvent { + patchbukkit.common.UUID player_uuid = 1; + patchbukkit.common.UUID entity_uuid = 2; + string entity_type = 3; + string item_key = 4; + int32 item_amount = 5; + string hand = 6; +} + +message PlayerSpawnLocationEvent { + patchbukkit.common.UUID player_uuid = 1; + patchbukkit.common.Location spawn_location = 2; +} + +message PlayerStatisticIncrementEvent { + patchbukkit.common.UUID player_uuid = 1; + string statistic = 2; + int32 initial_value = 3; + int32 new_value = 4; + string entity_type = 5; + string material_key = 6; +} + +message PlayerVelocityEvent { + patchbukkit.common.UUID player_uuid = 1; + patchbukkit.common.Vec3 velocity = 2; +} + message AsyncPlayerPreLoginEvent { string name = 1; patchbukkit.common.UUID player_uuid = 2; diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index 14d97f2..2d83eb1 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -35,6 +35,9 @@ use crate::proto::patchbukkit::events::{ PlayerLevelChangeEvent, PlayerKickEvent, PlayerToggleSneakEvent, PlayerToggleSprintEvent, PlayerToggleFlightEvent, PlayerSwapHandItemsEvent, PlayerResourcePackStatusEvent, PlayerRespawnEvent, + PlayerPickupArrowEvent, PlayerPortalEvent, PlayerRecipeDiscoverEvent, PlayerRiptideEvent, + PlayerShearEntityEvent, PlayerSpawnLocationEvent, PlayerStatisticIncrementEvent, + PlayerVelocityEvent, }; pub struct EventContext { @@ -1764,6 +1767,399 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_respawn::PlayerRespawn } } +impl PatchBukkitEvent for pumpkin::plugin::player::player_pickup_arrow::PlayerPickupArrowEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerPickupArrow(PlayerPickupArrowEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + arrow_uuid: Some(Uuid { + value: self.arrow_uuid.to_string(), + }), + item_uuid: Some(Uuid { + value: self.item_uuid.to_string(), + }), + item_key: item_to_key(self.item_stack.item), + item_amount: self.item_stack.item_count as i32, + remaining: self.remaining, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerPickupArrow(event) => { + if let Some(uuid) = event.arrow_uuid { + if let Ok(arrow_uuid) = uuid::Uuid::from_str(&uuid.value) { + self.arrow_uuid = arrow_uuid; + } + } + if let Some(uuid) = event.item_uuid { + if let Ok(item_uuid) = uuid::Uuid::from_str(&uuid.value) { + self.item_uuid = item_uuid; + } + } + if !event.item_key.is_empty() || event.item_amount > 0 { + let key = if event.item_key.is_empty() { + item_to_key(self.item_stack.item) + } else { + event.item_key + }; + let count = if event.item_amount > 0 { + event.item_amount as u8 + } else { + self.item_stack.item_count + }; + self.item_stack = item_stack_from_key(&key, count); + } + self.remaining = event.remaining; + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_portal::PlayerPortalEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let yaw = self.player.living_entity.entity.yaw.load(); + let pitch = self.player.living_entity.entity.pitch.load(); + JvmEventPayload { + event: Event { + data: Some(Data::PlayerPortal(PlayerPortalEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + from: Some(build_location( + self.from_world_uuid, + &self.from_position, + yaw, + pitch, + )), + to: Some(build_location( + self.to_world_uuid, + &self.to_position, + yaw, + pitch, + )), + cause: self.cause.clone(), + search_radius: self.search_radius, + can_create_portal: self.can_create_portal, + creation_radius: self.creation_radius, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerPortal(event) => { + if let Some(from) = event.from { + if let Some(pos) = location_to_vec3(from.clone()) { + self.from_position = pos; + } + if let Some(world) = from.world.and_then(|w| w.uuid) { + if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { + self.from_world_uuid = uuid; + } + } + } + if let Some(to) = event.to { + if let Some(pos) = location_to_vec3(to.clone()) { + self.to_position = pos; + } + if let Some(world) = to.world.and_then(|w| w.uuid) { + if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { + self.to_world_uuid = uuid; + } + } + } + if !event.cause.is_empty() { + self.cause = event.cause; + } + self.search_radius = event.search_radius; + self.can_create_portal = event.can_create_portal; + self.creation_radius = event.creation_radius; + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_recipe_discover::PlayerRecipeDiscoverEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerRecipeDiscover(PlayerRecipeDiscoverEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + recipe_key: self.recipe_key.clone(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerRecipeDiscover(event) => { + if !event.recipe_key.is_empty() { + self.recipe_key = event.recipe_key; + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_riptide::PlayerRiptideEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerRiptide(PlayerRiptideEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + item_key: item_to_key(self.item_stack.item), + item_amount: self.item_stack.item_count as i32, + velocity: Some(Vec3 { + x: self.velocity.x, + y: self.velocity.y, + z: self.velocity.z, + }), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerRiptide(event) => { + if !event.item_key.is_empty() || event.item_amount > 0 { + let key = if event.item_key.is_empty() { + item_to_key(self.item_stack.item) + } else { + event.item_key + }; + let count = if event.item_amount > 0 { + event.item_amount as u8 + } else { + self.item_stack.item_count + }; + self.item_stack = item_stack_from_key(&key, count); + } + if let Some(velocity) = event.velocity { + self.velocity = Vector3::new(velocity.x, velocity.y, velocity.z); + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_shear_entity::PlayerShearEntityEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerShearEntity(PlayerShearEntityEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + entity_uuid: Some(Uuid { + value: self.entity_uuid.to_string(), + }), + entity_type: self.entity_type.clone(), + item_key: item_to_key(self.item_stack.item), + item_amount: self.item_stack.item_count as i32, + hand: self.hand.clone(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerShearEntity(event) => { + if let Some(uuid) = event.entity_uuid { + if let Ok(entity_uuid) = uuid::Uuid::from_str(&uuid.value) { + self.entity_uuid = entity_uuid; + } + } + if !event.entity_type.is_empty() { + self.entity_type = event.entity_type; + } + if !event.item_key.is_empty() || event.item_amount > 0 { + let key = if event.item_key.is_empty() { + item_to_key(self.item_stack.item) + } else { + event.item_key + }; + let count = if event.item_amount > 0 { + event.item_amount as u8 + } else { + self.item_stack.item_count + }; + self.item_stack = item_stack_from_key(&key, count); + } + if !event.hand.is_empty() { + self.hand = event.hand; + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_spawn_location::PlayerSpawnLocationEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let yaw = self.player.living_entity.entity.yaw.load(); + let pitch = self.player.living_entity.entity.pitch.load(); + JvmEventPayload { + event: Event { + data: Some(Data::PlayerSpawnLocation(PlayerSpawnLocationEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + spawn_location: Some(build_location( + self.world_uuid, + &self.spawn_position, + yaw, + pitch, + )), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerSpawnLocation(event) => { + if let Some(loc) = event.spawn_location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.spawn_position = pos; + } + if let Some(world) = loc.world.and_then(|w| w.uuid) { + if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { + self.world_uuid = uuid; + } + } + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_statistic_increment::PlayerStatisticIncrementEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerStatisticIncrement(PlayerStatisticIncrementEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + statistic: self.statistic.clone(), + initial_value: self.initial_value, + new_value: self.new_value, + entity_type: self.entity_type.clone(), + material_key: self.material_key.clone(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerStatisticIncrement(event) => { + if !event.statistic.is_empty() { + self.statistic = event.statistic; + } + self.initial_value = event.initial_value; + self.new_value = event.new_value; + if !event.entity_type.is_empty() { + self.entity_type = event.entity_type; + } + if !event.material_key.is_empty() { + self.material_key = event.material_key; + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_velocity::PlayerVelocityEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerVelocity(PlayerVelocityEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + velocity: Some(Vec3 { + x: self.velocity.x, + y: self.velocity.y, + z: self.velocity.z, + }), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerVelocity(event) => { + if let Some(velocity) = event.velocity { + self.velocity = Vector3::new(velocity.x, velocity.y, velocity.z); + } + } + _ => {} + } + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::player::player_interact_event::PlayerInteractEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { let world_uuid = self.player.world().uuid; diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index 0219bd9..2cca0d6 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -26,6 +26,14 @@ use pumpkin::plugin::player::player_toggle_flight::PlayerToggleFlightEvent; use pumpkin::plugin::player::player_swap_hand_items::PlayerSwapHandItemsEvent; use pumpkin::plugin::player::player_resource_pack_status::PlayerResourcePackStatusEvent; use pumpkin::plugin::player::player_respawn::PlayerRespawnEvent; +use pumpkin::plugin::player::player_pickup_arrow::PlayerPickupArrowEvent; +use pumpkin::plugin::player::player_portal::PlayerPortalEvent; +use pumpkin::plugin::player::player_recipe_discover::PlayerRecipeDiscoverEvent; +use pumpkin::plugin::player::player_riptide::PlayerRiptideEvent; +use pumpkin::plugin::player::player_shear_entity::PlayerShearEntityEvent; +use pumpkin::plugin::player::player_spawn_location::PlayerSpawnLocationEvent; +use pumpkin::plugin::player::player_statistic_increment::PlayerStatisticIncrementEvent; +use pumpkin::plugin::player::player_velocity::PlayerVelocityEvent; use pumpkin::plugin::player::player_interact_event::{InteractAction, PlayerInteractEvent}; use pumpkin::plugin::player::player_join::PlayerJoinEvent; use pumpkin::plugin::player::player_login::PlayerLoginEvent; @@ -789,6 +797,142 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.player.PlayerPickupArrowEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_pickup_arrow::PlayerPickupArrowEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_pickup_arrow::PlayerPickupArrowEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerPortalEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_portal::PlayerPortalEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_portal::PlayerPortalEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerRecipeDiscoverEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_recipe_discover::PlayerRecipeDiscoverEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_recipe_discover::PlayerRecipeDiscoverEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerRiptideEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_riptide::PlayerRiptideEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_riptide::PlayerRiptideEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerShearEntityEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_shear_entity::PlayerShearEntityEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_shear_entity::PlayerShearEntityEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.spigotmc.event.player.PlayerSpawnLocationEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_spawn_location::PlayerSpawnLocationEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_spawn_location::PlayerSpawnLocationEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerStatisticIncrementEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_statistic_increment::PlayerStatisticIncrementEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_statistic_increment::PlayerStatisticIncrementEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerVelocityEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_velocity::PlayerVelocityEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_velocity::PlayerVelocityEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.player.PlayerInteractEvent" => { context .register_event::< @@ -1610,6 +1754,184 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let uuid = + uuid::Uuid::parse_str(&player_pickup_arrow_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let arrow_uuid = player_pickup_arrow_event_data + .arrow_uuid + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) + .unwrap_or_else(uuid::Uuid::new_v4); + let item_uuid = player_pickup_arrow_event_data + .item_uuid + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) + .unwrap_or_else(uuid::Uuid::new_v4); + let key = if player_pickup_arrow_event_data.item_key.is_empty() { + "minecraft:air" + } else { + player_pickup_arrow_event_data.item_key.as_str() + }; + let item = item_stack_from_key(key, player_pickup_arrow_event_data.item_amount); + let pumpkin_event = PlayerPickupArrowEvent::new( + player, + arrow_uuid, + item_uuid, + item, + player_pickup_arrow_event_data.remaining, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerPortal(player_portal_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_portal_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let (from_world_uuid, from_pos) = if let Some(loc) = player_portal_event_data.from { + let world_uuid = loc + .world + .and_then(|w| w.uuid) + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) + .unwrap_or_else(|| player.world().uuid); + let pos = location_to_vec3(loc).unwrap_or_else(|| player.position()); + (world_uuid, pos) + } else { + (player.world().uuid, player.position()) + }; + let (to_world_uuid, to_pos) = if let Some(loc) = player_portal_event_data.to { + let world_uuid = loc + .world + .and_then(|w| w.uuid) + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) + .unwrap_or_else(|| player.world().uuid); + let pos = location_to_vec3(loc).unwrap_or_else(|| player.position()); + (world_uuid, pos) + } else { + (player.world().uuid, player.position()) + }; + let cause = if player_portal_event_data.cause.is_empty() { + "UNKNOWN".to_string() + } else { + player_portal_event_data.cause + }; + let pumpkin_event = PlayerPortalEvent::new( + player, + from_pos, + from_world_uuid, + to_pos, + to_world_uuid, + cause, + player_portal_event_data.search_radius, + player_portal_event_data.can_create_portal, + player_portal_event_data.creation_radius, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerRecipeDiscover(player_recipe_discover_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_recipe_discover_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let pumpkin_event = PlayerRecipeDiscoverEvent::new( + player, + player_recipe_discover_event_data.recipe_key, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerRiptide(player_riptide_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_riptide_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let key = if player_riptide_event_data.item_key.is_empty() { + "minecraft:air" + } else { + player_riptide_event_data.item_key.as_str() + }; + let item = item_stack_from_key(key, player_riptide_event_data.item_amount); + let velocity = player_riptide_event_data + .velocity + .map(|v| Vector3::new(v.x, v.y, v.z)) + .unwrap_or_else(Vector3::default); + let pumpkin_event = PlayerRiptideEvent::new(player, item, velocity); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerShearEntity(player_shear_entity_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_shear_entity_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let entity_uuid = player_shear_entity_event_data + .entity_uuid + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) + .unwrap_or_else(uuid::Uuid::new_v4); + let key = if player_shear_entity_event_data.item_key.is_empty() { + "minecraft:air" + } else { + player_shear_entity_event_data.item_key.as_str() + }; + let item = item_stack_from_key(key, player_shear_entity_event_data.item_amount); + let hand = if player_shear_entity_event_data.hand.is_empty() { + "HAND".to_string() + } else { + player_shear_entity_event_data.hand + }; + let entity_type = player_shear_entity_event_data.entity_type; + let pumpkin_event = PlayerShearEntityEvent::new( + player, + entity_uuid, + entity_type, + item, + hand, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerSpawnLocation(player_spawn_location_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_spawn_location_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let (world_uuid, pos) = if let Some(loc) = player_spawn_location_event_data.spawn_location { + let world_uuid = loc + .world + .and_then(|w| w.uuid) + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) + .unwrap_or_else(|| player.world().uuid); + let pos = location_to_vec3(loc).unwrap_or_else(|| player.position()); + (world_uuid, pos) + } else { + (player.world().uuid, player.position()) + }; + let pumpkin_event = PlayerSpawnLocationEvent::new(player, pos, world_uuid); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerStatisticIncrement(player_statistic_increment_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_statistic_increment_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let pumpkin_event = PlayerStatisticIncrementEvent::new( + player, + player_statistic_increment_event_data.statistic, + player_statistic_increment_event_data.initial_value, + player_statistic_increment_event_data.new_value, + player_statistic_increment_event_data.entity_type, + player_statistic_increment_event_data.material_key, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerVelocity(player_velocity_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_velocity_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let velocity = player_velocity_event_data + .velocity + .map(|v| Vector3::new(v.x, v.y, v.z)) + .unwrap_or_else(Vector3::default); + let pumpkin_event = PlayerVelocityEvent::new(player, velocity); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } Data::PlayerInteract(player_interact_event_data) => { let uuid = uuid::Uuid::parse_str(&player_interact_event_data.player_uuid?.value).ok()?; From bfdf350e6a0589ed6977ca4078986fbca2f44ebd Mon Sep 17 00:00:00 2001 From: yunuservices Date: Thu, 5 Feb 2026 01:31:49 +0300 Subject: [PATCH 27/56] Add player harvest block event --- .../events/PatchBukkitEventFactory.java | 124 ++++++++++++++++++ .../events/PatchBukkitEventManager.java | 64 +++++++++ proto/patchbukkit/events/event.proto | 1 + proto/patchbukkit/events/player_events.proto | 8 ++ rust/src/events/handler.rs | 76 ++++++++++- rust/src/java/native_callbacks/events.rs | 62 +++++++++ 6 files changed, 334 insertions(+), 1 deletion(-) diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index d74ae9a..07664cc 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -58,6 +58,7 @@ import org.bukkit.event.player.PlayerStatisticIncrementEvent; import org.bukkit.event.player.PlayerVelocityEvent; import org.spigotmc.event.player.PlayerSpawnLocationEvent; +import org.bukkit.event.player.PlayerHarvestBlockEvent; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.server.BroadcastMessageEvent; @@ -933,6 +934,28 @@ yield new PlayerStatisticIncrementEvent( } yield new PlayerVelocityEvent(player, velocity); } + case PLAYER_HARVEST_BLOCK -> { + patchbukkit.events.PlayerHarvestBlockEvent harvestEvent = event.getPlayerHarvestBlock(); + Player player = getPlayer(harvestEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + Location location = BridgeUtils.convertLocation(harvestEvent.getBlockLocation()); + if (location == null || !(location.getWorld() instanceof PatchBukkitWorld world)) { + yield null; + } + Block block = PatchBukkitBlock.create( + world, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ(), + harvestEvent.getBlockKey() + ); + ItemStack tool = materialToItem(harvestEvent.getItemKey(), harvestEvent.getItemAmount()); + org.bukkit.event.Event constructed = createHarvestBlockEvent(player, block, tool); + if (constructed instanceof PlayerHarvestBlockEvent harvest) { + yield harvest; + } + yield null; + } case PLAYER_INTERACT -> { patchbukkit.events.PlayerInteractEvent interactEvent = event.getPlayerInteract(); Player player = getPlayer(interactEvent.getPlayerUuid().getValue()); @@ -1666,6 +1689,26 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .setVelocity(vec) .build() ); + } else if (event instanceof PlayerHarvestBlockEvent harvestEvent) { + Block harvestedBlock = resolveHarvestedBlock(harvestEvent); + ItemStack tool = resolveHarvestTool(harvestEvent); + Location location = harvestedBlock != null ? harvestedBlock.getLocation() : null; + String blockKey = harvestedBlock != null + ? harvestedBlock.getType().getKey().toString() + : "minecraft:air"; + String itemKey = tool != null ? tool.getType().getKey().toString() : "minecraft:air"; + int itemAmount = tool != null ? tool.getAmount() : 0; + eventBuilder.setPlayerHarvestBlock( + patchbukkit.events.PlayerHarvestBlockEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(harvestEvent.getPlayer().getUniqueId().toString()) + .build()) + .setBlockLocation(BridgeUtils.convertLocation(location)) + .setBlockKey(blockKey) + .setItemKey(itemKey) + .setItemAmount(itemAmount) + .build() + ); } else if (event instanceof AsyncPlayerChatEvent chatEvent) { var playerEventBuilder = patchbukkit.events.PlayerChatEvent.newBuilder() .setPlayerUuid(UUID.newBuilder() @@ -1985,6 +2028,87 @@ static java.util.UUID resolveResourcePackId(@NotNull PlayerResourcePackStatusEve return packUuid != null ? packUuid : java.util.UUID.randomUUID(); } + @Nullable + private static Block resolveHarvestedBlock(@NotNull PlayerHarvestBlockEvent event) { + try { + java.lang.reflect.Method method = event.getClass().getMethod("getHarvestedBlock"); + Object value = method.invoke(event); + if (value instanceof Block block) { + return block; + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + java.lang.reflect.Method method = event.getClass().getMethod("getBlock"); + Object value = method.invoke(event); + if (value instanceof Block block) { + return block; + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + return null; + } + + @Nullable + private static ItemStack resolveHarvestTool(@NotNull PlayerHarvestBlockEvent event) { + try { + java.lang.reflect.Method method = event.getClass().getMethod("getHarvestingTool"); + Object value = method.invoke(event); + if (value instanceof ItemStack stack) { + return stack; + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + java.lang.reflect.Method method = event.getClass().getMethod("getTool"); + Object value = method.invoke(event); + if (value instanceof ItemStack stack) { + return stack; + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + return null; + } + + @Nullable + private static org.bukkit.event.Event createHarvestBlockEvent( + @NotNull Player player, + @NotNull Block block, + @NotNull ItemStack tool + ) { + try { + java.lang.reflect.Constructor ctor = PlayerHarvestBlockEvent.class.getConstructor( + Player.class, + Block.class, + ItemStack.class, + java.util.List.class + ); + return (org.bukkit.event.Event) ctor.newInstance( + player, + block, + tool, + java.util.Collections.emptyList() + ); + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + java.lang.reflect.Constructor ctor = PlayerHarvestBlockEvent.class.getConstructor( + Player.class, + Block.class, + ItemStack.class + ); + return (org.bukkit.event.Event) ctor.newInstance(player, block, tool); + } catch (ReflectiveOperationException ignored) { + // ignore + } + return null; + } + @Nullable private static PlayerLoginEvent createLoginEvent(@NotNull Player player) { try { 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 96f158e..7330511 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -898,6 +898,70 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.player.PlayerHarvestBlockEvent": + var harvestEvent = (org.bukkit.event.player.PlayerHarvestBlockEvent) event; + Block harvestedBlock = null; + ItemStack harvestTool = null; + try { + var method = harvestEvent.getClass().getMethod("getHarvestedBlock"); + Object value = method.invoke(harvestEvent); + if (value instanceof Block block) { + harvestedBlock = block; + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + if (harvestedBlock == null) { + try { + var method = harvestEvent.getClass().getMethod("getBlock"); + Object value = method.invoke(harvestEvent); + if (value instanceof Block block) { + harvestedBlock = block; + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + } + try { + var method = harvestEvent.getClass().getMethod("getHarvestingTool"); + Object value = method.invoke(harvestEvent); + if (value instanceof ItemStack stack) { + harvestTool = stack; + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + if (harvestTool == null) { + try { + var method = harvestEvent.getClass().getMethod("getTool"); + Object value = method.invoke(harvestEvent); + if (value instanceof ItemStack stack) { + harvestTool = stack; + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + } + String harvestBlockKey = harvestedBlock != null + ? harvestedBlock.getType().getKey().toString() + : "minecraft:air"; + String harvestItemKey = harvestTool != null + ? harvestTool.getType().getKey().toString() + : "minecraft:air"; + int harvestItemAmount = harvestTool != null ? harvestTool.getAmount() : 0; + Location harvestLocation = harvestedBlock != null ? harvestedBlock.getLocation() : null; + request.setEvent( + patchbukkit.events.Event.newBuilder().setPlayerHarvestBlock( + patchbukkit.events.PlayerHarvestBlockEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(harvestEvent.getPlayer().getUniqueId())) + .setBlockLocation(BridgeUtils.convertLocation(harvestLocation)) + .setBlockKey(harvestBlockKey) + .setItemKey(harvestItemKey) + .setItemAmount(harvestItemAmount) + .build() + ).build() + ); + break; case "org.bukkit.event.player.PlayerInteractEvent": var interactEvent = (org.bukkit.event.player.PlayerInteractEvent) event; var clicked = interactEvent.getClickedBlock(); diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index dfc5a21..b456512 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -71,6 +71,7 @@ message Event { PlayerSpawnLocationEvent player_spawn_location = 56; PlayerStatisticIncrementEvent player_statistic_increment = 57; PlayerVelocityEvent player_velocity = 58; + PlayerHarvestBlockEvent player_harvest_block = 59; } } diff --git a/proto/patchbukkit/events/player_events.proto b/proto/patchbukkit/events/player_events.proto index 30b6bde..612f57d 100644 --- a/proto/patchbukkit/events/player_events.proto +++ b/proto/patchbukkit/events/player_events.proto @@ -264,6 +264,14 @@ message PlayerVelocityEvent { patchbukkit.common.Vec3 velocity = 2; } +message PlayerHarvestBlockEvent { + patchbukkit.common.UUID player_uuid = 1; + patchbukkit.common.Location block_location = 2; + string block_key = 3; + string item_key = 4; + int32 item_amount = 5; +} + message AsyncPlayerPreLoginEvent { string name = 1; patchbukkit.common.UUID player_uuid = 2; diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index 2d83eb1..e21c029 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -37,7 +37,7 @@ use crate::proto::patchbukkit::events::{ PlayerSwapHandItemsEvent, PlayerResourcePackStatusEvent, PlayerRespawnEvent, PlayerPickupArrowEvent, PlayerPortalEvent, PlayerRecipeDiscoverEvent, PlayerRiptideEvent, PlayerShearEntityEvent, PlayerSpawnLocationEvent, PlayerStatisticIncrementEvent, - PlayerVelocityEvent, + PlayerVelocityEvent, PlayerHarvestBlockEvent, }; pub struct EventContext { @@ -2160,6 +2160,80 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_velocity::PlayerVeloci } } +impl PatchBukkitEvent for pumpkin::plugin::player::player_harvest_block::PlayerHarvestBlockEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let yaw = self.player.living_entity.entity.yaw.load(); + let pitch = self.player.living_entity.entity.pitch.load(); + JvmEventPayload { + event: Event { + data: Some(Data::PlayerHarvestBlock(PlayerHarvestBlockEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + block_location: Some(build_location( + self.player.world().uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + yaw, + pitch, + )), + block_key: self.block_key.clone(), + item_key: item_to_key(self.item_stack.item), + item_amount: self.item_stack.item_count as i32, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerHarvestBlock(event) => { + if let Some(loc) = event.block_location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + if let Some(world) = loc.world.and_then(|w| w.uuid) { + if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { + if uuid != self.player.world().uuid { + // World changes are not supported for harvest event. + } + } + } + } + if !event.block_key.is_empty() { + self.block_key = event.block_key; + } + if !event.item_key.is_empty() || event.item_amount > 0 { + let key = if event.item_key.is_empty() { + item_to_key(self.item_stack.item) + } else { + event.item_key + }; + let count = if event.item_amount > 0 { + event.item_amount as u8 + } else { + self.item_stack.item_count + }; + self.item_stack = item_stack_from_key(&key, count); + } + } + _ => {} + } + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::player::player_interact_event::PlayerInteractEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { let world_uuid = self.player.world().uuid; diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index 2cca0d6..4ceb068 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -34,6 +34,7 @@ use pumpkin::plugin::player::player_shear_entity::PlayerShearEntityEvent; use pumpkin::plugin::player::player_spawn_location::PlayerSpawnLocationEvent; use pumpkin::plugin::player::player_statistic_increment::PlayerStatisticIncrementEvent; use pumpkin::plugin::player::player_velocity::PlayerVelocityEvent; +use pumpkin::plugin::player::player_harvest_block::PlayerHarvestBlockEvent; use pumpkin::plugin::player::player_interact_event::{InteractAction, PlayerInteractEvent}; use pumpkin::plugin::player::player_join::PlayerJoinEvent; use pumpkin::plugin::player::player_login::PlayerLoginEvent; @@ -933,6 +934,23 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.player.PlayerHarvestBlockEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_harvest_block::PlayerHarvestBlockEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_harvest_block::PlayerHarvestBlockEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.player.PlayerInteractEvent" => { context .register_event::< @@ -1932,6 +1950,50 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let uuid = + uuid::Uuid::parse_str(&player_harvest_block_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let (world_uuid, pos) = + if let Some(loc) = player_harvest_block_event_data.block_location { + let world_uuid = loc + .world + .and_then(|w| w.uuid) + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) + .unwrap_or_else(|| player.world().uuid); + let pos = location_to_vec3(loc).unwrap_or_else(|| player.position()); + (world_uuid, pos) + } else { + (player.world().uuid, player.position()) + }; + let block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + let key = if player_harvest_block_event_data.item_key.is_empty() { + "minecraft:air" + } else { + player_harvest_block_event_data.item_key.as_str() + }; + let item = item_stack_from_key( + key, + player_harvest_block_event_data.item_amount, + ); + let block_key = if player_harvest_block_event_data.block_key.is_empty() { + "minecraft:air".to_string() + } else { + player_harvest_block_event_data.block_key + }; + let pumpkin_event = PlayerHarvestBlockEvent::new( + player, + block_pos, + block_key, + item, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } Data::PlayerInteract(player_interact_event_data) => { let uuid = uuid::Uuid::parse_str(&player_interact_event_data.player_uuid?.value).ok()?; From 6545c560be2c9a6827fb786b159b5fa00147adbd Mon Sep 17 00:00:00 2001 From: yunuservices Date: Thu, 5 Feb 2026 01:48:44 +0300 Subject: [PATCH 28/56] Add block can build and burn events --- .../events/PatchBukkitEventFactory.java | 157 ++++++++++++++++++ .../events/PatchBukkitEventManager.java | 33 ++++ proto/patchbukkit/events/block_events.proto | 14 ++ proto/patchbukkit/events/event.proto | 2 + rust/src/events/handler.rs | 95 ++++++++++- rust/src/java/native_callbacks/events.rs | 119 +++++++++++++ 6 files changed, 419 insertions(+), 1 deletion(-) diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index 07664cc..6af76db 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -8,6 +8,8 @@ import org.bukkit.Location; import org.bukkit.entity.Player; import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockCanBuildEvent; +import org.bukkit.event.block.BlockBurnEvent; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.player.AsyncPlayerChatEvent; import org.bukkit.event.player.PlayerInteractEvent; @@ -1018,6 +1020,44 @@ yield new PlayerStatisticIncrementEvent( eventObj.setDropItems(breakEvent.getDrop()); yield eventObj; } + case BLOCK_CAN_BUILD -> { + patchbukkit.events.BlockCanBuildEvent canBuildEvent = event.getBlockCanBuild(); + Player player = getPlayer(canBuildEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + + Location location = BridgeUtils.convertLocation(canBuildEvent.getLocation()); + if (location == null || !(location.getWorld() instanceof PatchBukkitWorld world)) { + yield null; + } + + org.bukkit.block.Block block = PatchBukkitBlock.create( + world, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ(), + canBuildEvent.getBlockKey() + ); + org.bukkit.block.data.BlockData data = block.getBlockData(); + yield createBlockCanBuildEvent(block, data, canBuildEvent.getCanBuild()); + } + case BLOCK_BURN -> { + patchbukkit.events.BlockBurnEvent burnEvent = event.getBlockBurn(); + Location location = BridgeUtils.convertLocation(burnEvent.getLocation()); + if (location == null || !(location.getWorld() instanceof PatchBukkitWorld world)) { + yield null; + } + + org.bukkit.block.Block block = PatchBukkitBlock.create( + world, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ(), + burnEvent.getBlockKey() + ); + BlockBurnEvent eventObj = new BlockBurnEvent(block); + setIgnitingBlock(eventObj, burnEvent.getIgnitingBlockKey()); + yield eventObj; + } case BLOCK_PLACE -> { patchbukkit.events.BlockPlaceEvent placeEvent = event.getBlockPlace(); Player player = getPlayer(placeEvent.getPlayerUuid().getValue()); @@ -1904,6 +1944,34 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .setDrop(breakEvent.isDropItems()) .build() ); + } else if (event instanceof BlockCanBuildEvent canBuildEvent) { + Block block = canBuildEvent.getBlock(); + boolean canBuild = canBuildEvent.isBuildable(); + java.util.UUID playerUuid = resolveEventPlayerUuid(canBuildEvent); + eventBuilder.setBlockCanBuild( + patchbukkit.events.BlockCanBuildEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(playerUuid.toString()) + .build()) + .setBlockKey(block.getType().getKey().toString()) + .setBlockAgainstKey(block.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(block.getLocation())) + .setCanBuild(canBuild) + .build() + ); + } else if (event instanceof BlockBurnEvent burnEvent) { + Block block = burnEvent.getBlock(); + Block ignitingBlock = resolveIgnitingBlock(burnEvent); + String ignitingKey = ignitingBlock != null + ? ignitingBlock.getType().getKey().toString() + : "minecraft:fire"; + eventBuilder.setBlockBurn( + patchbukkit.events.BlockBurnEvent.newBuilder() + .setBlockKey(block.getType().getKey().toString()) + .setIgnitingBlockKey(ignitingKey) + .setLocation(BridgeUtils.convertLocation(block.getLocation())) + .build() + ); } else if (event instanceof BlockPlaceEvent placeEvent) { var block = placeEvent.getBlockPlaced(); var against = placeEvent.getBlockAgainst(); @@ -2074,6 +2142,43 @@ private static ItemStack resolveHarvestTool(@NotNull PlayerHarvestBlockEvent eve return null; } + @NotNull + static java.util.UUID resolveEventPlayerUuid(@NotNull org.bukkit.event.Event event) { + try { + java.lang.reflect.Method method = event.getClass().getMethod("getPlayer"); + Object value = method.invoke(event); + if (value instanceof Player player) { + return player.getUniqueId(); + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + java.lang.reflect.Method method = event.getClass().getMethod("getPlayerUUID"); + Object value = method.invoke(event); + if (value instanceof java.util.UUID uuid) { + return uuid; + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + return java.util.UUID.randomUUID(); + } + + @Nullable + static Block resolveIgnitingBlock(@NotNull BlockBurnEvent event) { + try { + java.lang.reflect.Method method = event.getClass().getMethod("getIgnitingBlock"); + Object value = method.invoke(event); + if (value instanceof Block block) { + return block; + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + return null; + } + @Nullable private static org.bukkit.event.Event createHarvestBlockEvent( @NotNull Player player, @@ -2109,6 +2214,58 @@ private static org.bukkit.event.Event createHarvestBlockEvent( return null; } + @Nullable + private static BlockCanBuildEvent createBlockCanBuildEvent( + @NotNull Block block, + @NotNull org.bukkit.block.data.BlockData data, + boolean canBuild + ) { + try { + java.lang.reflect.Constructor ctor = + BlockCanBuildEvent.class.getConstructor(Block.class, org.bukkit.block.data.BlockData.class, boolean.class); + return ctor.newInstance(block, data, canBuild); + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + java.lang.reflect.Constructor ctor = + BlockCanBuildEvent.class.getConstructor(Block.class, Material.class, boolean.class); + return ctor.newInstance(block, block.getType(), canBuild); + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + java.lang.reflect.Constructor ctor = + BlockCanBuildEvent.class.getConstructor(Block.class, boolean.class); + return ctor.newInstance(block, canBuild); + } catch (ReflectiveOperationException ignored) { + // ignore + } + return null; + } + + private static void setIgnitingBlock(@NotNull BlockBurnEvent event, @Nullable String ignitingKey) { + if (ignitingKey == null || ignitingKey.isEmpty()) { + return; + } + Material material = Material.matchMaterial(ignitingKey); + if (material == null) { + material = Material.matchMaterial("minecraft:" + ignitingKey); + } + if (material == null) { + return; + } + try { + java.lang.reflect.Method method = event.getClass().getMethod("setIgnitingBlock", Block.class); + Block block = event.getBlock().getWorld().getBlockAt(event.getBlock().getLocation()); + if (block != null) { + method.invoke(event, block); + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + } + @Nullable private static PlayerLoginEvent createLoginEvent(@NotNull Player player) { try { 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 7330511..33d299a 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -14,6 +14,7 @@ import org.bukkit.plugin.RegisteredListener; import org.bukkit.inventory.ItemStack; import org.bukkit.util.Vector; +import org.bukkit.block.Block; import org.patchbukkit.bridge.BridgeUtils; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; @@ -998,6 +999,38 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.block.BlockCanBuildEvent": + var canBuildEvent = (org.bukkit.event.block.BlockCanBuildEvent) event; + Block canBuildBlock = canBuildEvent.getBlock(); + request.setEvent( + patchbukkit.events.Event.newBuilder().setBlockCanBuild( + patchbukkit.events.BlockCanBuildEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(PatchBukkitEventFactory.resolveEventPlayerUuid(canBuildEvent))) + .setBlockKey(canBuildBlock.getType().getKey().toString()) + .setBlockAgainstKey(canBuildBlock.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(canBuildBlock.getLocation())) + .setCanBuild(canBuildEvent.isBuildable()) + .build() + ).build() + ); + break; + case "org.bukkit.event.block.BlockBurnEvent": + var burnEvent = (org.bukkit.event.block.BlockBurnEvent) event; + Block burnedBlock = burnEvent.getBlock(); + Block ignitingBlock = PatchBukkitEventFactory.resolveIgnitingBlock(burnEvent); + String ignitingKey = ignitingBlock != null + ? ignitingBlock.getType().getKey().toString() + : "minecraft:fire"; + request.setEvent( + patchbukkit.events.Event.newBuilder().setBlockBurn( + patchbukkit.events.BlockBurnEvent.newBuilder() + .setBlockKey(burnedBlock.getType().getKey().toString()) + .setIgnitingBlockKey(ignitingKey) + .setLocation(BridgeUtils.convertLocation(burnedBlock.getLocation())) + .build() + ).build() + ); + break; case "org.bukkit.event.block.BlockPlaceEvent": var placeEvent = (org.bukkit.event.block.BlockPlaceEvent) event; request.setEvent( diff --git a/proto/patchbukkit/events/block_events.proto b/proto/patchbukkit/events/block_events.proto index d13a724..e43ecbe 100644 --- a/proto/patchbukkit/events/block_events.proto +++ b/proto/patchbukkit/events/block_events.proto @@ -22,6 +22,20 @@ message BlockPlaceEvent { bool can_build = 5; } +message BlockCanBuildEvent { + patchbukkit.common.UUID player_uuid = 1; + string block_key = 2; + string block_against_key = 3; + patchbukkit.common.Location location = 4; + bool can_build = 5; +} + +message BlockBurnEvent { + string block_key = 1; + string igniting_block_key = 2; + patchbukkit.common.Location location = 3; +} + message PlayerInteractEvent { patchbukkit.common.UUID player_uuid = 1; string action = 2; diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index b456512..8d04c44 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -72,6 +72,8 @@ message Event { PlayerStatisticIncrementEvent player_statistic_increment = 57; PlayerVelocityEvent player_velocity = 58; PlayerHarvestBlockEvent player_harvest_block = 59; + BlockCanBuildEvent block_can_build = 60; + BlockBurnEvent block_burn = 61; } } diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index e21c029..57ea416 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -19,7 +19,7 @@ use crate::java::jvm::commands::JvmCommand; use crate::proto::patchbukkit::common::{Location, Uuid, Vec3, World}; use crate::proto::patchbukkit::events::event::Data; use crate::proto::patchbukkit::events::{ - BlockBreakEvent, BlockPlaceEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, + BlockBreakEvent, BlockPlaceEvent, BlockCanBuildEvent, BlockBurnEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, PlayerLeaveEvent, PlayerMoveEvent, PlayerInteractEvent, ServerBroadcastEvent, ServerCommandEvent, EntityDamageEvent, EntityDeathEvent, EntitySpawnEvent, PlayerLoginEvent, PlayerTeleportEvent, PlayerChangeWorldEvent, PlayerGamemodeChangeEvent, @@ -2373,6 +2373,99 @@ impl PatchBukkitEvent for pumpkin::plugin::block::block_place::BlockPlaceEvent { } } +impl PatchBukkitEvent for pumpkin::plugin::block::block_can_build::BlockCanBuildEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let player_uuid = self.player.gameprofile.id.to_string(); + let world_uuid = self.player.world().uuid; + let location = build_location( + world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockCanBuild(BlockCanBuildEvent { + player_uuid: Some(Uuid { value: player_uuid }), + block_key: block_to_key(self.block_to_build), + block_against_key: block_to_key(self.block), + location: Some(location), + can_build: self.buildable, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::BlockCanBuild(event) => { + self.buildable = event.can_build; + if let Some(loc) = event.location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + } + if !event.block_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_key) { + self.block_to_build = block; + } + } + if !event.block_against_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_against_key) { + self.block = block; + } + } + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::block::block_burn::BlockBurnEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockBurn(BlockBurnEvent { + block_key: block_to_key(self.block), + igniting_block_key: block_to_key(self.igniting_block), + location: Some(location), + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, _data: Data) -> Option<()> { + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::entity::entity_spawn::EntitySpawnEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { JvmEventPayload { diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index 4ceb068..5dfdfcb 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -3,6 +3,8 @@ use std::sync::Arc; use pumpkin::plugin::EventPriority; use pumpkin::plugin::block::block_break::BlockBreakEvent; use pumpkin::plugin::block::block_place::BlockPlaceEvent; +use pumpkin::plugin::block::block_can_build::BlockCanBuildEvent; +use pumpkin::plugin::block::block_burn::BlockBurnEvent; use pumpkin::plugin::player::player_chat::PlayerChatEvent; use pumpkin::plugin::player::player_command_preprocess::PlayerCommandPreprocessEvent; use pumpkin::plugin::player::player_command_send::PlayerCommandSendEvent; @@ -983,6 +985,36 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.block.BlockCanBuildEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_can_build::BlockCanBuildEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.BlockBurnEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_burn::BlockBurnEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.block.BlockPlaceEvent" => { context .register_event::< @@ -2070,11 +2102,23 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option Option { + let uuid = + uuid::Uuid::parse_str(&block_can_build_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let block_to_build = block_from_key(&block_can_build_event_data.block_key); + let block_against = block_from_key(&block_can_build_event_data.block_against_key); + let position = block_can_build_event_data + .location + .and_then(|loc| loc.position) + .map(|pos| { + pumpkin_util::math::position::BlockPos::new( + pos.x as i32, + pos.y as i32, + pos.z as i32, + ) + }) + .unwrap_or_else(|| player.position().to_block_pos()); + let pumpkin_event = BlockCanBuildEvent { + player, + block_to_build, + buildable: block_can_build_event_data.can_build, + block: block_against, + block_pos: position, + cancelled: false, + }; + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::BlockBurn(block_burn_event_data) => { + let block = block_from_key(&block_burn_event_data.block_key); + let igniting_block = + block_from_key(&block_burn_event_data.igniting_block_key); + let (world_uuid, pos) = if let Some(loc) = block_burn_event_data.location { + let world_uuid = loc + .world + .and_then(|w| w.uuid) + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) + .unwrap_or_else(|| { + context + .server + .worlds + .load() + .first() + .map(|w| w.uuid) + .unwrap_or_else(uuid::Uuid::new_v4) + }); + let pos = location_to_vec3(loc).unwrap_or_else(Vector3::default); + (world_uuid, pos) + } else { + ( + context + .server + .worlds + .load() + .first() + .map(|w| w.uuid) + .unwrap_or_else(uuid::Uuid::new_v4), + Vector3::default(), + ) + }; + let block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + let pumpkin_event = BlockBurnEvent { + igniting_block, + block, + block_pos, + world_uuid, + cancelled: false, + }; + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } Data::EntitySpawn(entity_spawn_event_data) => { let uuid = uuid::Uuid::parse_str(&entity_spawn_event_data.entity_uuid?.value) .ok()?; From d11b839db1bf05e6643952a869313011a99e2cc1 Mon Sep 17 00:00:00 2001 From: yunuservices Date: Thu, 5 Feb 2026 06:53:56 +0300 Subject: [PATCH 29/56] Add block ignite event --- .../events/PatchBukkitEventFactory.java | 45 ++++++++++++ .../events/PatchBukkitEventManager.java | 20 ++++++ proto/patchbukkit/events/block_events.proto | 8 +++ proto/patchbukkit/events/event.proto | 1 + rust/src/events/handler.rs | 71 ++++++++++++++++++- rust/src/java/native_callbacks/events.rs | 56 +++++++++++++++ 6 files changed, 200 insertions(+), 1 deletion(-) diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index 6af76db..ffa8e18 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -10,6 +10,7 @@ import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockCanBuildEvent; import org.bukkit.event.block.BlockBurnEvent; +import org.bukkit.event.block.BlockIgniteEvent; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.player.AsyncPlayerChatEvent; import org.bukkit.event.player.PlayerInteractEvent; @@ -1058,6 +1059,32 @@ yield new PlayerStatisticIncrementEvent( setIgnitingBlock(eventObj, burnEvent.getIgnitingBlockKey()); yield eventObj; } + case BLOCK_IGNITE -> { + patchbukkit.events.BlockIgniteEvent igniteEvent = event.getBlockIgnite(); + Player player = getPlayer(igniteEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + Location location = BridgeUtils.convertLocation(igniteEvent.getLocation()); + if (location == null || !(location.getWorld() instanceof PatchBukkitWorld world)) { + yield null; + } + Block block = PatchBukkitBlock.create( + world, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ(), + igniteEvent.getBlockKey() + ); + BlockIgniteEvent.IgniteCause cause = BlockIgniteEvent.IgniteCause.FLINT_AND_STEEL; + if (!igniteEvent.getCause().isEmpty()) { + try { + cause = BlockIgniteEvent.IgniteCause.valueOf(igniteEvent.getCause()); + } catch (IllegalArgumentException ignored) { + cause = BlockIgniteEvent.IgniteCause.FLINT_AND_STEEL; + } + } + BlockIgniteEvent eventObj = new BlockIgniteEvent(block, cause, player); + yield eventObj; + } case BLOCK_PLACE -> { patchbukkit.events.BlockPlaceEvent placeEvent = event.getBlockPlace(); Player player = getPlayer(placeEvent.getPlayerUuid().getValue()); @@ -1972,6 +1999,24 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .setLocation(BridgeUtils.convertLocation(block.getLocation())) .build() ); + } else if (event instanceof BlockIgniteEvent igniteEvent) { + Block block = igniteEvent.getBlock(); + String cause = igniteEvent.getCause() != null ? igniteEvent.getCause().name() : ""; + Block ignitingBlock = resolveIgnitingBlock(igniteEvent); + String ignitingKey = ignitingBlock != null + ? ignitingBlock.getType().getKey().toString() + : "minecraft:fire"; + eventBuilder.setBlockIgnite( + patchbukkit.events.BlockIgniteEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(igniteEvent.getPlayer().getUniqueId().toString()) + .build()) + .setBlockKey(block.getType().getKey().toString()) + .setIgnitingBlockKey(ignitingKey) + .setLocation(BridgeUtils.convertLocation(block.getLocation())) + .setCause(cause) + .build() + ); } else if (event instanceof BlockPlaceEvent placeEvent) { var block = placeEvent.getBlockPlaced(); var against = placeEvent.getBlockAgainst(); 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 33d299a..21f313a 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -1031,6 +1031,26 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.block.BlockIgniteEvent": + var igniteEvent = (org.bukkit.event.block.BlockIgniteEvent) event; + Block igniteBlock = igniteEvent.getBlock(); + String igniteCause = igniteEvent.getCause() != null ? igniteEvent.getCause().name() : ""; + Block igniteSource = PatchBukkitEventFactory.resolveIgnitingBlock(igniteEvent); + String igniteKey = igniteSource != null + ? igniteSource.getType().getKey().toString() + : "minecraft:fire"; + request.setEvent( + patchbukkit.events.Event.newBuilder().setBlockIgnite( + patchbukkit.events.BlockIgniteEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(igniteEvent.getPlayer().getUniqueId())) + .setBlockKey(igniteBlock.getType().getKey().toString()) + .setIgnitingBlockKey(igniteKey) + .setLocation(BridgeUtils.convertLocation(igniteBlock.getLocation())) + .setCause(igniteCause) + .build() + ).build() + ); + break; case "org.bukkit.event.block.BlockPlaceEvent": var placeEvent = (org.bukkit.event.block.BlockPlaceEvent) event; request.setEvent( diff --git a/proto/patchbukkit/events/block_events.proto b/proto/patchbukkit/events/block_events.proto index e43ecbe..bee6610 100644 --- a/proto/patchbukkit/events/block_events.proto +++ b/proto/patchbukkit/events/block_events.proto @@ -36,6 +36,14 @@ message BlockBurnEvent { patchbukkit.common.Location location = 3; } +message BlockIgniteEvent { + patchbukkit.common.UUID player_uuid = 1; + string block_key = 2; + string igniting_block_key = 3; + patchbukkit.common.Location location = 4; + string cause = 5; +} + message PlayerInteractEvent { patchbukkit.common.UUID player_uuid = 1; string action = 2; diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index 8d04c44..b599425 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -74,6 +74,7 @@ message Event { PlayerHarvestBlockEvent player_harvest_block = 59; BlockCanBuildEvent block_can_build = 60; BlockBurnEvent block_burn = 61; + BlockIgniteEvent block_ignite = 62; } } diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index 57ea416..a8d046c 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -19,7 +19,7 @@ use crate::java::jvm::commands::JvmCommand; use crate::proto::patchbukkit::common::{Location, Uuid, Vec3, World}; use crate::proto::patchbukkit::events::event::Data; use crate::proto::patchbukkit::events::{ - BlockBreakEvent, BlockPlaceEvent, BlockCanBuildEvent, BlockBurnEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, + BlockBreakEvent, BlockPlaceEvent, BlockCanBuildEvent, BlockBurnEvent, BlockIgniteEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, PlayerLeaveEvent, PlayerMoveEvent, PlayerInteractEvent, ServerBroadcastEvent, ServerCommandEvent, EntityDamageEvent, EntityDeathEvent, EntitySpawnEvent, PlayerLoginEvent, PlayerTeleportEvent, PlayerChangeWorldEvent, PlayerGamemodeChangeEvent, @@ -2466,6 +2466,75 @@ impl PatchBukkitEvent for pumpkin::plugin::block::block_burn::BlockBurnEvent { } } +impl PatchBukkitEvent for pumpkin::plugin::block::block_ignite::BlockIgniteEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockIgnite(BlockIgniteEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + block_key: block_to_key(self.block), + igniting_block_key: block_to_key(self.igniting_block), + location: Some(location), + cause: self.cause.clone(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::BlockIgnite(event) => { + if !event.block_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_key) { + self.block = block; + } + } + if !event.igniting_block_key.is_empty() { + if let Some(block) = Block::from_name(&event.igniting_block_key) { + self.igniting_block = block; + } + } + if let Some(loc) = event.location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + if let Some(world) = loc.world.and_then(|w| w.uuid) { + if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { + self.world_uuid = uuid; + } + } + } + if !event.cause.is_empty() { + self.cause = event.cause; + } + } + _ => {} + } + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::entity::entity_spawn::EntitySpawnEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { JvmEventPayload { diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index 5dfdfcb..3e05bef 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -5,6 +5,7 @@ use pumpkin::plugin::block::block_break::BlockBreakEvent; use pumpkin::plugin::block::block_place::BlockPlaceEvent; use pumpkin::plugin::block::block_can_build::BlockCanBuildEvent; use pumpkin::plugin::block::block_burn::BlockBurnEvent; +use pumpkin::plugin::block::block_ignite::BlockIgniteEvent; use pumpkin::plugin::player::player_chat::PlayerChatEvent; use pumpkin::plugin::player::player_command_preprocess::PlayerCommandPreprocessEvent; use pumpkin::plugin::player::player_command_send::PlayerCommandSendEvent; @@ -1015,6 +1016,21 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.block.BlockIgniteEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_ignite::BlockIgniteEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.block.BlockPlaceEvent" => { context .register_event::< @@ -2201,6 +2217,46 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let uuid = + uuid::Uuid::parse_str(&block_ignite_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let block = block_from_key(&block_ignite_event_data.block_key); + let igniting_block = + block_from_key(&block_ignite_event_data.igniting_block_key); + let (world_uuid, pos) = if let Some(loc) = block_ignite_event_data.location { + let world_uuid = loc + .world + .and_then(|w| w.uuid) + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) + .unwrap_or_else(|| player.world().uuid); + let pos = location_to_vec3(loc).unwrap_or_else(Vector3::default); + (world_uuid, pos) + } else { + (player.world().uuid, Vector3::default()) + }; + let block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + let cause = if block_ignite_event_data.cause.is_empty() { + "UNKNOWN".to_string() + } else { + block_ignite_event_data.cause + }; + let pumpkin_event = BlockIgniteEvent { + player, + block, + igniting_block, + block_pos, + world_uuid, + cause, + cancelled: false, + }; + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } Data::EntitySpawn(entity_spawn_event_data) => { let uuid = uuid::Uuid::parse_str(&entity_spawn_event_data.entity_uuid?.value) .ok()?; From e59c1e60076a246690c742789e16039416e2589b Mon Sep 17 00:00:00 2001 From: yunuservices Date: Thu, 5 Feb 2026 07:09:04 +0300 Subject: [PATCH 30/56] Add block spread event --- .../events/PatchBukkitEventFactory.java | 36 ++++++++ .../events/PatchBukkitEventManager.java | 15 ++++ proto/patchbukkit/events/block_events.proto | 7 ++ proto/patchbukkit/events/event.proto | 1 + rust/src/events/handler.rs | 86 ++++++++++++++++++- rust/src/java/native_callbacks/events.rs | 76 ++++++++++++++++ 6 files changed, 220 insertions(+), 1 deletion(-) diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index ffa8e18..5f8b6ee 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -11,6 +11,7 @@ import org.bukkit.event.block.BlockCanBuildEvent; import org.bukkit.event.block.BlockBurnEvent; import org.bukkit.event.block.BlockIgniteEvent; +import org.bukkit.event.block.BlockSpreadEvent; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.player.AsyncPlayerChatEvent; import org.bukkit.event.player.PlayerInteractEvent; @@ -1085,6 +1086,30 @@ yield new PlayerStatisticIncrementEvent( BlockIgniteEvent eventObj = new BlockIgniteEvent(block, cause, player); yield eventObj; } + case BLOCK_SPREAD -> { + patchbukkit.events.BlockSpreadEvent spreadEvent = event.getBlockSpread(); + Location sourceLocation = BridgeUtils.convertLocation(spreadEvent.getSourceLocation()); + Location location = BridgeUtils.convertLocation(spreadEvent.getLocation()); + if (sourceLocation == null || location == null) yield null; + if (!(sourceLocation.getWorld() instanceof PatchBukkitWorld sourceWorld)) yield null; + if (!(location.getWorld() instanceof PatchBukkitWorld world)) yield null; + Block sourceBlock = PatchBukkitBlock.create( + sourceWorld, + sourceLocation.getBlockX(), + sourceLocation.getBlockY(), + sourceLocation.getBlockZ(), + spreadEvent.getSourceBlockKey() + ); + Block block = PatchBukkitBlock.create( + world, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ(), + spreadEvent.getBlockKey() + ); + org.bukkit.block.BlockState newState = block.getState(); + yield new BlockSpreadEvent(block, sourceBlock, newState); + } case BLOCK_PLACE -> { patchbukkit.events.BlockPlaceEvent placeEvent = event.getBlockPlace(); Player player = getPlayer(placeEvent.getPlayerUuid().getValue()); @@ -2017,6 +2042,17 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .setCause(cause) .build() ); + } else if (event instanceof BlockSpreadEvent spreadEvent) { + Block block = spreadEvent.getBlock(); + Block sourceBlock = spreadEvent.getSource(); + eventBuilder.setBlockSpread( + patchbukkit.events.BlockSpreadEvent.newBuilder() + .setSourceBlockKey(sourceBlock.getType().getKey().toString()) + .setSourceLocation(BridgeUtils.convertLocation(sourceBlock.getLocation())) + .setBlockKey(block.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(block.getLocation())) + .build() + ); } else if (event instanceof BlockPlaceEvent placeEvent) { var block = placeEvent.getBlockPlaced(); var against = placeEvent.getBlockAgainst(); 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 21f313a..4b2c62e 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -1051,6 +1051,21 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.block.BlockSpreadEvent": + var spreadEvent = (org.bukkit.event.block.BlockSpreadEvent) event; + Block spreadBlock = spreadEvent.getBlock(); + Block spreadSource = spreadEvent.getSource(); + request.setEvent( + patchbukkit.events.Event.newBuilder().setBlockSpread( + patchbukkit.events.BlockSpreadEvent.newBuilder() + .setSourceBlockKey(spreadSource.getType().getKey().toString()) + .setSourceLocation(BridgeUtils.convertLocation(spreadSource.getLocation())) + .setBlockKey(spreadBlock.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(spreadBlock.getLocation())) + .build() + ).build() + ); + break; case "org.bukkit.event.block.BlockPlaceEvent": var placeEvent = (org.bukkit.event.block.BlockPlaceEvent) event; request.setEvent( diff --git a/proto/patchbukkit/events/block_events.proto b/proto/patchbukkit/events/block_events.proto index bee6610..b4ddcec 100644 --- a/proto/patchbukkit/events/block_events.proto +++ b/proto/patchbukkit/events/block_events.proto @@ -44,6 +44,13 @@ message BlockIgniteEvent { string cause = 5; } +message BlockSpreadEvent { + string source_block_key = 1; + patchbukkit.common.Location source_location = 2; + string block_key = 3; + patchbukkit.common.Location location = 4; +} + message PlayerInteractEvent { patchbukkit.common.UUID player_uuid = 1; string action = 2; diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index b599425..0114519 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -75,6 +75,7 @@ message Event { BlockCanBuildEvent block_can_build = 60; BlockBurnEvent block_burn = 61; BlockIgniteEvent block_ignite = 62; + BlockSpreadEvent block_spread = 63; } } diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index a8d046c..66725a3 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -19,7 +19,7 @@ use crate::java::jvm::commands::JvmCommand; use crate::proto::patchbukkit::common::{Location, Uuid, Vec3, World}; use crate::proto::patchbukkit::events::event::Data; use crate::proto::patchbukkit::events::{ - BlockBreakEvent, BlockPlaceEvent, BlockCanBuildEvent, BlockBurnEvent, BlockIgniteEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, + BlockBreakEvent, BlockPlaceEvent, BlockCanBuildEvent, BlockBurnEvent, BlockIgniteEvent, BlockSpreadEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, PlayerLeaveEvent, PlayerMoveEvent, PlayerInteractEvent, ServerBroadcastEvent, ServerCommandEvent, EntityDamageEvent, EntityDeathEvent, EntitySpawnEvent, PlayerLoginEvent, PlayerTeleportEvent, PlayerChangeWorldEvent, PlayerGamemodeChangeEvent, @@ -2535,6 +2535,90 @@ impl PatchBukkitEvent for pumpkin::plugin::block::block_ignite::BlockIgniteEvent } } +impl PatchBukkitEvent for pumpkin::plugin::block::block_spread::BlockSpreadEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let source_location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.source_pos.0.x), + f64::from(self.source_pos.0.y), + f64::from(self.source_pos.0.z), + ), + 0.0, + 0.0, + ); + let location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockSpread(BlockSpreadEvent { + source_block_key: block_to_key(self.source_block), + source_location: Some(source_location), + block_key: block_to_key(self.block), + location: Some(location), + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::BlockSpread(event) => { + if !event.source_block_key.is_empty() { + if let Some(block) = Block::from_name(&event.source_block_key) { + self.source_block = block; + } + } + if !event.block_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_key) { + self.block = block; + } + } + if let Some(loc) = event.source_location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.source_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + if let Some(world) = loc.world.and_then(|w| w.uuid) { + if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { + self.world_uuid = uuid; + } + } + } + if let Some(loc) = event.location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + if let Some(world) = loc.world.and_then(|w| w.uuid) { + if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { + self.world_uuid = uuid; + } + } + } + } + _ => {} + } + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::entity::entity_spawn::EntitySpawnEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { JvmEventPayload { diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index 3e05bef..ef77317 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -6,6 +6,7 @@ use pumpkin::plugin::block::block_place::BlockPlaceEvent; use pumpkin::plugin::block::block_can_build::BlockCanBuildEvent; use pumpkin::plugin::block::block_burn::BlockBurnEvent; use pumpkin::plugin::block::block_ignite::BlockIgniteEvent; +use pumpkin::plugin::block::block_spread::BlockSpreadEvent; use pumpkin::plugin::player::player_chat::PlayerChatEvent; use pumpkin::plugin::player::player_command_preprocess::PlayerCommandPreprocessEvent; use pumpkin::plugin::player::player_command_send::PlayerCommandSendEvent; @@ -1031,6 +1032,21 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.block.BlockSpreadEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_spread::BlockSpreadEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.block.BlockPlaceEvent" => { context .register_event::< @@ -2257,6 +2273,66 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let source_block = block_from_key(&block_spread_event_data.source_block_key); + let block = block_from_key(&block_spread_event_data.block_key); + let (world_uuid, source_pos) = + if let Some(loc) = block_spread_event_data.source_location { + let world_uuid = loc + .world + .and_then(|w| w.uuid) + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) + .unwrap_or_else(|| { + context + .server + .worlds + .load() + .first() + .map(|w| w.uuid) + .unwrap_or_else(uuid::Uuid::new_v4) + }); + let pos = location_to_vec3(loc).unwrap_or_else(Vector3::default); + ( + world_uuid, + pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ), + ) + } else { + ( + context + .server + .worlds + .load() + .first() + .map(|w| w.uuid) + .unwrap_or_else(uuid::Uuid::new_v4), + pumpkin_util::math::position::BlockPos::new(0, 0, 0), + ) + }; + let block_pos = if let Some(loc) = block_spread_event_data.location { + let pos = location_to_vec3(loc).unwrap_or_else(Vector3::default); + pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ) + } else { + source_pos + }; + let pumpkin_event = BlockSpreadEvent { + source_block, + source_pos, + block, + block_pos, + world_uuid, + cancelled: false, + }; + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } Data::EntitySpawn(entity_spawn_event_data) => { let uuid = uuid::Uuid::parse_str(&entity_spawn_event_data.entity_uuid?.value) .ok()?; From 7814906aa493ac29f0a7e41bf2054ca320a0a32e Mon Sep 17 00:00:00 2001 From: yunuservices Date: Thu, 5 Feb 2026 07:53:42 +0300 Subject: [PATCH 31/56] Add block damage events --- .../events/PatchBukkitEventFactory.java | 93 ++++++++++++++++++ .../events/PatchBukkitEventManager.java | 35 +++++++ proto/patchbukkit/events/block_events.proto | 15 +++ proto/patchbukkit/events/event.proto | 2 + rust/src/events/handler.rs | 96 ++++++++++++++++++- rust/src/java/native_callbacks/events.rs | 93 ++++++++++++++++++ 6 files changed, 333 insertions(+), 1 deletion(-) diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index 5f8b6ee..3a0241f 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -8,6 +8,8 @@ import org.bukkit.Location; import org.bukkit.entity.Player; import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockDamageAbortEvent; +import org.bukkit.event.block.BlockDamageEvent; import org.bukkit.event.block.BlockCanBuildEvent; import org.bukkit.event.block.BlockBurnEvent; import org.bukkit.event.block.BlockIgniteEvent; @@ -1022,6 +1024,68 @@ yield new PlayerStatisticIncrementEvent( eventObj.setDropItems(breakEvent.getDrop()); yield eventObj; } + case BLOCK_DAMAGE -> { + patchbukkit.events.BlockDamageEvent damageEvent = event.getBlockDamage(); + Player player = getPlayer(damageEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + + Location location = BridgeUtils.convertLocation(damageEvent.getLocation()); + if (location == null || !(location.getWorld() instanceof PatchBukkitWorld world)) { + yield null; + } + + org.bukkit.block.Block block = PatchBukkitBlock.create( + world, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ(), + damageEvent.getBlockKey() + ); + + ItemStack item = null; + if (!damageEvent.getItemKey().isEmpty()) { + Material material = Material.matchMaterial(damageEvent.getItemKey()); + if (material == null) { + material = Material.matchMaterial("minecraft:" + damageEvent.getItemKey()); + } + if (material != null) { + item = new ItemStack(material); + } + } + + yield new BlockDamageEvent(block, player, item, damageEvent.getInstaBreak()); + } + case BLOCK_DAMAGE_ABORT -> { + patchbukkit.events.BlockDamageAbortEvent damageAbortEvent = event.getBlockDamageAbort(); + Player player = getPlayer(damageAbortEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + + Location location = BridgeUtils.convertLocation(damageAbortEvent.getLocation()); + if (location == null || !(location.getWorld() instanceof PatchBukkitWorld world)) { + yield null; + } + + org.bukkit.block.Block block = PatchBukkitBlock.create( + world, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ(), + damageAbortEvent.getBlockKey() + ); + + ItemStack item = null; + if (!damageAbortEvent.getItemKey().isEmpty()) { + Material material = Material.matchMaterial(damageAbortEvent.getItemKey()); + if (material == null) { + material = Material.matchMaterial("minecraft:" + damageAbortEvent.getItemKey()); + } + if (material != null) { + item = new ItemStack(material); + } + } + + yield new BlockDamageAbortEvent(block, player, item); + } case BLOCK_CAN_BUILD -> { patchbukkit.events.BlockCanBuildEvent canBuildEvent = event.getBlockCanBuild(); Player player = getPlayer(canBuildEvent.getPlayerUuid().getValue()); @@ -1996,6 +2060,35 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .setDrop(breakEvent.isDropItems()) .build() ); + } else if (event instanceof BlockDamageEvent damageEvent) { + var block = damageEvent.getBlock(); + ItemStack item = damageEvent.getItemInHand(); + String itemKey = item != null ? item.getType().getKey().toString() : "minecraft:air"; + eventBuilder.setBlockDamage( + patchbukkit.events.BlockDamageEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(damageEvent.getPlayer().getUniqueId().toString()) + .build()) + .setBlockKey(block.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(block.getLocation())) + .setItemKey(itemKey) + .setInstaBreak(damageEvent.isInstaBreak()) + .build() + ); + } else if (event instanceof BlockDamageAbortEvent damageAbortEvent) { + var block = damageAbortEvent.getBlock(); + ItemStack item = damageAbortEvent.getItemInHand(); + String itemKey = item != null ? item.getType().getKey().toString() : "minecraft:air"; + eventBuilder.setBlockDamageAbort( + patchbukkit.events.BlockDamageAbortEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(damageAbortEvent.getPlayer().getUniqueId().toString()) + .build()) + .setBlockKey(block.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(block.getLocation())) + .setItemKey(itemKey) + .build() + ); } else if (event instanceof BlockCanBuildEvent canBuildEvent) { Block block = canBuildEvent.getBlock(); boolean canBuild = canBuildEvent.isBuildable(); 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 4b2c62e..cb54f5f 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -34,6 +34,8 @@ import patchbukkit.events.ServerBroadcastEvent; import patchbukkit.events.ServerCommandEvent; import patchbukkit.events.BlockBreakEvent; +import patchbukkit.events.BlockDamageAbortEvent; +import patchbukkit.events.BlockDamageEvent; import patchbukkit.events.BlockPlaceEvent; import patchbukkit.events.PlayerInteractEvent; import patchbukkit.events.EntitySpawnEvent; @@ -999,6 +1001,39 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.block.BlockDamageEvent": + var damageEvent = (org.bukkit.event.block.BlockDamageEvent) event; + String damageItemKey = damageEvent.getItemInHand() != null + ? damageEvent.getItemInHand().getType().getKey().toString() + : "minecraft:air"; + request.setEvent( + patchbukkit.events.Event.newBuilder().setBlockDamage( + BlockDamageEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(damageEvent.getPlayer().getUniqueId())) + .setBlockKey(damageEvent.getBlock().getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(damageEvent.getBlock().getLocation())) + .setItemKey(damageItemKey) + .setInstaBreak(damageEvent.isInstaBreak()) + .build() + ).build() + ); + break; + case "org.bukkit.event.block.BlockDamageAbortEvent": + var damageAbortEvent = (org.bukkit.event.block.BlockDamageAbortEvent) event; + String abortItemKey = damageAbortEvent.getItemInHand() != null + ? damageAbortEvent.getItemInHand().getType().getKey().toString() + : "minecraft:air"; + request.setEvent( + patchbukkit.events.Event.newBuilder().setBlockDamageAbort( + BlockDamageAbortEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(damageAbortEvent.getPlayer().getUniqueId())) + .setBlockKey(damageAbortEvent.getBlock().getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(damageAbortEvent.getBlock().getLocation())) + .setItemKey(abortItemKey) + .build() + ).build() + ); + break; case "org.bukkit.event.block.BlockCanBuildEvent": var canBuildEvent = (org.bukkit.event.block.BlockCanBuildEvent) event; Block canBuildBlock = canBuildEvent.getBlock(); diff --git a/proto/patchbukkit/events/block_events.proto b/proto/patchbukkit/events/block_events.proto index b4ddcec..846664f 100644 --- a/proto/patchbukkit/events/block_events.proto +++ b/proto/patchbukkit/events/block_events.proto @@ -14,6 +14,21 @@ message BlockBreakEvent { bool drop = 5; } +message BlockDamageEvent { + patchbukkit.common.UUID player_uuid = 1; + string block_key = 2; + patchbukkit.common.Location location = 3; + string item_key = 4; + bool insta_break = 5; +} + +message BlockDamageAbortEvent { + patchbukkit.common.UUID player_uuid = 1; + string block_key = 2; + patchbukkit.common.Location location = 3; + string item_key = 4; +} + message BlockPlaceEvent { patchbukkit.common.UUID player_uuid = 1; string block_key = 2; diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index 0114519..1affec0 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -76,6 +76,8 @@ message Event { BlockBurnEvent block_burn = 61; BlockIgniteEvent block_ignite = 62; BlockSpreadEvent block_spread = 63; + BlockDamageEvent block_damage = 64; + BlockDamageAbortEvent block_damage_abort = 65; } } diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index 66725a3..91cf16f 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -19,7 +19,7 @@ use crate::java::jvm::commands::JvmCommand; use crate::proto::patchbukkit::common::{Location, Uuid, Vec3, World}; use crate::proto::patchbukkit::events::event::Data; use crate::proto::patchbukkit::events::{ - BlockBreakEvent, BlockPlaceEvent, BlockCanBuildEvent, BlockBurnEvent, BlockIgniteEvent, BlockSpreadEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, + BlockBreakEvent, BlockDamageEvent, BlockDamageAbortEvent, BlockPlaceEvent, BlockCanBuildEvent, BlockBurnEvent, BlockIgniteEvent, BlockSpreadEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, PlayerLeaveEvent, PlayerMoveEvent, PlayerInteractEvent, ServerBroadcastEvent, ServerCommandEvent, EntityDamageEvent, EntityDeathEvent, EntitySpawnEvent, PlayerLoginEvent, PlayerTeleportEvent, PlayerChangeWorldEvent, PlayerGamemodeChangeEvent, @@ -2329,6 +2329,100 @@ impl PatchBukkitEvent for pumpkin::plugin::block::block_break::BlockBreakEvent { } } +impl PatchBukkitEvent for pumpkin::plugin::block::block_damage::BlockDamageEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let player_uuid = self.player.gameprofile.id.to_string(); + let world_uuid = self.player.world().uuid; + let location = build_location( + world_uuid, + &Vector3::new( + f64::from(self.block_position.0.x), + f64::from(self.block_position.0.y), + f64::from(self.block_position.0.z), + ), + 0.0, + 0.0, + ); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockDamage(BlockDamageEvent { + player_uuid: Some(Uuid { value: player_uuid }), + block_key: block_to_key(self.block), + location: Some(location), + item_key: item_to_key(self.item_stack.item), + insta_break: self.insta_break, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::BlockDamage(event) => { + self.insta_break = event.insta_break; + if !event.item_key.is_empty() { + let count = self.item_stack.item_count; + self.item_stack = item_stack_from_key(&event.item_key, count); + } + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::block::block_damage_abort::BlockDamageAbortEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let player_uuid = self.player.gameprofile.id.to_string(); + let world_uuid = self.player.world().uuid; + let location = build_location( + world_uuid, + &Vector3::new( + f64::from(self.block_position.0.x), + f64::from(self.block_position.0.y), + f64::from(self.block_position.0.z), + ), + 0.0, + 0.0, + ); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockDamageAbort(BlockDamageAbortEvent { + player_uuid: Some(Uuid { value: player_uuid }), + block_key: block_to_key(self.block), + location: Some(location), + item_key: item_to_key(self.item_stack.item), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::BlockDamageAbort(event) => { + if !event.item_key.is_empty() { + let count = self.item_stack.item_count; + self.item_stack = item_stack_from_key(&event.item_key, count); + } + } + _ => {} + } + + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::block::block_place::BlockPlaceEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { let player_uuid = self.player.gameprofile.id.to_string(); diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index ef77317..48dbc1d 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -2,6 +2,8 @@ use std::sync::Arc; use pumpkin::plugin::EventPriority; use pumpkin::plugin::block::block_break::BlockBreakEvent; +use pumpkin::plugin::block::block_damage::BlockDamageEvent; +use pumpkin::plugin::block::block_damage_abort::BlockDamageAbortEvent; use pumpkin::plugin::block::block_place::BlockPlaceEvent; use pumpkin::plugin::block::block_can_build::BlockCanBuildEvent; use pumpkin::plugin::block::block_burn::BlockBurnEvent; @@ -987,6 +989,38 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.block.BlockDamageEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_damage::BlockDamageEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.BlockDamageAbortEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_damage_abort::BlockDamageAbortEvent, + PatchBukkitEventHandler< + pumpkin::plugin::block::block_damage_abort::BlockDamageAbortEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.block.BlockCanBuildEvent" => { context .register_event::< @@ -2128,6 +2162,65 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let uuid = uuid::Uuid::parse_str(&block_damage_event_data.player_uuid?.value) + .ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let block = block_from_key(&block_damage_event_data.block_key); + let position = block_damage_event_data + .location + .and_then(|loc| loc.position) + .map(|pos| { + pumpkin_util::math::position::BlockPos::new( + pos.x as i32, + pos.y as i32, + pos.z as i32, + ) + }) + .unwrap_or_else(|| player.position().to_block_pos()); + let key = if block_damage_event_data.item_key.is_empty() { + "minecraft:air" + } else { + block_damage_event_data.item_key.as_str() + }; + let item_stack = item_stack_from_key(key, 1); + let pumpkin_event = BlockDamageEvent::new( + player, + block, + position, + item_stack, + block_damage_event_data.insta_break, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::BlockDamageAbort(block_damage_abort_event_data) => { + let uuid = uuid::Uuid::parse_str(&block_damage_abort_event_data.player_uuid?.value) + .ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let block = block_from_key(&block_damage_abort_event_data.block_key); + let position = block_damage_abort_event_data + .location + .and_then(|loc| loc.position) + .map(|pos| { + pumpkin_util::math::position::BlockPos::new( + pos.x as i32, + pos.y as i32, + pos.z as i32, + ) + }) + .unwrap_or_else(|| player.position().to_block_pos()); + let key = if block_damage_abort_event_data.item_key.is_empty() { + "minecraft:air" + } else { + block_damage_abort_event_data.item_key.as_str() + }; + let item_stack = item_stack_from_key(key, 1); + let pumpkin_event = + BlockDamageAbortEvent::new(player, block, position, item_stack); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } Data::BlockPlace(block_place_event_data) => { let uuid = uuid::Uuid::parse_str(&block_place_event_data.player_uuid?.value) .ok()?; From b0626735c452bdf72c72303db23d82e60700bef2 Mon Sep 17 00:00:00 2001 From: yunuservices Date: Thu, 5 Feb 2026 08:19:46 +0300 Subject: [PATCH 32/56] Add BlockDispenseEvent bridge --- .../events/PatchBukkitEventFactory.java | 56 ++++++++++++++++ .../events/PatchBukkitEventManager.java | 26 ++++++++ proto/patchbukkit/events/block_events.proto | 8 +++ proto/patchbukkit/events/event.proto | 1 + rust/src/events/handler.rs | 66 ++++++++++++++++++- rust/src/java/native_callbacks/events.rs | 45 +++++++++++++ 6 files changed, 201 insertions(+), 1 deletion(-) diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index 3a0241f..5fb4e87 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -10,6 +10,7 @@ import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockDamageAbortEvent; import org.bukkit.event.block.BlockDamageEvent; +import org.bukkit.event.block.BlockDispenseEvent; import org.bukkit.event.block.BlockCanBuildEvent; import org.bukkit.event.block.BlockBurnEvent; import org.bukkit.event.block.BlockIgniteEvent; @@ -1086,6 +1087,42 @@ yield new PlayerStatisticIncrementEvent( yield new BlockDamageAbortEvent(block, player, item); } + case BLOCK_DISPENSE -> { + patchbukkit.events.BlockDispenseEvent dispenseEvent = event.getBlockDispense(); + Location location = BridgeUtils.convertLocation(dispenseEvent.getLocation()); + if (location == null || !(location.getWorld() instanceof PatchBukkitWorld world)) { + yield null; + } + + org.bukkit.block.Block block = PatchBukkitBlock.create( + world, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ(), + dispenseEvent.getBlockKey() + ); + + ItemStack item = null; + if (!dispenseEvent.getItemKey().isEmpty()) { + Material material = Material.matchMaterial(dispenseEvent.getItemKey()); + if (material == null) { + material = Material.matchMaterial("minecraft:" + dispenseEvent.getItemKey()); + } + if (material != null) { + int amount = Math.max(1, dispenseEvent.getItemAmount()); + item = new ItemStack(material, amount); + } + } + + Vector velocity = new Vector(); + if (dispenseEvent.hasVelocity()) { + velocity.setX(dispenseEvent.getVelocity().getX()); + velocity.setY(dispenseEvent.getVelocity().getY()); + velocity.setZ(dispenseEvent.getVelocity().getZ()); + } + + yield new BlockDispenseEvent(block, item, velocity); + } case BLOCK_CAN_BUILD -> { patchbukkit.events.BlockCanBuildEvent canBuildEvent = event.getBlockCanBuild(); Player player = getPlayer(canBuildEvent.getPlayerUuid().getValue()); @@ -2089,6 +2126,25 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .setItemKey(itemKey) .build() ); + } else if (event instanceof BlockDispenseEvent dispenseEvent) { + var block = dispenseEvent.getBlock(); + ItemStack item = dispenseEvent.getItem(); + String itemKey = item != null ? item.getType().getKey().toString() : "minecraft:air"; + int amount = item != null ? item.getAmount() : 0; + Vector velocity = dispenseEvent.getVelocity(); + eventBuilder.setBlockDispense( + patchbukkit.events.BlockDispenseEvent.newBuilder() + .setBlockKey(block.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(block.getLocation())) + .setItemKey(itemKey) + .setItemAmount(amount) + .setVelocity(patchbukkit.common.Vec3.newBuilder() + .setX(velocity.getX()) + .setY(velocity.getY()) + .setZ(velocity.getZ()) + .build()) + .build() + ); } else if (event instanceof BlockCanBuildEvent canBuildEvent) { Block block = canBuildEvent.getBlock(); boolean canBuild = canBuildEvent.isBuildable(); 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 cb54f5f..5a840eb 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -36,6 +36,7 @@ import patchbukkit.events.BlockBreakEvent; import patchbukkit.events.BlockDamageAbortEvent; import patchbukkit.events.BlockDamageEvent; +import patchbukkit.events.BlockDispenseEvent; import patchbukkit.events.BlockPlaceEvent; import patchbukkit.events.PlayerInteractEvent; import patchbukkit.events.EntitySpawnEvent; @@ -1034,6 +1035,31 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.block.BlockDispenseEvent": + var dispenseEvent = (org.bukkit.event.block.BlockDispenseEvent) event; + String dispenseItemKey = dispenseEvent.getItem() != null + ? dispenseEvent.getItem().getType().getKey().toString() + : "minecraft:air"; + int dispenseAmount = dispenseEvent.getItem() != null + ? dispenseEvent.getItem().getAmount() + : 0; + var velocity = dispenseEvent.getVelocity(); + request.setEvent( + patchbukkit.events.Event.newBuilder().setBlockDispense( + BlockDispenseEvent.newBuilder() + .setBlockKey(dispenseEvent.getBlock().getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(dispenseEvent.getBlock().getLocation())) + .setItemKey(dispenseItemKey) + .setItemAmount(dispenseAmount) + .setVelocity(patchbukkit.common.Vec3.newBuilder() + .setX(velocity.getX()) + .setY(velocity.getY()) + .setZ(velocity.getZ()) + .build()) + .build() + ).build() + ); + break; case "org.bukkit.event.block.BlockCanBuildEvent": var canBuildEvent = (org.bukkit.event.block.BlockCanBuildEvent) event; Block canBuildBlock = canBuildEvent.getBlock(); diff --git a/proto/patchbukkit/events/block_events.proto b/proto/patchbukkit/events/block_events.proto index 846664f..0791bfd 100644 --- a/proto/patchbukkit/events/block_events.proto +++ b/proto/patchbukkit/events/block_events.proto @@ -29,6 +29,14 @@ message BlockDamageAbortEvent { string item_key = 4; } +message BlockDispenseEvent { + string block_key = 1; + patchbukkit.common.Location location = 2; + string item_key = 3; + int32 item_amount = 4; + patchbukkit.common.Vec3 velocity = 5; +} + message BlockPlaceEvent { patchbukkit.common.UUID player_uuid = 1; string block_key = 2; diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index 1affec0..1491935 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -78,6 +78,7 @@ message Event { BlockSpreadEvent block_spread = 63; BlockDamageEvent block_damage = 64; BlockDamageAbortEvent block_damage_abort = 65; + BlockDispenseEvent block_dispense = 66; } } diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index 91cf16f..842cc55 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -19,7 +19,7 @@ use crate::java::jvm::commands::JvmCommand; use crate::proto::patchbukkit::common::{Location, Uuid, Vec3, World}; use crate::proto::patchbukkit::events::event::Data; use crate::proto::patchbukkit::events::{ - BlockBreakEvent, BlockDamageEvent, BlockDamageAbortEvent, BlockPlaceEvent, BlockCanBuildEvent, BlockBurnEvent, BlockIgniteEvent, BlockSpreadEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, + BlockBreakEvent, BlockDamageEvent, BlockDamageAbortEvent, BlockDispenseEvent, BlockPlaceEvent, BlockCanBuildEvent, BlockBurnEvent, BlockIgniteEvent, BlockSpreadEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, PlayerLeaveEvent, PlayerMoveEvent, PlayerInteractEvent, ServerBroadcastEvent, ServerCommandEvent, EntityDamageEvent, EntityDeathEvent, EntitySpawnEvent, PlayerLoginEvent, PlayerTeleportEvent, PlayerChangeWorldEvent, PlayerGamemodeChangeEvent, @@ -2423,6 +2423,70 @@ impl PatchBukkitEvent for pumpkin::plugin::block::block_damage_abort::BlockDamag } } +impl PatchBukkitEvent for pumpkin::plugin::block::block_dispense::BlockDispenseEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let world_uuid = server + .worlds + .load() + .first() + .map(|world| world.uuid) + .unwrap_or_default(); + let location = build_location( + world_uuid, + &Vector3::new( + f64::from(self.block_position.0.x), + f64::from(self.block_position.0.y), + f64::from(self.block_position.0.z), + ), + 0.0, + 0.0, + ); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockDispense(BlockDispenseEvent { + block_key: block_to_key(self.block), + location: Some(location), + item_key: item_to_key(self.item_stack.item), + item_amount: i32::from(self.item_stack.item_count), + velocity: Some(Vec3 { + x: self.velocity.x, + y: self.velocity.y, + z: self.velocity.z, + }), + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::BlockDispense(event) => { + if !event.item_key.is_empty() || event.item_amount > 0 { + let key = if event.item_key.is_empty() { + item_to_key(self.item_stack.item) + } else { + event.item_key + }; + let count = if event.item_amount > 0 { + event.item_amount as u8 + } else { + self.item_stack.item_count + }; + self.item_stack = item_stack_from_key(&key, count); + } + if let Some(vel) = event.velocity { + self.velocity = Vector3::new(vel.x, vel.y, vel.z); + } + } + _ => {} + } + + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::block::block_place::BlockPlaceEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { let player_uuid = self.player.gameprofile.id.to_string(); diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index 48dbc1d..1dcb33b 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -4,6 +4,7 @@ use pumpkin::plugin::EventPriority; use pumpkin::plugin::block::block_break::BlockBreakEvent; use pumpkin::plugin::block::block_damage::BlockDamageEvent; use pumpkin::plugin::block::block_damage_abort::BlockDamageAbortEvent; +use pumpkin::plugin::block::block_dispense::BlockDispenseEvent; use pumpkin::plugin::block::block_place::BlockPlaceEvent; use pumpkin::plugin::block::block_can_build::BlockCanBuildEvent; use pumpkin::plugin::block::block_burn::BlockBurnEvent; @@ -1021,6 +1022,21 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.block.BlockDispenseEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_dispense::BlockDispenseEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.block.BlockCanBuildEvent" => { context .register_event::< @@ -2221,6 +2237,35 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let block = block_from_key(&block_dispense_event_data.block_key); + let position = block_dispense_event_data + .location + .and_then(|loc| loc.position) + .map(|pos| { + pumpkin_util::math::position::BlockPos::new( + pos.x as i32, + pos.y as i32, + pos.z as i32, + ) + }) + .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); + let key = if block_dispense_event_data.item_key.is_empty() { + "minecraft:air" + } else { + block_dispense_event_data.item_key.as_str() + }; + let item_stack = + item_stack_from_key(key, block_dispense_event_data.item_amount); + let velocity = block_dispense_event_data + .velocity + .map(|v| Vector3::new(v.x, v.y, v.z)) + .unwrap_or_else(|| Vector3::new(0.0, 0.0, 0.0)); + let pumpkin_event = + BlockDispenseEvent::new(block, position, item_stack, velocity); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } Data::BlockPlace(block_place_event_data) => { let uuid = uuid::Uuid::parse_str(&block_place_event_data.player_uuid?.value) .ok()?; From f49b3e3ab1a22b0a1d889430fbc41aaf6c005c8b Mon Sep 17 00:00:00 2001 From: yunuservices Date: Thu, 5 Feb 2026 08:26:55 +0300 Subject: [PATCH 33/56] Add BlockDropItemEvent bridge --- .../events/PatchBukkitEventFactory.java | 56 +++++++++++++++ .../events/PatchBukkitEventManager.java | 24 ++++++- proto/patchbukkit/events/block_events.proto | 12 ++++ proto/patchbukkit/events/event.proto | 1 + rust/src/events/handler.rs | 71 ++++++++++++++++++- rust/src/java/native_callbacks/events.rs | 51 +++++++++++++ 6 files changed, 213 insertions(+), 2 deletions(-) diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index 5fb4e87..5ba271a 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -11,6 +11,7 @@ import org.bukkit.event.block.BlockDamageAbortEvent; import org.bukkit.event.block.BlockDamageEvent; import org.bukkit.event.block.BlockDispenseEvent; +import org.bukkit.event.block.BlockDropItemEvent; import org.bukkit.event.block.BlockCanBuildEvent; import org.bukkit.event.block.BlockBurnEvent; import org.bukkit.event.block.BlockIgniteEvent; @@ -1123,6 +1124,40 @@ yield new PlayerStatisticIncrementEvent( yield new BlockDispenseEvent(block, item, velocity); } + case BLOCK_DROP_ITEM -> { + patchbukkit.events.BlockDropItemEvent dropItemEvent = event.getBlockDropItem(); + Player player = getPlayer(dropItemEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + + Location location = BridgeUtils.convertLocation(dropItemEvent.getLocation()); + if (location == null || !(location.getWorld() instanceof PatchBukkitWorld world)) { + yield null; + } + + org.bukkit.block.Block block = PatchBukkitBlock.create( + world, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ(), + dropItemEvent.getBlockKey() + ); + + java.util.List items = new java.util.ArrayList<>(); + for (patchbukkit.events.BlockDropItemEntry entry : dropItemEvent.getItemsList()) { + if (entry.getItemKey().isEmpty() || entry.getItemAmount() <= 0) continue; + Material material = Material.matchMaterial(entry.getItemKey()); + if (material == null) { + material = Material.matchMaterial("minecraft:" + entry.getItemKey()); + } + if (material == null) continue; + ItemStack stack = new ItemStack(material, entry.getItemAmount()); + org.patchbukkit.entity.PatchBukkitItem itemEntity = + new org.patchbukkit.entity.PatchBukkitItem(java.util.UUID.randomUUID(), stack); + items.add(itemEntity); + } + + yield new BlockDropItemEvent(block, player, items); + } case BLOCK_CAN_BUILD -> { patchbukkit.events.BlockCanBuildEvent canBuildEvent = event.getBlockCanBuild(); Player player = getPlayer(canBuildEvent.getPlayerUuid().getValue()); @@ -2145,6 +2180,27 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .build()) .build() ); + } else if (event instanceof BlockDropItemEvent dropItemEvent) { + var block = dropItemEvent.getBlock(); + var builder = patchbukkit.events.BlockDropItemEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(dropItemEvent.getPlayer().getUniqueId().toString()) + .build()) + .setBlockKey(block.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(block.getLocation())); + + for (org.bukkit.entity.Item item : dropItemEvent.getItems()) { + ItemStack stack = item.getItemStack(); + if (stack == null) continue; + builder.addItems( + patchbukkit.events.BlockDropItemEntry.newBuilder() + .setItemKey(stack.getType().getKey().toString()) + .setItemAmount(stack.getAmount()) + .build() + ); + } + + eventBuilder.setBlockDropItem(builder.build()); } else if (event instanceof BlockCanBuildEvent canBuildEvent) { Block block = canBuildEvent.getBlock(); boolean canBuild = canBuildEvent.isBuildable(); 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 5a840eb..6db0798 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -37,6 +37,8 @@ import patchbukkit.events.BlockDamageAbortEvent; import patchbukkit.events.BlockDamageEvent; import patchbukkit.events.BlockDispenseEvent; +import patchbukkit.events.BlockDropItemEntry; +import patchbukkit.events.BlockDropItemEvent; import patchbukkit.events.BlockPlaceEvent; import patchbukkit.events.PlayerInteractEvent; import patchbukkit.events.EntitySpawnEvent; @@ -1055,11 +1057,31 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { .setX(velocity.getX()) .setY(velocity.getY()) .setZ(velocity.getZ()) - .build()) + .build()) .build() ).build() ); break; + case "org.bukkit.event.block.BlockDropItemEvent": + var dropItemEvent = (org.bukkit.event.block.BlockDropItemEvent) event; + Block dropBlock = dropItemEvent.getBlock(); + var dropBuilder = BlockDropItemEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(dropItemEvent.getPlayer().getUniqueId())) + .setBlockKey(dropBlock.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(dropBlock.getLocation())); + for (org.bukkit.entity.Item item : dropItemEvent.getItems()) { + if (item.getItemStack() == null) continue; + dropBuilder.addItems( + BlockDropItemEntry.newBuilder() + .setItemKey(item.getItemStack().getType().getKey().toString()) + .setItemAmount(item.getItemStack().getAmount()) + .build() + ); + } + request.setEvent( + patchbukkit.events.Event.newBuilder().setBlockDropItem(dropBuilder.build()).build() + ); + break; case "org.bukkit.event.block.BlockCanBuildEvent": var canBuildEvent = (org.bukkit.event.block.BlockCanBuildEvent) event; Block canBuildBlock = canBuildEvent.getBlock(); diff --git a/proto/patchbukkit/events/block_events.proto b/proto/patchbukkit/events/block_events.proto index 0791bfd..3bc85d1 100644 --- a/proto/patchbukkit/events/block_events.proto +++ b/proto/patchbukkit/events/block_events.proto @@ -37,6 +37,18 @@ message BlockDispenseEvent { patchbukkit.common.Vec3 velocity = 5; } +message BlockDropItemEntry { + string item_key = 1; + int32 item_amount = 2; +} + +message BlockDropItemEvent { + patchbukkit.common.UUID player_uuid = 1; + string block_key = 2; + patchbukkit.common.Location location = 3; + repeated BlockDropItemEntry items = 4; +} + message BlockPlaceEvent { patchbukkit.common.UUID player_uuid = 1; string block_key = 2; diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index 1491935..d727b68 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -79,6 +79,7 @@ message Event { BlockDamageEvent block_damage = 64; BlockDamageAbortEvent block_damage_abort = 65; BlockDispenseEvent block_dispense = 66; + BlockDropItemEvent block_drop_item = 67; } } diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index 842cc55..85971b8 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -19,7 +19,7 @@ use crate::java::jvm::commands::JvmCommand; use crate::proto::patchbukkit::common::{Location, Uuid, Vec3, World}; use crate::proto::patchbukkit::events::event::Data; use crate::proto::patchbukkit::events::{ - BlockBreakEvent, BlockDamageEvent, BlockDamageAbortEvent, BlockDispenseEvent, BlockPlaceEvent, BlockCanBuildEvent, BlockBurnEvent, BlockIgniteEvent, BlockSpreadEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, + BlockBreakEvent, BlockDamageEvent, BlockDamageAbortEvent, BlockDispenseEvent, BlockDropItemEntry, BlockDropItemEvent, BlockPlaceEvent, BlockCanBuildEvent, BlockBurnEvent, BlockIgniteEvent, BlockSpreadEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, PlayerLeaveEvent, PlayerMoveEvent, PlayerInteractEvent, ServerBroadcastEvent, ServerCommandEvent, EntityDamageEvent, EntityDeathEvent, EntitySpawnEvent, PlayerLoginEvent, PlayerTeleportEvent, PlayerChangeWorldEvent, PlayerGamemodeChangeEvent, @@ -2487,6 +2487,75 @@ impl PatchBukkitEvent for pumpkin::plugin::block::block_dispense::BlockDispenseE } } +impl PatchBukkitEvent for pumpkin::plugin::block::block_drop_item::BlockDropItemEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let world_uuid = self.player.world().uuid; + let location = build_location( + world_uuid, + &Vector3::new( + f64::from(self.block_position.0.x), + f64::from(self.block_position.0.y), + f64::from(self.block_position.0.z), + ), + 0.0, + 0.0, + ); + let items = self + .items + .iter() + .map(|item| BlockDropItemEntry { + item_key: item_to_key(item.item), + item_amount: i32::from(item.item_count), + }) + .collect(); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockDropItem(BlockDropItemEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + block_key: block_to_key(self.block), + location: Some(location), + items, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::BlockDropItem(event) => { + if !event.items.is_empty() { + let mut items = Vec::with_capacity(event.items.len()); + for entry in event.items { + if entry.item_key.is_empty() && entry.item_amount <= 0 { + continue; + } + let key = if entry.item_key.is_empty() { + "minecraft:air" + } else { + entry.item_key.as_str() + }; + let stack = item_stack_from_key(key, entry.item_amount.clamp(0, u8::MAX as i32) as u8); + if !stack.is_empty() { + items.push(stack); + } + } + self.items = items; + } + } + _ => {} + } + + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::block::block_place::BlockPlaceEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { let player_uuid = self.player.gameprofile.id.to_string(); diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index 1dcb33b..4edda4d 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -5,6 +5,7 @@ use pumpkin::plugin::block::block_break::BlockBreakEvent; use pumpkin::plugin::block::block_damage::BlockDamageEvent; use pumpkin::plugin::block::block_damage_abort::BlockDamageAbortEvent; use pumpkin::plugin::block::block_dispense::BlockDispenseEvent; +use pumpkin::plugin::block::block_drop_item::BlockDropItemEvent; use pumpkin::plugin::block::block_place::BlockPlaceEvent; use pumpkin::plugin::block::block_can_build::BlockCanBuildEvent; use pumpkin::plugin::block::block_burn::BlockBurnEvent; @@ -1037,6 +1038,21 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.block.BlockDropItemEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_drop_item::BlockDropItemEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.block.BlockCanBuildEvent" => { context .register_event::< @@ -2266,6 +2282,41 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let uuid = uuid::Uuid::parse_str(&block_drop_item_event_data.player_uuid?.value) + .ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let block = block_from_key(&block_drop_item_event_data.block_key); + let position = block_drop_item_event_data + .location + .and_then(|loc| loc.position) + .map(|pos| { + pumpkin_util::math::position::BlockPos::new( + pos.x as i32, + pos.y as i32, + pos.z as i32, + ) + }) + .unwrap_or_else(|| player.position().to_block_pos()); + let mut items = Vec::new(); + for entry in block_drop_item_event_data.items { + if entry.item_key.is_empty() && entry.item_amount <= 0 { + continue; + } + let key = if entry.item_key.is_empty() { + "minecraft:air" + } else { + entry.item_key.as_str() + }; + let stack = item_stack_from_key(key, entry.item_amount); + if !stack.is_empty() { + items.push(stack); + } + } + let pumpkin_event = BlockDropItemEvent::new(player, block, position, items); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } Data::BlockPlace(block_place_event_data) => { let uuid = uuid::Uuid::parse_str(&block_place_event_data.player_uuid?.value) .ok()?; From 3c4ae91541210e25435a1113b43affd020ccb6b1 Mon Sep 17 00:00:00 2001 From: yunuservices Date: Thu, 5 Feb 2026 08:38:07 +0300 Subject: [PATCH 34/56] Add BlockExplodeEvent bridge --- .../events/PatchBukkitEventFactory.java | 52 ++++++++++++++ .../events/PatchBukkitEventManager.java | 21 ++++++ proto/patchbukkit/events/block_events.proto | 12 ++++ proto/patchbukkit/events/event.proto | 1 + rust/src/events/handler.rs | 71 ++++++++++++++++++- rust/src/java/native_callbacks/events.rs | 65 +++++++++++++++++ 6 files changed, 221 insertions(+), 1 deletion(-) diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index 5ba271a..32ed3f2 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -12,6 +12,7 @@ import org.bukkit.event.block.BlockDamageEvent; import org.bukkit.event.block.BlockDispenseEvent; import org.bukkit.event.block.BlockDropItemEvent; +import org.bukkit.event.block.BlockExplodeEvent; import org.bukkit.event.block.BlockCanBuildEvent; import org.bukkit.event.block.BlockBurnEvent; import org.bukkit.event.block.BlockIgniteEvent; @@ -1158,6 +1159,42 @@ yield new PlayerStatisticIncrementEvent( yield new BlockDropItemEvent(block, player, items); } + case BLOCK_EXPLODE -> { + patchbukkit.events.BlockExplodeEvent explodeEvent = event.getBlockExplode(); + Location location = BridgeUtils.convertLocation(explodeEvent.getLocation()); + if (location == null || !(location.getWorld() instanceof PatchBukkitWorld world)) { + yield null; + } + + org.bukkit.block.Block block = PatchBukkitBlock.create( + world, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ(), + explodeEvent.getBlockKey() + ); + + java.util.List blockList = new java.util.ArrayList<>(); + for (patchbukkit.events.BlockExplodeBlockEntry entry : explodeEvent.getBlocksList()) { + Location entryLoc = BridgeUtils.convertLocation(entry.getLocation()); + if (entryLoc == null || !(entryLoc.getWorld() instanceof PatchBukkitWorld entryWorld)) { + continue; + } + String key = entry.getBlockKey().isEmpty() + ? "minecraft:air" + : entry.getBlockKey(); + org.bukkit.block.Block entryBlock = PatchBukkitBlock.create( + entryWorld, + entryLoc.getBlockX(), + entryLoc.getBlockY(), + entryLoc.getBlockZ(), + key + ); + blockList.add(entryBlock); + } + + yield new BlockExplodeEvent(block, blockList, explodeEvent.getYield()); + } case BLOCK_CAN_BUILD -> { patchbukkit.events.BlockCanBuildEvent canBuildEvent = event.getBlockCanBuild(); Player player = getPlayer(canBuildEvent.getPlayerUuid().getValue()); @@ -2201,6 +2238,21 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) } eventBuilder.setBlockDropItem(builder.build()); + } else if (event instanceof BlockExplodeEvent explodeEvent) { + var block = explodeEvent.getBlock(); + var builder = patchbukkit.events.BlockExplodeEvent.newBuilder() + .setBlockKey(block.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(block.getLocation())) + .setYield(explodeEvent.getYield()); + for (Block b : explodeEvent.blockList()) { + builder.addBlocks( + patchbukkit.events.BlockExplodeBlockEntry.newBuilder() + .setBlockKey(b.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(b.getLocation())) + .build() + ); + } + eventBuilder.setBlockExplode(builder.build()); } else if (event instanceof BlockCanBuildEvent canBuildEvent) { Block block = canBuildEvent.getBlock(); boolean canBuild = canBuildEvent.isBuildable(); 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 6db0798..4cb3697 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -39,6 +39,8 @@ import patchbukkit.events.BlockDispenseEvent; import patchbukkit.events.BlockDropItemEntry; import patchbukkit.events.BlockDropItemEvent; +import patchbukkit.events.BlockExplodeBlockEntry; +import patchbukkit.events.BlockExplodeEvent; import patchbukkit.events.BlockPlaceEvent; import patchbukkit.events.PlayerInteractEvent; import patchbukkit.events.EntitySpawnEvent; @@ -1082,6 +1084,25 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { patchbukkit.events.Event.newBuilder().setBlockDropItem(dropBuilder.build()).build() ); break; + case "org.bukkit.event.block.BlockExplodeEvent": + var explodeEvent = (org.bukkit.event.block.BlockExplodeEvent) event; + Block explodeBlock = explodeEvent.getBlock(); + var explodeBuilder = BlockExplodeEvent.newBuilder() + .setBlockKey(explodeBlock.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(explodeBlock.getLocation())) + .setYield(explodeEvent.getYield()); + for (Block b : explodeEvent.blockList()) { + explodeBuilder.addBlocks( + BlockExplodeBlockEntry.newBuilder() + .setBlockKey(b.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(b.getLocation())) + .build() + ); + } + request.setEvent( + patchbukkit.events.Event.newBuilder().setBlockExplode(explodeBuilder.build()).build() + ); + break; case "org.bukkit.event.block.BlockCanBuildEvent": var canBuildEvent = (org.bukkit.event.block.BlockCanBuildEvent) event; Block canBuildBlock = canBuildEvent.getBlock(); diff --git a/proto/patchbukkit/events/block_events.proto b/proto/patchbukkit/events/block_events.proto index 3bc85d1..782df67 100644 --- a/proto/patchbukkit/events/block_events.proto +++ b/proto/patchbukkit/events/block_events.proto @@ -49,6 +49,18 @@ message BlockDropItemEvent { repeated BlockDropItemEntry items = 4; } +message BlockExplodeBlockEntry { + string block_key = 1; + patchbukkit.common.Location location = 2; +} + +message BlockExplodeEvent { + string block_key = 1; + patchbukkit.common.Location location = 2; + float yield = 3; + repeated BlockExplodeBlockEntry blocks = 4; +} + message BlockPlaceEvent { patchbukkit.common.UUID player_uuid = 1; string block_key = 2; diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index d727b68..1445298 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -80,6 +80,7 @@ message Event { BlockDamageAbortEvent block_damage_abort = 65; BlockDispenseEvent block_dispense = 66; BlockDropItemEvent block_drop_item = 67; + BlockExplodeEvent block_explode = 68; } } diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index 85971b8..494b4e7 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -19,7 +19,7 @@ use crate::java::jvm::commands::JvmCommand; use crate::proto::patchbukkit::common::{Location, Uuid, Vec3, World}; use crate::proto::patchbukkit::events::event::Data; use crate::proto::patchbukkit::events::{ - BlockBreakEvent, BlockDamageEvent, BlockDamageAbortEvent, BlockDispenseEvent, BlockDropItemEntry, BlockDropItemEvent, BlockPlaceEvent, BlockCanBuildEvent, BlockBurnEvent, BlockIgniteEvent, BlockSpreadEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, + BlockBreakEvent, BlockDamageEvent, BlockDamageAbortEvent, BlockDispenseEvent, BlockDropItemEntry, BlockDropItemEvent, BlockExplodeBlockEntry, BlockExplodeEvent, BlockPlaceEvent, BlockCanBuildEvent, BlockBurnEvent, BlockIgniteEvent, BlockSpreadEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, PlayerLeaveEvent, PlayerMoveEvent, PlayerInteractEvent, ServerBroadcastEvent, ServerCommandEvent, EntityDamageEvent, EntityDeathEvent, EntitySpawnEvent, PlayerLoginEvent, PlayerTeleportEvent, PlayerChangeWorldEvent, PlayerGamemodeChangeEvent, @@ -2556,6 +2556,75 @@ impl PatchBukkitEvent for pumpkin::plugin::block::block_drop_item::BlockDropItem } } +impl PatchBukkitEvent for pumpkin::plugin::block::block_explode::BlockExplodeEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.block_position.0.x), + f64::from(self.block_position.0.y), + f64::from(self.block_position.0.z), + ), + 0.0, + 0.0, + ); + let blocks = self + .blocks + .iter() + .map(|pos| { + let loc = build_location( + self.world_uuid, + &Vector3::new(f64::from(pos.0.x), f64::from(pos.0.y), f64::from(pos.0.z)), + 0.0, + 0.0, + ); + BlockExplodeBlockEntry { + block_key: String::new(), + location: Some(loc), + } + }) + .collect(); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockExplode(BlockExplodeEvent { + block_key: block_to_key(self.block), + location: Some(location), + yield_: self.yield_rate, + blocks, + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::BlockExplode(event) => { + self.yield_rate = event.yield_; + if !event.blocks.is_empty() { + let mut blocks = Vec::with_capacity(event.blocks.len()); + for entry in event.blocks { + if let Some(loc) = entry.location + && let Some(pos) = location_to_vec3(loc.clone()) + { + blocks.push(pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + )); + } + } + self.blocks = blocks; + } + } + _ => {} + } + + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::block::block_place::BlockPlaceEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { let player_uuid = self.player.gameprofile.id.to_string(); diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index 4edda4d..1192693 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -6,6 +6,7 @@ use pumpkin::plugin::block::block_damage::BlockDamageEvent; use pumpkin::plugin::block::block_damage_abort::BlockDamageAbortEvent; use pumpkin::plugin::block::block_dispense::BlockDispenseEvent; use pumpkin::plugin::block::block_drop_item::BlockDropItemEvent; +use pumpkin::plugin::block::block_explode::BlockExplodeEvent; use pumpkin::plugin::block::block_place::BlockPlaceEvent; use pumpkin::plugin::block::block_can_build::BlockCanBuildEvent; use pumpkin::plugin::block::block_burn::BlockBurnEvent; @@ -1053,6 +1054,21 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.block.BlockExplodeEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_explode::BlockExplodeEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.block.BlockCanBuildEvent" => { context .register_event::< @@ -2317,6 +2333,55 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let block = block_from_key(&block_explode_event_data.block_key); + let position = block_explode_event_data + .location + .and_then(|loc| loc.position) + .map(|pos| { + pumpkin_util::math::position::BlockPos::new( + pos.x as i32, + pos.y as i32, + pos.z as i32, + ) + }) + .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); + let world_uuid = block_explode_event_data + .location + .and_then(|loc| loc.world) + .and_then(|w| w.uuid) + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) + .unwrap_or_else(|| { + context + .server + .worlds + .load() + .first() + .map(|world| world.uuid) + .unwrap_or_default() + }); + let mut blocks = Vec::new(); + for entry in block_explode_event_data.blocks { + if let Some(loc) = entry.location + && let Some(pos) = location_to_vec3(loc.clone()) + { + blocks.push(pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + )); + } + } + let pumpkin_event = BlockExplodeEvent::new( + block, + position, + world_uuid, + blocks, + block_explode_event_data.yield_, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } Data::BlockPlace(block_place_event_data) => { let uuid = uuid::Uuid::parse_str(&block_place_event_data.player_uuid?.value) .ok()?; From c79540da89e3f5cf1f69cccd8ace4b17b132b0cd Mon Sep 17 00:00:00 2001 From: yunuservices Date: Thu, 5 Feb 2026 08:44:25 +0300 Subject: [PATCH 35/56] Add BlockFadeEvent bridge --- .../events/PatchBukkitEventFactory.java | 38 +++++++++++++ .../events/PatchBukkitEventManager.java | 14 +++++ proto/patchbukkit/events/block_events.proto | 6 ++ proto/patchbukkit/events/event.proto | 1 + rust/src/events/handler.rs | 57 ++++++++++++++++++- rust/src/java/native_callbacks/events.rs | 48 ++++++++++++++++ 6 files changed, 163 insertions(+), 1 deletion(-) diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index 32ed3f2..34ddc0f 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -13,6 +13,7 @@ import org.bukkit.event.block.BlockDispenseEvent; import org.bukkit.event.block.BlockDropItemEvent; import org.bukkit.event.block.BlockExplodeEvent; +import org.bukkit.event.block.BlockFadeEvent; import org.bukkit.event.block.BlockCanBuildEvent; import org.bukkit.event.block.BlockBurnEvent; import org.bukkit.event.block.BlockIgniteEvent; @@ -1195,6 +1196,33 @@ yield new PlayerStatisticIncrementEvent( yield new BlockExplodeEvent(block, blockList, explodeEvent.getYield()); } + case BLOCK_FADE -> { + patchbukkit.events.BlockFadeEvent fadeEvent = event.getBlockFade(); + Location location = BridgeUtils.convertLocation(fadeEvent.getLocation()); + if (location == null || !(location.getWorld() instanceof PatchBukkitWorld world)) { + yield null; + } + + org.bukkit.block.Block block = PatchBukkitBlock.create( + world, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ(), + fadeEvent.getBlockKey() + ); + String newKey = fadeEvent.getNewBlockKey().isEmpty() + ? "minecraft:air" + : fadeEvent.getNewBlockKey(); + org.bukkit.block.Block newBlock = PatchBukkitBlock.create( + world, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ(), + newKey + ); + org.bukkit.block.BlockState newState = newBlock.getState(); + yield new BlockFadeEvent(block, newState); + } case BLOCK_CAN_BUILD -> { patchbukkit.events.BlockCanBuildEvent canBuildEvent = event.getBlockCanBuild(); Player player = getPlayer(canBuildEvent.getPlayerUuid().getValue()); @@ -2253,6 +2281,16 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) ); } eventBuilder.setBlockExplode(builder.build()); + } else if (event instanceof BlockFadeEvent fadeEvent) { + var block = fadeEvent.getBlock(); + var newState = fadeEvent.getNewState(); + eventBuilder.setBlockFade( + patchbukkit.events.BlockFadeEvent.newBuilder() + .setBlockKey(block.getType().getKey().toString()) + .setNewBlockKey(newState.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(block.getLocation())) + .build() + ); } else if (event instanceof BlockCanBuildEvent canBuildEvent) { Block block = canBuildEvent.getBlock(); boolean canBuild = canBuildEvent.isBuildable(); 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 4cb3697..a7967f5 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -41,6 +41,7 @@ import patchbukkit.events.BlockDropItemEvent; import patchbukkit.events.BlockExplodeBlockEntry; import patchbukkit.events.BlockExplodeEvent; +import patchbukkit.events.BlockFadeEvent; import patchbukkit.events.BlockPlaceEvent; import patchbukkit.events.PlayerInteractEvent; import patchbukkit.events.EntitySpawnEvent; @@ -1103,6 +1104,19 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { patchbukkit.events.Event.newBuilder().setBlockExplode(explodeBuilder.build()).build() ); break; + case "org.bukkit.event.block.BlockFadeEvent": + var fadeEvent = (org.bukkit.event.block.BlockFadeEvent) event; + Block fadeBlock = fadeEvent.getBlock(); + request.setEvent( + patchbukkit.events.Event.newBuilder().setBlockFade( + BlockFadeEvent.newBuilder() + .setBlockKey(fadeBlock.getType().getKey().toString()) + .setNewBlockKey(fadeEvent.getNewState().getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(fadeBlock.getLocation())) + .build() + ).build() + ); + break; case "org.bukkit.event.block.BlockCanBuildEvent": var canBuildEvent = (org.bukkit.event.block.BlockCanBuildEvent) event; Block canBuildBlock = canBuildEvent.getBlock(); diff --git a/proto/patchbukkit/events/block_events.proto b/proto/patchbukkit/events/block_events.proto index 782df67..4c90626 100644 --- a/proto/patchbukkit/events/block_events.proto +++ b/proto/patchbukkit/events/block_events.proto @@ -61,6 +61,12 @@ message BlockExplodeEvent { repeated BlockExplodeBlockEntry blocks = 4; } +message BlockFadeEvent { + string block_key = 1; + string new_block_key = 2; + patchbukkit.common.Location location = 3; +} + message BlockPlaceEvent { patchbukkit.common.UUID player_uuid = 1; string block_key = 2; diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index 1445298..6444d58 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -81,6 +81,7 @@ message Event { BlockDispenseEvent block_dispense = 66; BlockDropItemEvent block_drop_item = 67; BlockExplodeEvent block_explode = 68; + BlockFadeEvent block_fade = 69; } } diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index 494b4e7..1cd4bf2 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -19,7 +19,7 @@ use crate::java::jvm::commands::JvmCommand; use crate::proto::patchbukkit::common::{Location, Uuid, Vec3, World}; use crate::proto::patchbukkit::events::event::Data; use crate::proto::patchbukkit::events::{ - BlockBreakEvent, BlockDamageEvent, BlockDamageAbortEvent, BlockDispenseEvent, BlockDropItemEntry, BlockDropItemEvent, BlockExplodeBlockEntry, BlockExplodeEvent, BlockPlaceEvent, BlockCanBuildEvent, BlockBurnEvent, BlockIgniteEvent, BlockSpreadEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, + BlockBreakEvent, BlockDamageEvent, BlockDamageAbortEvent, BlockDispenseEvent, BlockDropItemEntry, BlockDropItemEvent, BlockExplodeBlockEntry, BlockExplodeEvent, BlockFadeEvent, BlockPlaceEvent, BlockCanBuildEvent, BlockBurnEvent, BlockIgniteEvent, BlockSpreadEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, PlayerLeaveEvent, PlayerMoveEvent, PlayerInteractEvent, ServerBroadcastEvent, ServerCommandEvent, EntityDamageEvent, EntityDeathEvent, EntitySpawnEvent, PlayerLoginEvent, PlayerTeleportEvent, PlayerChangeWorldEvent, PlayerGamemodeChangeEvent, @@ -2625,6 +2625,61 @@ impl PatchBukkitEvent for pumpkin::plugin::block::block_explode::BlockExplodeEve } } +impl PatchBukkitEvent for pumpkin::plugin::block::block_fade::BlockFadeEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockFade(BlockFadeEvent { + block_key: block_to_key(self.block), + new_block_key: block_to_key(self.new_block), + location: Some(location), + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::BlockFade(event) => { + if !event.new_block_key.is_empty() { + if let Some(block) = Block::from_name(&event.new_block_key) { + self.new_block = block; + } + } + if let Some(loc) = event.location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + } + if !event.block_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_key) { + self.block = block; + } + } + } + _ => {} + } + + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::block::block_place::BlockPlaceEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { let player_uuid = self.player.gameprofile.id.to_string(); diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index 1192693..c74ac17 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -7,6 +7,7 @@ use pumpkin::plugin::block::block_damage_abort::BlockDamageAbortEvent; use pumpkin::plugin::block::block_dispense::BlockDispenseEvent; use pumpkin::plugin::block::block_drop_item::BlockDropItemEvent; use pumpkin::plugin::block::block_explode::BlockExplodeEvent; +use pumpkin::plugin::block::block_fade::BlockFadeEvent; use pumpkin::plugin::block::block_place::BlockPlaceEvent; use pumpkin::plugin::block::block_can_build::BlockCanBuildEvent; use pumpkin::plugin::block::block_burn::BlockBurnEvent; @@ -1069,6 +1070,21 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.block.BlockFadeEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_fade::BlockFadeEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.block.BlockCanBuildEvent" => { context .register_event::< @@ -2382,6 +2398,38 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let block = block_from_key(&block_fade_event_data.block_key); + let new_block = block_from_key(&block_fade_event_data.new_block_key); + let position = block_fade_event_data + .location + .and_then(|loc| loc.position) + .map(|pos| { + pumpkin_util::math::position::BlockPos::new( + pos.x as i32, + pos.y as i32, + pos.z as i32, + ) + }) + .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); + let world_uuid = block_fade_event_data + .location + .and_then(|loc| loc.world) + .and_then(|w| w.uuid) + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) + .unwrap_or_else(|| { + context + .server + .worlds + .load() + .first() + .map(|world| world.uuid) + .unwrap_or_default() + }); + let pumpkin_event = BlockFadeEvent::new(block, new_block, position, world_uuid); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } Data::BlockPlace(block_place_event_data) => { let uuid = uuid::Uuid::parse_str(&block_place_event_data.player_uuid?.value) .ok()?; From 30c75f9fec570758cb7fa9284c0c3447d2525edf Mon Sep 17 00:00:00 2001 From: yunuservices Date: Thu, 5 Feb 2026 08:50:45 +0300 Subject: [PATCH 36/56] Add BlockFertilizeEvent bridge --- .../events/PatchBukkitEventFactory.java | 57 ++++++++++++++ .../events/PatchBukkitEventManager.java | 21 +++++ proto/patchbukkit/events/block_events.proto | 12 +++ proto/patchbukkit/events/event.proto | 1 + rust/src/events/handler.rs | 76 ++++++++++++++++++- rust/src/java/native_callbacks/events.rs | 49 ++++++++++++ 6 files changed, 215 insertions(+), 1 deletion(-) diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index 34ddc0f..ba5aaf5 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -14,6 +14,7 @@ import org.bukkit.event.block.BlockDropItemEvent; import org.bukkit.event.block.BlockExplodeEvent; import org.bukkit.event.block.BlockFadeEvent; +import org.bukkit.event.block.BlockFertilizeEvent; import org.bukkit.event.block.BlockCanBuildEvent; import org.bukkit.event.block.BlockBurnEvent; import org.bukkit.event.block.BlockIgniteEvent; @@ -1223,6 +1224,45 @@ yield new PlayerStatisticIncrementEvent( org.bukkit.block.BlockState newState = newBlock.getState(); yield new BlockFadeEvent(block, newState); } + case BLOCK_FERTILIZE -> { + patchbukkit.events.BlockFertilizeEvent fertilizeEvent = event.getBlockFertilize(); + Player player = getPlayer(fertilizeEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + + Location location = BridgeUtils.convertLocation(fertilizeEvent.getLocation()); + if (location == null || !(location.getWorld() instanceof PatchBukkitWorld world)) { + yield null; + } + + org.bukkit.block.Block block = PatchBukkitBlock.create( + world, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ(), + fertilizeEvent.getBlockKey() + ); + + java.util.List states = new java.util.ArrayList<>(); + for (patchbukkit.events.BlockFertilizeBlockEntry entry : fertilizeEvent.getBlocksList()) { + Location entryLoc = BridgeUtils.convertLocation(entry.getLocation()); + if (entryLoc == null || !(entryLoc.getWorld() instanceof PatchBukkitWorld entryWorld)) { + continue; + } + String key = entry.getBlockKey().isEmpty() + ? "minecraft:air" + : entry.getBlockKey(); + org.bukkit.block.Block entryBlock = PatchBukkitBlock.create( + entryWorld, + entryLoc.getBlockX(), + entryLoc.getBlockY(), + entryLoc.getBlockZ(), + key + ); + states.add(entryBlock.getState()); + } + + yield new BlockFertilizeEvent(block, player, states); + } case BLOCK_CAN_BUILD -> { patchbukkit.events.BlockCanBuildEvent canBuildEvent = event.getBlockCanBuild(); Player player = getPlayer(canBuildEvent.getPlayerUuid().getValue()); @@ -2291,6 +2331,23 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .setLocation(BridgeUtils.convertLocation(block.getLocation())) .build() ); + } else if (event instanceof BlockFertilizeEvent fertilizeEvent) { + var block = fertilizeEvent.getBlock(); + var builder = patchbukkit.events.BlockFertilizeEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(fertilizeEvent.getPlayer().getUniqueId().toString()) + .build()) + .setBlockKey(block.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(block.getLocation())); + for (org.bukkit.block.BlockState state : fertilizeEvent.getBlocks()) { + builder.addBlocks( + patchbukkit.events.BlockFertilizeBlockEntry.newBuilder() + .setBlockKey(state.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(state.getLocation())) + .build() + ); + } + eventBuilder.setBlockFertilize(builder.build()); } else if (event instanceof BlockCanBuildEvent canBuildEvent) { Block block = canBuildEvent.getBlock(); boolean canBuild = canBuildEvent.isBuildable(); 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 a7967f5..adba92a 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -42,6 +42,8 @@ import patchbukkit.events.BlockExplodeBlockEntry; import patchbukkit.events.BlockExplodeEvent; import patchbukkit.events.BlockFadeEvent; +import patchbukkit.events.BlockFertilizeBlockEntry; +import patchbukkit.events.BlockFertilizeEvent; import patchbukkit.events.BlockPlaceEvent; import patchbukkit.events.PlayerInteractEvent; import patchbukkit.events.EntitySpawnEvent; @@ -1117,6 +1119,25 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.block.BlockFertilizeEvent": + var fertilizeEvent = (org.bukkit.event.block.BlockFertilizeEvent) event; + Block fertilizeBlock = fertilizeEvent.getBlock(); + var fertilizeBuilder = BlockFertilizeEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(fertilizeEvent.getPlayer().getUniqueId())) + .setBlockKey(fertilizeBlock.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(fertilizeBlock.getLocation())); + for (org.bukkit.block.BlockState state : fertilizeEvent.getBlocks()) { + fertilizeBuilder.addBlocks( + BlockFertilizeBlockEntry.newBuilder() + .setBlockKey(state.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(state.getLocation())) + .build() + ); + } + request.setEvent( + patchbukkit.events.Event.newBuilder().setBlockFertilize(fertilizeBuilder.build()).build() + ); + break; case "org.bukkit.event.block.BlockCanBuildEvent": var canBuildEvent = (org.bukkit.event.block.BlockCanBuildEvent) event; Block canBuildBlock = canBuildEvent.getBlock(); diff --git a/proto/patchbukkit/events/block_events.proto b/proto/patchbukkit/events/block_events.proto index 4c90626..8d63b9e 100644 --- a/proto/patchbukkit/events/block_events.proto +++ b/proto/patchbukkit/events/block_events.proto @@ -67,6 +67,18 @@ message BlockFadeEvent { patchbukkit.common.Location location = 3; } +message BlockFertilizeBlockEntry { + string block_key = 1; + patchbukkit.common.Location location = 2; +} + +message BlockFertilizeEvent { + patchbukkit.common.UUID player_uuid = 1; + string block_key = 2; + patchbukkit.common.Location location = 3; + repeated BlockFertilizeBlockEntry blocks = 4; +} + message BlockPlaceEvent { patchbukkit.common.UUID player_uuid = 1; string block_key = 2; diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index 6444d58..3e07aa3 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -82,6 +82,7 @@ message Event { BlockDropItemEvent block_drop_item = 67; BlockExplodeEvent block_explode = 68; BlockFadeEvent block_fade = 69; + BlockFertilizeEvent block_fertilize = 70; } } diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index 1cd4bf2..d3dd68e 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -19,7 +19,7 @@ use crate::java::jvm::commands::JvmCommand; use crate::proto::patchbukkit::common::{Location, Uuid, Vec3, World}; use crate::proto::patchbukkit::events::event::Data; use crate::proto::patchbukkit::events::{ - BlockBreakEvent, BlockDamageEvent, BlockDamageAbortEvent, BlockDispenseEvent, BlockDropItemEntry, BlockDropItemEvent, BlockExplodeBlockEntry, BlockExplodeEvent, BlockFadeEvent, BlockPlaceEvent, BlockCanBuildEvent, BlockBurnEvent, BlockIgniteEvent, BlockSpreadEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, + BlockBreakEvent, BlockDamageEvent, BlockDamageAbortEvent, BlockDispenseEvent, BlockDropItemEntry, BlockDropItemEvent, BlockExplodeBlockEntry, BlockExplodeEvent, BlockFadeEvent, BlockFertilizeBlockEntry, BlockFertilizeEvent, BlockPlaceEvent, BlockCanBuildEvent, BlockBurnEvent, BlockIgniteEvent, BlockSpreadEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, PlayerLeaveEvent, PlayerMoveEvent, PlayerInteractEvent, ServerBroadcastEvent, ServerCommandEvent, EntityDamageEvent, EntityDeathEvent, EntitySpawnEvent, PlayerLoginEvent, PlayerTeleportEvent, PlayerChangeWorldEvent, PlayerGamemodeChangeEvent, @@ -2680,6 +2680,80 @@ impl PatchBukkitEvent for pumpkin::plugin::block::block_fade::BlockFadeEvent { } } +impl PatchBukkitEvent for pumpkin::plugin::block::block_fertilize::BlockFertilizeEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let world_uuid = self.player.world().uuid; + let location = build_location( + world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + let blocks = self + .blocks + .iter() + .map(|pos| { + let loc = build_location( + world_uuid, + &Vector3::new(f64::from(pos.0.x), f64::from(pos.0.y), f64::from(pos.0.z)), + 0.0, + 0.0, + ); + BlockFertilizeBlockEntry { + block_key: block_to_key(self.block), + location: Some(loc), + } + }) + .collect(); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockFertilize(BlockFertilizeEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + block_key: block_to_key(self.block), + location: Some(location), + blocks, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::BlockFertilize(event) => { + if !event.blocks.is_empty() { + let mut blocks = Vec::with_capacity(event.blocks.len()); + for entry in event.blocks { + if let Some(loc) = entry.location + && let Some(pos) = location_to_vec3(loc.clone()) + { + blocks.push(pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + )); + } + } + self.blocks = blocks; + } + } + _ => {} + } + + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::block::block_place::BlockPlaceEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { let player_uuid = self.player.gameprofile.id.to_string(); diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index c74ac17..dd7596c 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -8,6 +8,7 @@ use pumpkin::plugin::block::block_dispense::BlockDispenseEvent; use pumpkin::plugin::block::block_drop_item::BlockDropItemEvent; use pumpkin::plugin::block::block_explode::BlockExplodeEvent; use pumpkin::plugin::block::block_fade::BlockFadeEvent; +use pumpkin::plugin::block::block_fertilize::BlockFertilizeEvent; use pumpkin::plugin::block::block_place::BlockPlaceEvent; use pumpkin::plugin::block::block_can_build::BlockCanBuildEvent; use pumpkin::plugin::block::block_burn::BlockBurnEvent; @@ -1085,6 +1086,21 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.block.BlockFertilizeEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_fertilize::BlockFertilizeEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.block.BlockCanBuildEvent" => { context .register_event::< @@ -2430,6 +2446,39 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let uuid = uuid::Uuid::parse_str(&block_fertilize_event_data.player_uuid?.value) + .ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let block = block_from_key(&block_fertilize_event_data.block_key); + let position = block_fertilize_event_data + .location + .and_then(|loc| loc.position) + .map(|pos| { + pumpkin_util::math::position::BlockPos::new( + pos.x as i32, + pos.y as i32, + pos.z as i32, + ) + }) + .unwrap_or_else(|| player.position().to_block_pos()); + let mut blocks = Vec::new(); + for entry in block_fertilize_event_data.blocks { + if let Some(loc) = entry.location + && let Some(pos) = location_to_vec3(loc.clone()) + { + blocks.push(pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + )); + } + } + let pumpkin_event = + BlockFertilizeEvent::new(player, block, position, blocks); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } Data::BlockPlace(block_place_event_data) => { let uuid = uuid::Uuid::parse_str(&block_place_event_data.player_uuid?.value) .ok()?; From 2a19cbba29de077baa6d549b5bfbf4a041826eb8 Mon Sep 17 00:00:00 2001 From: yunuservices Date: Thu, 5 Feb 2026 09:04:45 +0300 Subject: [PATCH 37/56] Add BlockFormEvent bridge --- .../events/PatchBukkitEventFactory.java | 38 +++++++++++++ .../events/PatchBukkitEventManager.java | 14 +++++ proto/patchbukkit/events/block_events.proto | 6 ++ proto/patchbukkit/events/event.proto | 1 + rust/src/events/handler.rs | 57 ++++++++++++++++++- rust/src/java/native_callbacks/events.rs | 48 ++++++++++++++++ 6 files changed, 163 insertions(+), 1 deletion(-) diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index ba5aaf5..e80a198 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -15,6 +15,7 @@ import org.bukkit.event.block.BlockExplodeEvent; import org.bukkit.event.block.BlockFadeEvent; import org.bukkit.event.block.BlockFertilizeEvent; +import org.bukkit.event.block.BlockFormEvent; import org.bukkit.event.block.BlockCanBuildEvent; import org.bukkit.event.block.BlockBurnEvent; import org.bukkit.event.block.BlockIgniteEvent; @@ -1263,6 +1264,33 @@ yield new PlayerStatisticIncrementEvent( yield new BlockFertilizeEvent(block, player, states); } + case BLOCK_FORM -> { + patchbukkit.events.BlockFormEvent formEvent = event.getBlockForm(); + Location location = BridgeUtils.convertLocation(formEvent.getLocation()); + if (location == null || !(location.getWorld() instanceof PatchBukkitWorld world)) { + yield null; + } + + org.bukkit.block.Block block = PatchBukkitBlock.create( + world, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ(), + formEvent.getBlockKey() + ); + String newKey = formEvent.getNewBlockKey().isEmpty() + ? "minecraft:air" + : formEvent.getNewBlockKey(); + org.bukkit.block.Block newBlock = PatchBukkitBlock.create( + world, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ(), + newKey + ); + org.bukkit.block.BlockState newState = newBlock.getState(); + yield new BlockFormEvent(block, newState); + } case BLOCK_CAN_BUILD -> { patchbukkit.events.BlockCanBuildEvent canBuildEvent = event.getBlockCanBuild(); Player player = getPlayer(canBuildEvent.getPlayerUuid().getValue()); @@ -2348,6 +2376,16 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) ); } eventBuilder.setBlockFertilize(builder.build()); + } else if (event instanceof BlockFormEvent formEvent) { + var block = formEvent.getBlock(); + var newState = formEvent.getNewState(); + eventBuilder.setBlockForm( + patchbukkit.events.BlockFormEvent.newBuilder() + .setBlockKey(block.getType().getKey().toString()) + .setNewBlockKey(newState.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(block.getLocation())) + .build() + ); } else if (event instanceof BlockCanBuildEvent canBuildEvent) { Block block = canBuildEvent.getBlock(); boolean canBuild = canBuildEvent.isBuildable(); 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 adba92a..a0959ad 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -44,6 +44,7 @@ import patchbukkit.events.BlockFadeEvent; import patchbukkit.events.BlockFertilizeBlockEntry; import patchbukkit.events.BlockFertilizeEvent; +import patchbukkit.events.BlockFormEvent; import patchbukkit.events.BlockPlaceEvent; import patchbukkit.events.PlayerInteractEvent; import patchbukkit.events.EntitySpawnEvent; @@ -1138,6 +1139,19 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { patchbukkit.events.Event.newBuilder().setBlockFertilize(fertilizeBuilder.build()).build() ); break; + case "org.bukkit.event.block.BlockFormEvent": + var formEvent = (org.bukkit.event.block.BlockFormEvent) event; + Block formBlock = formEvent.getBlock(); + request.setEvent( + patchbukkit.events.Event.newBuilder().setBlockForm( + BlockFormEvent.newBuilder() + .setBlockKey(formBlock.getType().getKey().toString()) + .setNewBlockKey(formEvent.getNewState().getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(formBlock.getLocation())) + .build() + ).build() + ); + break; case "org.bukkit.event.block.BlockCanBuildEvent": var canBuildEvent = (org.bukkit.event.block.BlockCanBuildEvent) event; Block canBuildBlock = canBuildEvent.getBlock(); diff --git a/proto/patchbukkit/events/block_events.proto b/proto/patchbukkit/events/block_events.proto index 8d63b9e..a7e66aa 100644 --- a/proto/patchbukkit/events/block_events.proto +++ b/proto/patchbukkit/events/block_events.proto @@ -79,6 +79,12 @@ message BlockFertilizeEvent { repeated BlockFertilizeBlockEntry blocks = 4; } +message BlockFormEvent { + string block_key = 1; + string new_block_key = 2; + patchbukkit.common.Location location = 3; +} + message BlockPlaceEvent { patchbukkit.common.UUID player_uuid = 1; string block_key = 2; diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index 3e07aa3..2802037 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -83,6 +83,7 @@ message Event { BlockExplodeEvent block_explode = 68; BlockFadeEvent block_fade = 69; BlockFertilizeEvent block_fertilize = 70; + BlockFormEvent block_form = 71; } } diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index d3dd68e..2786042 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -19,7 +19,7 @@ use crate::java::jvm::commands::JvmCommand; use crate::proto::patchbukkit::common::{Location, Uuid, Vec3, World}; use crate::proto::patchbukkit::events::event::Data; use crate::proto::patchbukkit::events::{ - BlockBreakEvent, BlockDamageEvent, BlockDamageAbortEvent, BlockDispenseEvent, BlockDropItemEntry, BlockDropItemEvent, BlockExplodeBlockEntry, BlockExplodeEvent, BlockFadeEvent, BlockFertilizeBlockEntry, BlockFertilizeEvent, BlockPlaceEvent, BlockCanBuildEvent, BlockBurnEvent, BlockIgniteEvent, BlockSpreadEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, + BlockBreakEvent, BlockDamageEvent, BlockDamageAbortEvent, BlockDispenseEvent, BlockDropItemEntry, BlockDropItemEvent, BlockExplodeBlockEntry, BlockExplodeEvent, BlockFadeEvent, BlockFertilizeBlockEntry, BlockFertilizeEvent, BlockFormEvent, BlockPlaceEvent, BlockCanBuildEvent, BlockBurnEvent, BlockIgniteEvent, BlockSpreadEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, PlayerLeaveEvent, PlayerMoveEvent, PlayerInteractEvent, ServerBroadcastEvent, ServerCommandEvent, EntityDamageEvent, EntityDeathEvent, EntitySpawnEvent, PlayerLoginEvent, PlayerTeleportEvent, PlayerChangeWorldEvent, PlayerGamemodeChangeEvent, @@ -2754,6 +2754,61 @@ impl PatchBukkitEvent for pumpkin::plugin::block::block_fertilize::BlockFertiliz } } +impl PatchBukkitEvent for pumpkin::plugin::block::block_form::BlockFormEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockForm(BlockFormEvent { + block_key: block_to_key(self.old_block), + new_block_key: block_to_key(self.new_block), + location: Some(location), + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::BlockForm(event) => { + if !event.new_block_key.is_empty() { + if let Some(block) = Block::from_name(&event.new_block_key) { + self.new_block = block; + } + } + if let Some(loc) = event.location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + } + if !event.block_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_key) { + self.old_block = block; + } + } + } + _ => {} + } + + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::block::block_place::BlockPlaceEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { let player_uuid = self.player.gameprofile.id.to_string(); diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index dd7596c..63ec82f 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -9,6 +9,7 @@ use pumpkin::plugin::block::block_drop_item::BlockDropItemEvent; use pumpkin::plugin::block::block_explode::BlockExplodeEvent; use pumpkin::plugin::block::block_fade::BlockFadeEvent; use pumpkin::plugin::block::block_fertilize::BlockFertilizeEvent; +use pumpkin::plugin::block::block_form::BlockFormEvent; use pumpkin::plugin::block::block_place::BlockPlaceEvent; use pumpkin::plugin::block::block_can_build::BlockCanBuildEvent; use pumpkin::plugin::block::block_burn::BlockBurnEvent; @@ -1101,6 +1102,21 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.block.BlockFormEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_form::BlockFormEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.block.BlockCanBuildEvent" => { context .register_event::< @@ -2479,6 +2495,38 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let old_block = block_from_key(&block_form_event_data.block_key); + let new_block = block_from_key(&block_form_event_data.new_block_key); + let position = block_form_event_data + .location + .and_then(|loc| loc.position) + .map(|pos| { + pumpkin_util::math::position::BlockPos::new( + pos.x as i32, + pos.y as i32, + pos.z as i32, + ) + }) + .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); + let world_uuid = block_form_event_data + .location + .and_then(|loc| loc.world) + .and_then(|w| w.uuid) + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) + .unwrap_or_else(|| { + context + .server + .worlds + .load() + .first() + .map(|world| world.uuid) + .unwrap_or_default() + }); + let pumpkin_event = BlockFormEvent::new(old_block, new_block, position, world_uuid); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } Data::BlockPlace(block_place_event_data) => { let uuid = uuid::Uuid::parse_str(&block_place_event_data.player_uuid?.value) .ok()?; From 1bf504bf23ece463419cfd9a715b5a63f673bcfd Mon Sep 17 00:00:00 2001 From: yunuservices Date: Thu, 5 Feb 2026 09:14:10 +0300 Subject: [PATCH 38/56] Add BlockFromToEvent bridge --- .../events/PatchBukkitEventFactory.java | 41 ++++++++++ .../events/PatchBukkitEventManager.java | 18 +++++ proto/patchbukkit/events/block_events.proto | 8 ++ proto/patchbukkit/events/event.proto | 1 + rust/src/events/handler.rs | 81 ++++++++++++++++++- rust/src/java/native_callbacks/events.rs | 72 +++++++++++++++++ 6 files changed, 220 insertions(+), 1 deletion(-) diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index e80a198..5f52ad4 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -16,6 +16,7 @@ import org.bukkit.event.block.BlockFadeEvent; import org.bukkit.event.block.BlockFertilizeEvent; import org.bukkit.event.block.BlockFormEvent; +import org.bukkit.event.block.BlockFromToEvent; import org.bukkit.event.block.BlockCanBuildEvent; import org.bukkit.event.block.BlockBurnEvent; import org.bukkit.event.block.BlockIgniteEvent; @@ -1291,6 +1292,33 @@ yield new PlayerStatisticIncrementEvent( org.bukkit.block.BlockState newState = newBlock.getState(); yield new BlockFormEvent(block, newState); } + case BLOCK_FROM_TO -> { + patchbukkit.events.BlockFromToEvent fromToEvent = event.getBlockFromTo(); + Location location = BridgeUtils.convertLocation(fromToEvent.getLocation()); + Location toLocation = BridgeUtils.convertLocation(fromToEvent.getToLocation()); + if (location == null || toLocation == null) yield null; + if (!(location.getWorld() instanceof PatchBukkitWorld world)) yield null; + if (!(toLocation.getWorld() instanceof PatchBukkitWorld toWorld)) yield null; + + org.bukkit.block.Block block = PatchBukkitBlock.create( + world, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ(), + fromToEvent.getBlockKey() + ); + String toKey = fromToEvent.getToBlockKey().isEmpty() + ? "minecraft:air" + : fromToEvent.getToBlockKey(); + org.bukkit.block.Block toBlock = PatchBukkitBlock.create( + toWorld, + toLocation.getBlockX(), + toLocation.getBlockY(), + toLocation.getBlockZ(), + toKey + ); + yield new BlockFromToEvent(block, toBlock); + } case BLOCK_CAN_BUILD -> { patchbukkit.events.BlockCanBuildEvent canBuildEvent = event.getBlockCanBuild(); Player player = getPlayer(canBuildEvent.getPlayerUuid().getValue()); @@ -2386,6 +2414,19 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .setLocation(BridgeUtils.convertLocation(block.getLocation())) .build() ); + } else if (event instanceof BlockFromToEvent fromToEvent) { + var block = fromToEvent.getBlock(); + var toBlock = fromToEvent.getToBlock(); + String face = fromToEvent.getFace() != null ? fromToEvent.getFace().name() : ""; + eventBuilder.setBlockFromTo( + patchbukkit.events.BlockFromToEvent.newBuilder() + .setBlockKey(block.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(block.getLocation())) + .setToBlockKey(toBlock.getType().getKey().toString()) + .setToLocation(BridgeUtils.convertLocation(toBlock.getLocation())) + .setFace(face) + .build() + ); } else if (event instanceof BlockCanBuildEvent canBuildEvent) { Block block = canBuildEvent.getBlock(); boolean canBuild = canBuildEvent.isBuildable(); 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 a0959ad..0351d1d 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -45,6 +45,7 @@ import patchbukkit.events.BlockFertilizeBlockEntry; import patchbukkit.events.BlockFertilizeEvent; import patchbukkit.events.BlockFormEvent; +import patchbukkit.events.BlockFromToEvent; import patchbukkit.events.BlockPlaceEvent; import patchbukkit.events.PlayerInteractEvent; import patchbukkit.events.EntitySpawnEvent; @@ -1152,6 +1153,23 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.block.BlockFromToEvent": + var fromToEvent = (org.bukkit.event.block.BlockFromToEvent) event; + Block fromBlock = fromToEvent.getBlock(); + Block toBlock = fromToEvent.getToBlock(); + String face = fromToEvent.getFace() != null ? fromToEvent.getFace().name() : ""; + request.setEvent( + patchbukkit.events.Event.newBuilder().setBlockFromTo( + BlockFromToEvent.newBuilder() + .setBlockKey(fromBlock.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(fromBlock.getLocation())) + .setToBlockKey(toBlock.getType().getKey().toString()) + .setToLocation(BridgeUtils.convertLocation(toBlock.getLocation())) + .setFace(face) + .build() + ).build() + ); + break; case "org.bukkit.event.block.BlockCanBuildEvent": var canBuildEvent = (org.bukkit.event.block.BlockCanBuildEvent) event; Block canBuildBlock = canBuildEvent.getBlock(); diff --git a/proto/patchbukkit/events/block_events.proto b/proto/patchbukkit/events/block_events.proto index a7e66aa..3c67432 100644 --- a/proto/patchbukkit/events/block_events.proto +++ b/proto/patchbukkit/events/block_events.proto @@ -85,6 +85,14 @@ message BlockFormEvent { patchbukkit.common.Location location = 3; } +message BlockFromToEvent { + string block_key = 1; + patchbukkit.common.Location location = 2; + string to_block_key = 3; + patchbukkit.common.Location to_location = 4; + string face = 5; +} + message BlockPlaceEvent { patchbukkit.common.UUID player_uuid = 1; string block_key = 2; diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index 2802037..a97872b 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -84,6 +84,7 @@ message Event { BlockFadeEvent block_fade = 69; BlockFertilizeEvent block_fertilize = 70; BlockFormEvent block_form = 71; + BlockFromToEvent block_from_to = 72; } } diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index 2786042..5ccd518 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -19,7 +19,7 @@ use crate::java::jvm::commands::JvmCommand; use crate::proto::patchbukkit::common::{Location, Uuid, Vec3, World}; use crate::proto::patchbukkit::events::event::Data; use crate::proto::patchbukkit::events::{ - BlockBreakEvent, BlockDamageEvent, BlockDamageAbortEvent, BlockDispenseEvent, BlockDropItemEntry, BlockDropItemEvent, BlockExplodeBlockEntry, BlockExplodeEvent, BlockFadeEvent, BlockFertilizeBlockEntry, BlockFertilizeEvent, BlockFormEvent, BlockPlaceEvent, BlockCanBuildEvent, BlockBurnEvent, BlockIgniteEvent, BlockSpreadEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, + BlockBreakEvent, BlockDamageEvent, BlockDamageAbortEvent, BlockDispenseEvent, BlockDropItemEntry, BlockDropItemEvent, BlockExplodeBlockEntry, BlockExplodeEvent, BlockFadeEvent, BlockFertilizeBlockEntry, BlockFertilizeEvent, BlockFormEvent, BlockFromToEvent, BlockPlaceEvent, BlockCanBuildEvent, BlockBurnEvent, BlockIgniteEvent, BlockSpreadEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, PlayerLeaveEvent, PlayerMoveEvent, PlayerInteractEvent, ServerBroadcastEvent, ServerCommandEvent, EntityDamageEvent, EntityDeathEvent, EntitySpawnEvent, PlayerLoginEvent, PlayerTeleportEvent, PlayerChangeWorldEvent, PlayerGamemodeChangeEvent, @@ -2809,6 +2809,85 @@ impl PatchBukkitEvent for pumpkin::plugin::block::block_form::BlockFormEvent { } } +impl PatchBukkitEvent for pumpkin::plugin::block::block_from_to::BlockFromToEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + let to_location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.to_pos.0.x), + f64::from(self.to_pos.0.y), + f64::from(self.to_pos.0.z), + ), + 0.0, + 0.0, + ); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockFromTo(BlockFromToEvent { + block_key: block_to_key(self.block), + location: Some(location), + to_block_key: block_to_key(self.to_block), + to_location: Some(to_location), + face: block_face_to_bukkit(Some(self.face)), + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::BlockFromTo(event) => { + if !event.to_block_key.is_empty() { + if let Some(block) = Block::from_name(&event.to_block_key) { + self.to_block = block; + } + } + if let Some(loc) = event.to_location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.to_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + } + if let Some(face) = bukkit_block_face_from_string(&event.face) { + self.face = face; + } + if !event.block_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_key) { + self.block = block; + } + } + if let Some(loc) = event.location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + } + } + _ => {} + } + + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::block::block_place::BlockPlaceEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { let player_uuid = self.player.gameprofile.id.to_string(); diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index 63ec82f..97c857b 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -10,6 +10,7 @@ use pumpkin::plugin::block::block_explode::BlockExplodeEvent; use pumpkin::plugin::block::block_fade::BlockFadeEvent; use pumpkin::plugin::block::block_fertilize::BlockFertilizeEvent; use pumpkin::plugin::block::block_form::BlockFormEvent; +use pumpkin::plugin::block::block_from_to::BlockFromToEvent; use pumpkin::plugin::block::block_place::BlockPlaceEvent; use pumpkin::plugin::block::block_can_build::BlockCanBuildEvent; use pumpkin::plugin::block::block_burn::BlockBurnEvent; @@ -1117,6 +1118,23 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.block.BlockFromToEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_from_to::BlockFromToEvent, + PatchBukkitEventHandler< + pumpkin::plugin::block::block_from_to::BlockFromToEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.block.BlockCanBuildEvent" => { context .register_event::< @@ -2527,6 +2545,60 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let block = block_from_key(&block_from_to_event_data.block_key); + let to_block = block_from_key(&block_from_to_event_data.to_block_key); + let position = block_from_to_event_data + .location + .and_then(|loc| loc.position) + .map(|pos| { + pumpkin_util::math::position::BlockPos::new( + pos.x as i32, + pos.y as i32, + pos.z as i32, + ) + }) + .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); + let to_position = block_from_to_event_data + .to_location + .and_then(|loc| loc.position) + .map(|pos| { + pumpkin_util::math::position::BlockPos::new( + pos.x as i32, + pos.y as i32, + pos.z as i32, + ) + }) + .unwrap_or_else(|| position); + let world_uuid = block_from_to_event_data + .location + .and_then(|loc| loc.world) + .and_then(|w| w.uuid) + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) + .unwrap_or_else(|| { + context + .server + .worlds + .load() + .first() + .map(|world| world.uuid) + .unwrap_or_default() + }); + let face = + bukkit_block_face_to_direction(&block_from_to_event_data.face).unwrap_or( + BlockDirection::Down, + ); + let pumpkin_event = BlockFromToEvent::new( + block, + position, + to_block, + to_position, + face, + world_uuid, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } Data::BlockPlace(block_place_event_data) => { let uuid = uuid::Uuid::parse_str(&block_place_event_data.player_uuid?.value) .ok()?; From b92b5bd3da8a7b757d6bf5c966a23d104cda82a8 Mon Sep 17 00:00:00 2001 From: yunuservices Date: Thu, 5 Feb 2026 09:23:27 +0300 Subject: [PATCH 39/56] Add BlockGrowEvent bridge --- .../events/PatchBukkitEventFactory.java | 38 +++++++++++++ .../events/PatchBukkitEventManager.java | 14 +++++ proto/patchbukkit/events/block_events.proto | 6 ++ proto/patchbukkit/events/event.proto | 1 + rust/src/events/handler.rs | 57 ++++++++++++++++++- rust/src/java/native_callbacks/events.rs | 48 ++++++++++++++++ 6 files changed, 163 insertions(+), 1 deletion(-) diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index 5f52ad4..9b991db 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -17,6 +17,7 @@ import org.bukkit.event.block.BlockFertilizeEvent; import org.bukkit.event.block.BlockFormEvent; import org.bukkit.event.block.BlockFromToEvent; +import org.bukkit.event.block.BlockGrowEvent; import org.bukkit.event.block.BlockCanBuildEvent; import org.bukkit.event.block.BlockBurnEvent; import org.bukkit.event.block.BlockIgniteEvent; @@ -1319,6 +1320,33 @@ yield new PlayerStatisticIncrementEvent( ); yield new BlockFromToEvent(block, toBlock); } + case BLOCK_GROW -> { + patchbukkit.events.BlockGrowEvent growEvent = event.getBlockGrow(); + Location location = BridgeUtils.convertLocation(growEvent.getLocation()); + if (location == null || !(location.getWorld() instanceof PatchBukkitWorld world)) { + yield null; + } + + org.bukkit.block.Block block = PatchBukkitBlock.create( + world, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ(), + growEvent.getBlockKey() + ); + String newKey = growEvent.getNewBlockKey().isEmpty() + ? "minecraft:air" + : growEvent.getNewBlockKey(); + org.bukkit.block.Block newBlock = PatchBukkitBlock.create( + world, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ(), + newKey + ); + org.bukkit.block.BlockState newState = newBlock.getState(); + yield new BlockGrowEvent(block, newState); + } case BLOCK_CAN_BUILD -> { patchbukkit.events.BlockCanBuildEvent canBuildEvent = event.getBlockCanBuild(); Player player = getPlayer(canBuildEvent.getPlayerUuid().getValue()); @@ -2427,6 +2455,16 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .setFace(face) .build() ); + } else if (event instanceof BlockGrowEvent growEvent) { + var block = growEvent.getBlock(); + var newState = growEvent.getNewState(); + eventBuilder.setBlockGrow( + patchbukkit.events.BlockGrowEvent.newBuilder() + .setBlockKey(block.getType().getKey().toString()) + .setNewBlockKey(newState.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(block.getLocation())) + .build() + ); } else if (event instanceof BlockCanBuildEvent canBuildEvent) { Block block = canBuildEvent.getBlock(); boolean canBuild = canBuildEvent.isBuildable(); 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 0351d1d..0dc347c 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -46,6 +46,7 @@ import patchbukkit.events.BlockFertilizeEvent; import patchbukkit.events.BlockFormEvent; import patchbukkit.events.BlockFromToEvent; +import patchbukkit.events.BlockGrowEvent; import patchbukkit.events.BlockPlaceEvent; import patchbukkit.events.PlayerInteractEvent; import patchbukkit.events.EntitySpawnEvent; @@ -1170,6 +1171,19 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.block.BlockGrowEvent": + var growEvent = (org.bukkit.event.block.BlockGrowEvent) event; + Block growBlock = growEvent.getBlock(); + request.setEvent( + patchbukkit.events.Event.newBuilder().setBlockGrow( + BlockGrowEvent.newBuilder() + .setBlockKey(growBlock.getType().getKey().toString()) + .setNewBlockKey(growEvent.getNewState().getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(growBlock.getLocation())) + .build() + ).build() + ); + break; case "org.bukkit.event.block.BlockCanBuildEvent": var canBuildEvent = (org.bukkit.event.block.BlockCanBuildEvent) event; Block canBuildBlock = canBuildEvent.getBlock(); diff --git a/proto/patchbukkit/events/block_events.proto b/proto/patchbukkit/events/block_events.proto index 3c67432..5f398ec 100644 --- a/proto/patchbukkit/events/block_events.proto +++ b/proto/patchbukkit/events/block_events.proto @@ -93,6 +93,12 @@ message BlockFromToEvent { string face = 5; } +message BlockGrowEvent { + string block_key = 1; + string new_block_key = 2; + patchbukkit.common.Location location = 3; +} + message BlockPlaceEvent { patchbukkit.common.UUID player_uuid = 1; string block_key = 2; diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index a97872b..a7ae52a 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -85,6 +85,7 @@ message Event { BlockFertilizeEvent block_fertilize = 70; BlockFormEvent block_form = 71; BlockFromToEvent block_from_to = 72; + BlockGrowEvent block_grow = 73; } } diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index 5ccd518..9fd36d5 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -19,7 +19,7 @@ use crate::java::jvm::commands::JvmCommand; use crate::proto::patchbukkit::common::{Location, Uuid, Vec3, World}; use crate::proto::patchbukkit::events::event::Data; use crate::proto::patchbukkit::events::{ - BlockBreakEvent, BlockDamageEvent, BlockDamageAbortEvent, BlockDispenseEvent, BlockDropItemEntry, BlockDropItemEvent, BlockExplodeBlockEntry, BlockExplodeEvent, BlockFadeEvent, BlockFertilizeBlockEntry, BlockFertilizeEvent, BlockFormEvent, BlockFromToEvent, BlockPlaceEvent, BlockCanBuildEvent, BlockBurnEvent, BlockIgniteEvent, BlockSpreadEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, + BlockBreakEvent, BlockDamageEvent, BlockDamageAbortEvent, BlockDispenseEvent, BlockDropItemEntry, BlockDropItemEvent, BlockExplodeBlockEntry, BlockExplodeEvent, BlockFadeEvent, BlockFertilizeBlockEntry, BlockFertilizeEvent, BlockFormEvent, BlockFromToEvent, BlockGrowEvent, BlockPlaceEvent, BlockCanBuildEvent, BlockBurnEvent, BlockIgniteEvent, BlockSpreadEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, PlayerLeaveEvent, PlayerMoveEvent, PlayerInteractEvent, ServerBroadcastEvent, ServerCommandEvent, EntityDamageEvent, EntityDeathEvent, EntitySpawnEvent, PlayerLoginEvent, PlayerTeleportEvent, PlayerChangeWorldEvent, PlayerGamemodeChangeEvent, @@ -2888,6 +2888,61 @@ impl PatchBukkitEvent for pumpkin::plugin::block::block_from_to::BlockFromToEven } } +impl PatchBukkitEvent for pumpkin::plugin::block::block_grow::BlockGrowEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockGrow(BlockGrowEvent { + block_key: block_to_key(self.block), + new_block_key: block_to_key(self.new_block), + location: Some(location), + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::BlockGrow(event) => { + if !event.new_block_key.is_empty() { + if let Some(block) = Block::from_name(&event.new_block_key) { + self.new_block = block; + } + } + if let Some(loc) = event.location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + } + if !event.block_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_key) { + self.block = block; + } + } + } + _ => {} + } + + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::block::block_place::BlockPlaceEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { let player_uuid = self.player.gameprofile.id.to_string(); diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index 97c857b..3265fab 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -11,6 +11,7 @@ use pumpkin::plugin::block::block_fade::BlockFadeEvent; use pumpkin::plugin::block::block_fertilize::BlockFertilizeEvent; use pumpkin::plugin::block::block_form::BlockFormEvent; use pumpkin::plugin::block::block_from_to::BlockFromToEvent; +use pumpkin::plugin::block::block_grow::BlockGrowEvent; use pumpkin::plugin::block::block_place::BlockPlaceEvent; use pumpkin::plugin::block::block_can_build::BlockCanBuildEvent; use pumpkin::plugin::block::block_burn::BlockBurnEvent; @@ -1135,6 +1136,21 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.block.BlockGrowEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_grow::BlockGrowEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.block.BlockCanBuildEvent" => { context .register_event::< @@ -2599,6 +2615,38 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let block = block_from_key(&block_grow_event_data.block_key); + let new_block = block_from_key(&block_grow_event_data.new_block_key); + let position = block_grow_event_data + .location + .and_then(|loc| loc.position) + .map(|pos| { + pumpkin_util::math::position::BlockPos::new( + pos.x as i32, + pos.y as i32, + pos.z as i32, + ) + }) + .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); + let world_uuid = block_grow_event_data + .location + .and_then(|loc| loc.world) + .and_then(|w| w.uuid) + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) + .unwrap_or_else(|| { + context + .server + .worlds + .load() + .first() + .map(|world| world.uuid) + .unwrap_or_default() + }); + let pumpkin_event = BlockGrowEvent::new(block, new_block, position, world_uuid); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } Data::BlockPlace(block_place_event_data) => { let uuid = uuid::Uuid::parse_str(&block_place_event_data.player_uuid?.value) .ok()?; From a619e38896114859161e385ce2e99f97425680f8 Mon Sep 17 00:00:00 2001 From: yunuservices Date: Thu, 5 Feb 2026 09:29:26 +0300 Subject: [PATCH 40/56] Add piston extend/retract events bridge --- .../events/PatchBukkitEventFactory.java | 102 +++++++++++++ .../events/PatchBukkitEventManager.java | 45 ++++++ proto/patchbukkit/events/block_events.proto | 21 +++ proto/patchbukkit/events/event.proto | 2 + rust/src/events/handler.rs | 110 +++++++++++++- rust/src/java/native_callbacks/events.rs | 142 ++++++++++++++++++ 6 files changed, 421 insertions(+), 1 deletion(-) diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index 9b991db..ee74e17 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -18,6 +18,8 @@ import org.bukkit.event.block.BlockFormEvent; import org.bukkit.event.block.BlockFromToEvent; import org.bukkit.event.block.BlockGrowEvent; +import org.bukkit.event.block.BlockPistonExtendEvent; +import org.bukkit.event.block.BlockPistonRetractEvent; import org.bukkit.event.block.BlockCanBuildEvent; import org.bukkit.event.block.BlockBurnEvent; import org.bukkit.event.block.BlockIgniteEvent; @@ -1347,6 +1349,72 @@ yield new PlayerStatisticIncrementEvent( org.bukkit.block.BlockState newState = newBlock.getState(); yield new BlockGrowEvent(block, newState); } + case BLOCK_PISTON_EXTEND -> { + patchbukkit.events.BlockPistonExtendEvent extendEvent = event.getBlockPistonExtend(); + Location location = BridgeUtils.convertLocation(extendEvent.getLocation()); + if (location == null || !(location.getWorld() instanceof PatchBukkitWorld world)) { + yield null; + } + org.bukkit.block.Block block = PatchBukkitBlock.create( + world, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ(), + extendEvent.getBlockKey() + ); + java.util.List blocks = new java.util.ArrayList<>(); + for (patchbukkit.events.BlockPistonBlockEntry entry : extendEvent.getBlocksList()) { + Location entryLoc = BridgeUtils.convertLocation(entry.getLocation()); + if (entryLoc == null || !(entryLoc.getWorld() instanceof PatchBukkitWorld entryWorld)) { + continue; + } + String key = entry.getBlockKey().isEmpty() + ? "minecraft:air" + : entry.getBlockKey(); + org.bukkit.block.Block entryBlock = PatchBukkitBlock.create( + entryWorld, + entryLoc.getBlockX(), + entryLoc.getBlockY(), + entryLoc.getBlockZ(), + key + ); + blocks.add(entryBlock); + } + yield new BlockPistonExtendEvent(block, blocks, extendEvent.getLength()); + } + case BLOCK_PISTON_RETRACT -> { + patchbukkit.events.BlockPistonRetractEvent retractEvent = event.getBlockPistonRetract(); + Location location = BridgeUtils.convertLocation(retractEvent.getLocation()); + if (location == null || !(location.getWorld() instanceof PatchBukkitWorld world)) { + yield null; + } + org.bukkit.block.Block block = PatchBukkitBlock.create( + world, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ(), + retractEvent.getBlockKey() + ); + java.util.List blocks = new java.util.ArrayList<>(); + for (patchbukkit.events.BlockPistonBlockEntry entry : retractEvent.getBlocksList()) { + Location entryLoc = BridgeUtils.convertLocation(entry.getLocation()); + if (entryLoc == null || !(entryLoc.getWorld() instanceof PatchBukkitWorld entryWorld)) { + continue; + } + String key = entry.getBlockKey().isEmpty() + ? "minecraft:air" + : entry.getBlockKey(); + org.bukkit.block.Block entryBlock = PatchBukkitBlock.create( + entryWorld, + entryLoc.getBlockX(), + entryLoc.getBlockY(), + entryLoc.getBlockZ(), + key + ); + blocks.add(entryBlock); + } + yield new BlockPistonRetractEvent(block, blocks, retractEvent.getLength()); + } case BLOCK_CAN_BUILD -> { patchbukkit.events.BlockCanBuildEvent canBuildEvent = event.getBlockCanBuild(); Player player = getPlayer(canBuildEvent.getPlayerUuid().getValue()); @@ -2465,6 +2533,40 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .setLocation(BridgeUtils.convertLocation(block.getLocation())) .build() ); + } else if (event instanceof BlockPistonExtendEvent extendEvent) { + var block = extendEvent.getBlock(); + String direction = extendEvent.getDirection() != null ? extendEvent.getDirection().name() : ""; + var builder = patchbukkit.events.BlockPistonExtendEvent.newBuilder() + .setBlockKey(block.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(block.getLocation())) + .setDirection(direction) + .setLength(extendEvent.getLength()); + for (Block b : extendEvent.getBlocks()) { + builder.addBlocks( + patchbukkit.events.BlockPistonBlockEntry.newBuilder() + .setBlockKey(b.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(b.getLocation())) + .build() + ); + } + eventBuilder.setBlockPistonExtend(builder.build()); + } else if (event instanceof BlockPistonRetractEvent retractEvent) { + var block = retractEvent.getBlock(); + String direction = retractEvent.getDirection() != null ? retractEvent.getDirection().name() : ""; + var builder = patchbukkit.events.BlockPistonRetractEvent.newBuilder() + .setBlockKey(block.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(block.getLocation())) + .setDirection(direction) + .setLength(retractEvent.getLength()); + for (Block b : retractEvent.getBlocks()) { + builder.addBlocks( + patchbukkit.events.BlockPistonBlockEntry.newBuilder() + .setBlockKey(b.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(b.getLocation())) + .build() + ); + } + eventBuilder.setBlockPistonRetract(builder.build()); } else if (event instanceof BlockCanBuildEvent canBuildEvent) { Block block = canBuildEvent.getBlock(); boolean canBuild = canBuildEvent.isBuildable(); 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 0dc347c..4c12fcc 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -47,6 +47,9 @@ import patchbukkit.events.BlockFormEvent; import patchbukkit.events.BlockFromToEvent; import patchbukkit.events.BlockGrowEvent; +import patchbukkit.events.BlockPistonBlockEntry; +import patchbukkit.events.BlockPistonExtendEvent; +import patchbukkit.events.BlockPistonRetractEvent; import patchbukkit.events.BlockPlaceEvent; import patchbukkit.events.PlayerInteractEvent; import patchbukkit.events.EntitySpawnEvent; @@ -1184,6 +1187,48 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.block.BlockPistonExtendEvent": + var extendEvent = (org.bukkit.event.block.BlockPistonExtendEvent) event; + Block extendBlock = extendEvent.getBlock(); + String extendDir = extendEvent.getDirection() != null ? extendEvent.getDirection().name() : ""; + var extendBuilder = BlockPistonExtendEvent.newBuilder() + .setBlockKey(extendBlock.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(extendBlock.getLocation())) + .setDirection(extendDir) + .setLength(extendEvent.getLength()); + for (Block b : extendEvent.getBlocks()) { + extendBuilder.addBlocks( + BlockPistonBlockEntry.newBuilder() + .setBlockKey(b.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(b.getLocation())) + .build() + ); + } + request.setEvent( + patchbukkit.events.Event.newBuilder().setBlockPistonExtend(extendBuilder.build()).build() + ); + break; + case "org.bukkit.event.block.BlockPistonRetractEvent": + var retractEvent = (org.bukkit.event.block.BlockPistonRetractEvent) event; + Block retractBlock = retractEvent.getBlock(); + String retractDir = retractEvent.getDirection() != null ? retractEvent.getDirection().name() : ""; + var retractBuilder = BlockPistonRetractEvent.newBuilder() + .setBlockKey(retractBlock.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(retractBlock.getLocation())) + .setDirection(retractDir) + .setLength(retractEvent.getLength()); + for (Block b : retractEvent.getBlocks()) { + retractBuilder.addBlocks( + BlockPistonBlockEntry.newBuilder() + .setBlockKey(b.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(b.getLocation())) + .build() + ); + } + request.setEvent( + patchbukkit.events.Event.newBuilder().setBlockPistonRetract(retractBuilder.build()).build() + ); + break; case "org.bukkit.event.block.BlockCanBuildEvent": var canBuildEvent = (org.bukkit.event.block.BlockCanBuildEvent) event; Block canBuildBlock = canBuildEvent.getBlock(); diff --git a/proto/patchbukkit/events/block_events.proto b/proto/patchbukkit/events/block_events.proto index 5f398ec..e58f6d7 100644 --- a/proto/patchbukkit/events/block_events.proto +++ b/proto/patchbukkit/events/block_events.proto @@ -99,6 +99,27 @@ message BlockGrowEvent { patchbukkit.common.Location location = 3; } +message BlockPistonBlockEntry { + string block_key = 1; + patchbukkit.common.Location location = 2; +} + +message BlockPistonExtendEvent { + string block_key = 1; + patchbukkit.common.Location location = 2; + string direction = 3; + int32 length = 4; + repeated BlockPistonBlockEntry blocks = 5; +} + +message BlockPistonRetractEvent { + string block_key = 1; + patchbukkit.common.Location location = 2; + string direction = 3; + int32 length = 4; + repeated BlockPistonBlockEntry blocks = 5; +} + message BlockPlaceEvent { patchbukkit.common.UUID player_uuid = 1; string block_key = 2; diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index a7ae52a..e71e2ba 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -86,6 +86,8 @@ message Event { BlockFormEvent block_form = 71; BlockFromToEvent block_from_to = 72; BlockGrowEvent block_grow = 73; + BlockPistonExtendEvent block_piston_extend = 74; + BlockPistonRetractEvent block_piston_retract = 75; } } diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index 9fd36d5..a5fe303 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -19,7 +19,7 @@ use crate::java::jvm::commands::JvmCommand; use crate::proto::patchbukkit::common::{Location, Uuid, Vec3, World}; use crate::proto::patchbukkit::events::event::Data; use crate::proto::patchbukkit::events::{ - BlockBreakEvent, BlockDamageEvent, BlockDamageAbortEvent, BlockDispenseEvent, BlockDropItemEntry, BlockDropItemEvent, BlockExplodeBlockEntry, BlockExplodeEvent, BlockFadeEvent, BlockFertilizeBlockEntry, BlockFertilizeEvent, BlockFormEvent, BlockFromToEvent, BlockGrowEvent, BlockPlaceEvent, BlockCanBuildEvent, BlockBurnEvent, BlockIgniteEvent, BlockSpreadEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, + BlockBreakEvent, BlockDamageEvent, BlockDamageAbortEvent, BlockDispenseEvent, BlockDropItemEntry, BlockDropItemEvent, BlockExplodeBlockEntry, BlockExplodeEvent, BlockFadeEvent, BlockFertilizeBlockEntry, BlockFertilizeEvent, BlockFormEvent, BlockFromToEvent, BlockGrowEvent, BlockPistonBlockEntry, BlockPistonExtendEvent, BlockPistonRetractEvent, BlockPlaceEvent, BlockCanBuildEvent, BlockBurnEvent, BlockIgniteEvent, BlockSpreadEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, PlayerLeaveEvent, PlayerMoveEvent, PlayerInteractEvent, ServerBroadcastEvent, ServerCommandEvent, EntityDamageEvent, EntityDeathEvent, EntitySpawnEvent, PlayerLoginEvent, PlayerTeleportEvent, PlayerChangeWorldEvent, PlayerGamemodeChangeEvent, @@ -2943,6 +2943,114 @@ impl PatchBukkitEvent for pumpkin::plugin::block::block_grow::BlockGrowEvent { } } +impl PatchBukkitEvent for pumpkin::plugin::block::block_piston_extend::BlockPistonExtendEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + let blocks = self + .blocks + .iter() + .map(|pos| { + let loc = build_location( + self.world_uuid, + &Vector3::new(f64::from(pos.0.x), f64::from(pos.0.y), f64::from(pos.0.z)), + 0.0, + 0.0, + ); + BlockPistonBlockEntry { + block_key: String::new(), + location: Some(loc), + } + }) + .collect(); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockPistonExtend(BlockPistonExtendEvent { + block_key: block_to_key(self.block), + location: Some(location), + direction: block_face_to_bukkit(Some(self.direction)), + length: self.length, + blocks, + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::BlockPistonExtend(event) => { + self.length = event.length; + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::block::block_piston_retract::BlockPistonRetractEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + let blocks = self + .blocks + .iter() + .map(|pos| { + let loc = build_location( + self.world_uuid, + &Vector3::new(f64::from(pos.0.x), f64::from(pos.0.y), f64::from(pos.0.z)), + 0.0, + 0.0, + ); + BlockPistonBlockEntry { + block_key: String::new(), + location: Some(loc), + } + }) + .collect(); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockPistonRetract(BlockPistonRetractEvent { + block_key: block_to_key(self.block), + location: Some(location), + direction: block_face_to_bukkit(Some(self.direction)), + length: self.length, + blocks, + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::BlockPistonRetract(event) => { + self.length = event.length; + } + _ => {} + } + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::block::block_place::BlockPlaceEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { let player_uuid = self.player.gameprofile.id.to_string(); diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index 3265fab..43b193a 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -12,6 +12,8 @@ use pumpkin::plugin::block::block_fertilize::BlockFertilizeEvent; use pumpkin::plugin::block::block_form::BlockFormEvent; use pumpkin::plugin::block::block_from_to::BlockFromToEvent; use pumpkin::plugin::block::block_grow::BlockGrowEvent; +use pumpkin::plugin::block::block_piston_extend::BlockPistonExtendEvent; +use pumpkin::plugin::block::block_piston_retract::BlockPistonRetractEvent; use pumpkin::plugin::block::block_place::BlockPlaceEvent; use pumpkin::plugin::block::block_can_build::BlockCanBuildEvent; use pumpkin::plugin::block::block_burn::BlockBurnEvent; @@ -1151,6 +1153,40 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.block.BlockPistonExtendEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_piston_extend::BlockPistonExtendEvent, + PatchBukkitEventHandler< + pumpkin::plugin::block::block_piston_extend::BlockPistonExtendEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.BlockPistonRetractEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_piston_retract::BlockPistonRetractEvent, + PatchBukkitEventHandler< + pumpkin::plugin::block::block_piston_retract::BlockPistonRetractEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.block.BlockCanBuildEvent" => { context .register_event::< @@ -2647,6 +2683,112 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let block = block_from_key(&block_piston_extend_event_data.block_key); + let position = block_piston_extend_event_data + .location + .and_then(|loc| loc.position) + .map(|pos| { + pumpkin_util::math::position::BlockPos::new( + pos.x as i32, + pos.y as i32, + pos.z as i32, + ) + }) + .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); + let world_uuid = block_piston_extend_event_data + .location + .and_then(|loc| loc.world) + .and_then(|w| w.uuid) + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) + .unwrap_or_else(|| { + context + .server + .worlds + .load() + .first() + .map(|world| world.uuid) + .unwrap_or_default() + }); + let face = + bukkit_block_face_to_direction(&block_piston_extend_event_data.direction) + .unwrap_or(BlockDirection::Down); + let mut blocks = Vec::new(); + for entry in block_piston_extend_event_data.blocks { + if let Some(loc) = entry.location + && let Some(pos) = location_to_vec3(loc.clone()) + { + blocks.push(pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + )); + } + } + let pumpkin_event = BlockPistonExtendEvent::new( + block, + position, + face, + block_piston_extend_event_data.length, + blocks, + world_uuid, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::BlockPistonRetract(block_piston_retract_event_data) => { + let block = block_from_key(&block_piston_retract_event_data.block_key); + let position = block_piston_retract_event_data + .location + .and_then(|loc| loc.position) + .map(|pos| { + pumpkin_util::math::position::BlockPos::new( + pos.x as i32, + pos.y as i32, + pos.z as i32, + ) + }) + .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); + let world_uuid = block_piston_retract_event_data + .location + .and_then(|loc| loc.world) + .and_then(|w| w.uuid) + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) + .unwrap_or_else(|| { + context + .server + .worlds + .load() + .first() + .map(|world| world.uuid) + .unwrap_or_default() + }); + let face = + bukkit_block_face_to_direction(&block_piston_retract_event_data.direction) + .unwrap_or(BlockDirection::Down); + let mut blocks = Vec::new(); + for entry in block_piston_retract_event_data.blocks { + if let Some(loc) = entry.location + && let Some(pos) = location_to_vec3(loc.clone()) + { + blocks.push(pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + )); + } + } + let pumpkin_event = BlockPistonRetractEvent::new( + block, + position, + face, + block_piston_retract_event_data.length, + blocks, + world_uuid, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } Data::BlockPlace(block_place_event_data) => { let uuid = uuid::Uuid::parse_str(&block_place_event_data.player_uuid?.value) .ok()?; From a222a6ae2c07b8aeb6752a097960489de7b908bf Mon Sep 17 00:00:00 2001 From: yunuservices Date: Thu, 5 Feb 2026 09:44:53 +0300 Subject: [PATCH 41/56] Add BlockRedstoneEvent bridge --- .../events/PatchBukkitEventFactory.java | 26 +++++++++++ .../events/PatchBukkitEventManager.java | 15 +++++++ proto/patchbukkit/events/block_events.proto | 7 +++ proto/patchbukkit/events/event.proto | 1 + rust/src/events/handler.rs | 45 ++++++++++++++++++- rust/src/java/native_callbacks/events.rs | 38 ++++++++++++++++ 6 files changed, 131 insertions(+), 1 deletion(-) diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index ee74e17..1918b66 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -20,6 +20,7 @@ import org.bukkit.event.block.BlockGrowEvent; import org.bukkit.event.block.BlockPistonExtendEvent; import org.bukkit.event.block.BlockPistonRetractEvent; +import org.bukkit.event.block.BlockRedstoneEvent; import org.bukkit.event.block.BlockCanBuildEvent; import org.bukkit.event.block.BlockBurnEvent; import org.bukkit.event.block.BlockIgniteEvent; @@ -1415,6 +1416,21 @@ yield new PlayerStatisticIncrementEvent( } yield new BlockPistonRetractEvent(block, blocks, retractEvent.getLength()); } + case BLOCK_REDSTONE -> { + patchbukkit.events.BlockRedstoneEvent redstoneEvent = event.getBlockRedstone(); + Location location = BridgeUtils.convertLocation(redstoneEvent.getLocation()); + if (location == null || !(location.getWorld() instanceof PatchBukkitWorld world)) { + yield null; + } + org.bukkit.block.Block block = PatchBukkitBlock.create( + world, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ(), + redstoneEvent.getBlockKey() + ); + yield new BlockRedstoneEvent(block, redstoneEvent.getOldCurrent(), redstoneEvent.getNewCurrent()); + } case BLOCK_CAN_BUILD -> { patchbukkit.events.BlockCanBuildEvent canBuildEvent = event.getBlockCanBuild(); Player player = getPlayer(canBuildEvent.getPlayerUuid().getValue()); @@ -2567,6 +2583,16 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) ); } eventBuilder.setBlockPistonRetract(builder.build()); + } else if (event instanceof BlockRedstoneEvent redstoneEvent) { + var block = redstoneEvent.getBlock(); + eventBuilder.setBlockRedstone( + patchbukkit.events.BlockRedstoneEvent.newBuilder() + .setBlockKey(block.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(block.getLocation())) + .setOldCurrent(redstoneEvent.getOldCurrent()) + .setNewCurrent(redstoneEvent.getNewCurrent()) + .build() + ); } else if (event instanceof BlockCanBuildEvent canBuildEvent) { Block block = canBuildEvent.getBlock(); boolean canBuild = canBuildEvent.isBuildable(); 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 4c12fcc..18223bc 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -50,6 +50,7 @@ import patchbukkit.events.BlockPistonBlockEntry; import patchbukkit.events.BlockPistonExtendEvent; import patchbukkit.events.BlockPistonRetractEvent; +import patchbukkit.events.BlockRedstoneEvent; import patchbukkit.events.BlockPlaceEvent; import patchbukkit.events.PlayerInteractEvent; import patchbukkit.events.EntitySpawnEvent; @@ -1229,6 +1230,20 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { patchbukkit.events.Event.newBuilder().setBlockPistonRetract(retractBuilder.build()).build() ); break; + case "org.bukkit.event.block.BlockRedstoneEvent": + var redstoneEvent = (org.bukkit.event.block.BlockRedstoneEvent) event; + Block redstoneBlock = redstoneEvent.getBlock(); + request.setEvent( + patchbukkit.events.Event.newBuilder().setBlockRedstone( + BlockRedstoneEvent.newBuilder() + .setBlockKey(redstoneBlock.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(redstoneBlock.getLocation())) + .setOldCurrent(redstoneEvent.getOldCurrent()) + .setNewCurrent(redstoneEvent.getNewCurrent()) + .build() + ).build() + ); + break; case "org.bukkit.event.block.BlockCanBuildEvent": var canBuildEvent = (org.bukkit.event.block.BlockCanBuildEvent) event; Block canBuildBlock = canBuildEvent.getBlock(); diff --git a/proto/patchbukkit/events/block_events.proto b/proto/patchbukkit/events/block_events.proto index e58f6d7..b584498 100644 --- a/proto/patchbukkit/events/block_events.proto +++ b/proto/patchbukkit/events/block_events.proto @@ -120,6 +120,13 @@ message BlockPistonRetractEvent { repeated BlockPistonBlockEntry blocks = 5; } +message BlockRedstoneEvent { + string block_key = 1; + patchbukkit.common.Location location = 2; + int32 old_current = 3; + int32 new_current = 4; +} + message BlockPlaceEvent { patchbukkit.common.UUID player_uuid = 1; string block_key = 2; diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index e71e2ba..0ec2da7 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -88,6 +88,7 @@ message Event { BlockGrowEvent block_grow = 73; BlockPistonExtendEvent block_piston_extend = 74; BlockPistonRetractEvent block_piston_retract = 75; + BlockRedstoneEvent block_redstone = 76; } } diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index a5fe303..9da4dbf 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -19,7 +19,7 @@ use crate::java::jvm::commands::JvmCommand; use crate::proto::patchbukkit::common::{Location, Uuid, Vec3, World}; use crate::proto::patchbukkit::events::event::Data; use crate::proto::patchbukkit::events::{ - BlockBreakEvent, BlockDamageEvent, BlockDamageAbortEvent, BlockDispenseEvent, BlockDropItemEntry, BlockDropItemEvent, BlockExplodeBlockEntry, BlockExplodeEvent, BlockFadeEvent, BlockFertilizeBlockEntry, BlockFertilizeEvent, BlockFormEvent, BlockFromToEvent, BlockGrowEvent, BlockPistonBlockEntry, BlockPistonExtendEvent, BlockPistonRetractEvent, BlockPlaceEvent, BlockCanBuildEvent, BlockBurnEvent, BlockIgniteEvent, BlockSpreadEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, + BlockBreakEvent, BlockDamageEvent, BlockDamageAbortEvent, BlockDispenseEvent, BlockDropItemEntry, BlockDropItemEvent, BlockExplodeBlockEntry, BlockExplodeEvent, BlockFadeEvent, BlockFertilizeBlockEntry, BlockFertilizeEvent, BlockFormEvent, BlockFromToEvent, BlockGrowEvent, BlockPistonBlockEntry, BlockPistonExtendEvent, BlockPistonRetractEvent, BlockRedstoneEvent, BlockPlaceEvent, BlockCanBuildEvent, BlockBurnEvent, BlockIgniteEvent, BlockSpreadEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, PlayerLeaveEvent, PlayerMoveEvent, PlayerInteractEvent, ServerBroadcastEvent, ServerCommandEvent, EntityDamageEvent, EntityDeathEvent, EntitySpawnEvent, PlayerLoginEvent, PlayerTeleportEvent, PlayerChangeWorldEvent, PlayerGamemodeChangeEvent, @@ -3051,6 +3051,49 @@ impl PatchBukkitEvent for pumpkin::plugin::block::block_piston_retract::BlockPis } } +impl PatchBukkitEvent for pumpkin::plugin::block::block_redstone::BlockRedstoneEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let world_uuid = server + .worlds + .load() + .first() + .map(|world| world.uuid) + .unwrap_or_default(); + let location = build_location( + world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockRedstone(BlockRedstoneEvent { + block_key: block_to_key(self.block), + location: Some(location), + old_current: self.old_current, + new_current: self.new_current, + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::BlockRedstone(event) => { + self.new_current = event.new_current; + } + _ => {} + } + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::block::block_place::BlockPlaceEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { let player_uuid = self.player.gameprofile.id.to_string(); diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index 43b193a..88552f2 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -14,6 +14,7 @@ use pumpkin::plugin::block::block_from_to::BlockFromToEvent; use pumpkin::plugin::block::block_grow::BlockGrowEvent; use pumpkin::plugin::block::block_piston_extend::BlockPistonExtendEvent; use pumpkin::plugin::block::block_piston_retract::BlockPistonRetractEvent; +use pumpkin::plugin::block::block_redstone::BlockRedstoneEvent; use pumpkin::plugin::block::block_place::BlockPlaceEvent; use pumpkin::plugin::block::block_can_build::BlockCanBuildEvent; use pumpkin::plugin::block::block_burn::BlockBurnEvent; @@ -1187,6 +1188,21 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.block.BlockRedstoneEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_redstone::BlockRedstoneEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.block.BlockCanBuildEvent" => { context .register_event::< @@ -2789,6 +2805,28 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let block = block_from_key(&block_redstone_event_data.block_key); + let position = block_redstone_event_data + .location + .and_then(|loc| loc.position) + .map(|pos| { + pumpkin_util::math::position::BlockPos::new( + pos.x as i32, + pos.y as i32, + pos.z as i32, + ) + }) + .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); + let pumpkin_event = BlockRedstoneEvent::new( + block, + position, + block_redstone_event_data.old_current, + block_redstone_event_data.new_current, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } Data::BlockPlace(block_place_event_data) => { let uuid = uuid::Uuid::parse_str(&block_place_event_data.player_uuid?.value) .ok()?; From 3f7bfcc09589f058d7cdc42970a0c7f322b80087 Mon Sep 17 00:00:00 2001 From: yunuservices Date: Thu, 5 Feb 2026 09:58:14 +0300 Subject: [PATCH 42/56] Add BlockMultiPlace and BlockPhysics events bridge --- .../events/PatchBukkitEventFactory.java | 87 ++++++++++++++ .../events/PatchBukkitEventManager.java | 36 ++++++ proto/patchbukkit/events/block_events.proto | 19 ++++ proto/patchbukkit/events/event.proto | 2 + rust/src/events/handler.rs | 101 ++++++++++++++++- rust/src/java/native_callbacks/events.rs | 107 ++++++++++++++++++ 6 files changed, 351 insertions(+), 1 deletion(-) diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index 1918b66..80ba1db 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -21,6 +21,8 @@ import org.bukkit.event.block.BlockPistonExtendEvent; import org.bukkit.event.block.BlockPistonRetractEvent; import org.bukkit.event.block.BlockRedstoneEvent; +import org.bukkit.event.block.BlockMultiPlaceEvent; +import org.bukkit.event.block.BlockPhysicsEvent; import org.bukkit.event.block.BlockCanBuildEvent; import org.bukkit.event.block.BlockBurnEvent; import org.bukkit.event.block.BlockIgniteEvent; @@ -1431,6 +1433,63 @@ yield new PlayerStatisticIncrementEvent( ); yield new BlockRedstoneEvent(block, redstoneEvent.getOldCurrent(), redstoneEvent.getNewCurrent()); } + case BLOCK_MULTI_PLACE -> { + patchbukkit.events.BlockMultiPlaceEvent multiEvent = event.getBlockMultiPlace(); + Player player = getPlayer(multiEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + Location location = BridgeUtils.convertLocation(multiEvent.getLocation()); + if (location == null || !(location.getWorld() instanceof PatchBukkitWorld world)) { + yield null; + } + org.bukkit.block.Block block = PatchBukkitBlock.create( + world, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ(), + multiEvent.getBlockKey() + ); + java.util.List states = new java.util.ArrayList<>(); + for (patchbukkit.events.BlockMultiPlaceBlockEntry entry : multiEvent.getBlocksList()) { + Location entryLoc = BridgeUtils.convertLocation(entry.getLocation()); + if (entryLoc == null || !(entryLoc.getWorld() instanceof PatchBukkitWorld entryWorld)) { + continue; + } + String key = entry.getBlockKey().isEmpty() + ? "minecraft:air" + : entry.getBlockKey(); + org.bukkit.block.Block entryBlock = PatchBukkitBlock.create( + entryWorld, + entryLoc.getBlockX(), + entryLoc.getBlockY(), + entryLoc.getBlockZ(), + key + ); + states.add(entryBlock.getState()); + } + yield new BlockMultiPlaceEvent(states, block, null, player, true); + } + case BLOCK_PHYSICS -> { + patchbukkit.events.BlockPhysicsEvent physicsEvent = event.getBlockPhysics(); + Location location = BridgeUtils.convertLocation(physicsEvent.getLocation()); + if (location == null || !(location.getWorld() instanceof PatchBukkitWorld world)) { + yield null; + } + org.bukkit.block.Block block = PatchBukkitBlock.create( + world, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ(), + physicsEvent.getBlockKey() + ); + Material material = Material.matchMaterial(physicsEvent.getSourceBlockKey()); + if (material == null) { + material = Material.matchMaterial("minecraft:" + physicsEvent.getSourceBlockKey()); + } + org.bukkit.block.data.BlockData data = material != null + ? material.createBlockData() + : block.getBlockData(); + yield new BlockPhysicsEvent(block, data); + } case BLOCK_CAN_BUILD -> { patchbukkit.events.BlockCanBuildEvent canBuildEvent = event.getBlockCanBuild(); Player player = getPlayer(canBuildEvent.getPlayerUuid().getValue()); @@ -2593,6 +2652,34 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .setNewCurrent(redstoneEvent.getNewCurrent()) .build() ); + } else if (event instanceof BlockMultiPlaceEvent multiEvent) { + var block = multiEvent.getBlock(); + var builder = patchbukkit.events.BlockMultiPlaceEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(multiEvent.getPlayer().getUniqueId().toString()) + .build()) + .setBlockKey(block.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(block.getLocation())); + for (org.bukkit.block.BlockState state : multiEvent.getBlockStates()) { + builder.addBlocks( + patchbukkit.events.BlockMultiPlaceBlockEntry.newBuilder() + .setBlockKey(state.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(state.getLocation())) + .build() + ); + } + eventBuilder.setBlockMultiPlace(builder.build()); + } else if (event instanceof BlockPhysicsEvent physicsEvent) { + var block = physicsEvent.getBlock(); + var data = physicsEvent.getChangedType(); + eventBuilder.setBlockPhysics( + patchbukkit.events.BlockPhysicsEvent.newBuilder() + .setBlockKey(block.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(block.getLocation())) + .setSourceBlockKey(data.getMaterial().getKey().toString()) + .setSourceLocation(BridgeUtils.convertLocation(block.getLocation())) + .build() + ); } else if (event instanceof BlockCanBuildEvent canBuildEvent) { Block block = canBuildEvent.getBlock(); boolean canBuild = canBuildEvent.isBuildable(); 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 18223bc..c3b03f1 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -51,6 +51,9 @@ import patchbukkit.events.BlockPistonExtendEvent; import patchbukkit.events.BlockPistonRetractEvent; import patchbukkit.events.BlockRedstoneEvent; +import patchbukkit.events.BlockMultiPlaceBlockEntry; +import patchbukkit.events.BlockMultiPlaceEvent; +import patchbukkit.events.BlockPhysicsEvent; import patchbukkit.events.BlockPlaceEvent; import patchbukkit.events.PlayerInteractEvent; import patchbukkit.events.EntitySpawnEvent; @@ -1244,6 +1247,39 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.block.BlockMultiPlaceEvent": + var multiEvent = (org.bukkit.event.block.BlockMultiPlaceEvent) event; + Block multiBlock = multiEvent.getBlock(); + var multiBuilder = BlockMultiPlaceEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(multiEvent.getPlayer().getUniqueId())) + .setBlockKey(multiBlock.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(multiBlock.getLocation())); + for (org.bukkit.block.BlockState state : multiEvent.getBlockStates()) { + multiBuilder.addBlocks( + BlockMultiPlaceBlockEntry.newBuilder() + .setBlockKey(state.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(state.getLocation())) + .build() + ); + } + request.setEvent( + patchbukkit.events.Event.newBuilder().setBlockMultiPlace(multiBuilder.build()).build() + ); + break; + case "org.bukkit.event.block.BlockPhysicsEvent": + var physicsEvent = (org.bukkit.event.block.BlockPhysicsEvent) event; + Block physicsBlock = physicsEvent.getBlock(); + request.setEvent( + patchbukkit.events.Event.newBuilder().setBlockPhysics( + BlockPhysicsEvent.newBuilder() + .setBlockKey(physicsBlock.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(physicsBlock.getLocation())) + .setSourceBlockKey(physicsEvent.getChangedType().getMaterial().getKey().toString()) + .setSourceLocation(BridgeUtils.convertLocation(physicsBlock.getLocation())) + .build() + ).build() + ); + break; case "org.bukkit.event.block.BlockCanBuildEvent": var canBuildEvent = (org.bukkit.event.block.BlockCanBuildEvent) event; Block canBuildBlock = canBuildEvent.getBlock(); diff --git a/proto/patchbukkit/events/block_events.proto b/proto/patchbukkit/events/block_events.proto index b584498..5625090 100644 --- a/proto/patchbukkit/events/block_events.proto +++ b/proto/patchbukkit/events/block_events.proto @@ -127,6 +127,25 @@ message BlockRedstoneEvent { int32 new_current = 4; } +message BlockMultiPlaceBlockEntry { + string block_key = 1; + patchbukkit.common.Location location = 2; +} + +message BlockMultiPlaceEvent { + patchbukkit.common.UUID player_uuid = 1; + string block_key = 2; + patchbukkit.common.Location location = 3; + repeated BlockMultiPlaceBlockEntry blocks = 4; +} + +message BlockPhysicsEvent { + string block_key = 1; + patchbukkit.common.Location location = 2; + string source_block_key = 3; + patchbukkit.common.Location source_location = 4; +} + message BlockPlaceEvent { patchbukkit.common.UUID player_uuid = 1; string block_key = 2; diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index 0ec2da7..de0429e 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -89,6 +89,8 @@ message Event { BlockPistonExtendEvent block_piston_extend = 74; BlockPistonRetractEvent block_piston_retract = 75; BlockRedstoneEvent block_redstone = 76; + BlockMultiPlaceEvent block_multi_place = 77; + BlockPhysicsEvent block_physics = 78; } } diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index 9da4dbf..acfc513 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -19,7 +19,7 @@ use crate::java::jvm::commands::JvmCommand; use crate::proto::patchbukkit::common::{Location, Uuid, Vec3, World}; use crate::proto::patchbukkit::events::event::Data; use crate::proto::patchbukkit::events::{ - BlockBreakEvent, BlockDamageEvent, BlockDamageAbortEvent, BlockDispenseEvent, BlockDropItemEntry, BlockDropItemEvent, BlockExplodeBlockEntry, BlockExplodeEvent, BlockFadeEvent, BlockFertilizeBlockEntry, BlockFertilizeEvent, BlockFormEvent, BlockFromToEvent, BlockGrowEvent, BlockPistonBlockEntry, BlockPistonExtendEvent, BlockPistonRetractEvent, BlockRedstoneEvent, BlockPlaceEvent, BlockCanBuildEvent, BlockBurnEvent, BlockIgniteEvent, BlockSpreadEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, + BlockBreakEvent, BlockDamageEvent, BlockDamageAbortEvent, BlockDispenseEvent, BlockDropItemEntry, BlockDropItemEvent, BlockExplodeBlockEntry, BlockExplodeEvent, BlockFadeEvent, BlockFertilizeBlockEntry, BlockFertilizeEvent, BlockFormEvent, BlockFromToEvent, BlockGrowEvent, BlockPistonBlockEntry, BlockPistonExtendEvent, BlockPistonRetractEvent, BlockRedstoneEvent, BlockMultiPlaceBlockEntry, BlockMultiPlaceEvent, BlockPhysicsEvent, BlockPlaceEvent, BlockCanBuildEvent, BlockBurnEvent, BlockIgniteEvent, BlockSpreadEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, PlayerLeaveEvent, PlayerMoveEvent, PlayerInteractEvent, ServerBroadcastEvent, ServerCommandEvent, EntityDamageEvent, EntityDeathEvent, EntitySpawnEvent, PlayerLoginEvent, PlayerTeleportEvent, PlayerChangeWorldEvent, PlayerGamemodeChangeEvent, @@ -3094,6 +3094,105 @@ impl PatchBukkitEvent for pumpkin::plugin::block::block_redstone::BlockRedstoneE } } +impl PatchBukkitEvent for pumpkin::plugin::block::block_multi_place::BlockMultiPlaceEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let world_uuid = self.player.world().uuid; + let origin = self + .positions + .first() + .copied() + .unwrap_or_else(|| self.player.position().to_block_pos()); + let location = build_location( + world_uuid, + &Vector3::new( + f64::from(origin.0.x), + f64::from(origin.0.y), + f64::from(origin.0.z), + ), + 0.0, + 0.0, + ); + let blocks = self + .positions + .iter() + .map(|pos| { + let loc = build_location( + world_uuid, + &Vector3::new(f64::from(pos.0.x), f64::from(pos.0.y), f64::from(pos.0.z)), + 0.0, + 0.0, + ); + BlockMultiPlaceBlockEntry { + block_key: block_to_key(self.block_placed), + location: Some(loc), + } + }) + .collect(); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockMultiPlace(BlockMultiPlaceEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + block_key: block_to_key(self.block_placed), + location: Some(location), + blocks, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, _data: Data) -> Option<()> { + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::block::block_physics::BlockPhysicsEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + let source_location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.source_pos.0.x), + f64::from(self.source_pos.0.y), + f64::from(self.source_pos.0.z), + ), + 0.0, + 0.0, + ); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockPhysics(BlockPhysicsEvent { + block_key: block_to_key(self.block), + location: Some(location), + source_block_key: block_to_key(self.source_block), + source_location: Some(source_location), + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, _data: Data) -> Option<()> { + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::block::block_place::BlockPlaceEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { let player_uuid = self.player.gameprofile.id.to_string(); diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index 88552f2..b914585 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -15,6 +15,8 @@ use pumpkin::plugin::block::block_grow::BlockGrowEvent; use pumpkin::plugin::block::block_piston_extend::BlockPistonExtendEvent; use pumpkin::plugin::block::block_piston_retract::BlockPistonRetractEvent; use pumpkin::plugin::block::block_redstone::BlockRedstoneEvent; +use pumpkin::plugin::block::block_multi_place::BlockMultiPlaceEvent; +use pumpkin::plugin::block::block_physics::BlockPhysicsEvent; use pumpkin::plugin::block::block_place::BlockPlaceEvent; use pumpkin::plugin::block::block_can_build::BlockCanBuildEvent; use pumpkin::plugin::block::block_burn::BlockBurnEvent; @@ -1203,6 +1205,40 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.block.BlockMultiPlaceEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_multi_place::BlockMultiPlaceEvent, + PatchBukkitEventHandler< + pumpkin::plugin::block::block_multi_place::BlockMultiPlaceEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.BlockPhysicsEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_physics::BlockPhysicsEvent, + PatchBukkitEventHandler< + pumpkin::plugin::block::block_physics::BlockPhysicsEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.block.BlockCanBuildEvent" => { context .register_event::< @@ -2827,6 +2863,77 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let uuid = uuid::Uuid::parse_str(&block_multi_place_event_data.player_uuid?.value) + .ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let block = block_from_key(&block_multi_place_event_data.block_key); + let mut positions = Vec::new(); + for entry in block_multi_place_event_data.blocks { + if let Some(loc) = entry.location + && let Some(pos) = location_to_vec3(loc.clone()) + { + positions.push(pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + )); + } + } + let pumpkin_event = + BlockMultiPlaceEvent::new(player, block, positions); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::BlockPhysics(block_physics_event_data) => { + let block = block_from_key(&block_physics_event_data.block_key); + let source_block = block_from_key(&block_physics_event_data.source_block_key); + let position = block_physics_event_data + .location + .and_then(|loc| loc.position) + .map(|pos| { + pumpkin_util::math::position::BlockPos::new( + pos.x as i32, + pos.y as i32, + pos.z as i32, + ) + }) + .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); + let source_pos = block_physics_event_data + .source_location + .and_then(|loc| loc.position) + .map(|pos| { + pumpkin_util::math::position::BlockPos::new( + pos.x as i32, + pos.y as i32, + pos.z as i32, + ) + }) + .unwrap_or_else(|| position); + let world_uuid = block_physics_event_data + .location + .and_then(|loc| loc.world) + .and_then(|w| w.uuid) + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) + .unwrap_or_else(|| { + context + .server + .worlds + .load() + .first() + .map(|world| world.uuid) + .unwrap_or_default() + }); + let pumpkin_event = BlockPhysicsEvent::new( + block, + position, + source_block, + source_pos, + world_uuid, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } Data::BlockPlace(block_place_event_data) => { let uuid = uuid::Uuid::parse_str(&block_place_event_data.player_uuid?.value) .ok()?; From 50a126db26bda851e94c136616ef798b8b36b6d7 Mon Sep 17 00:00:00 2001 From: yunuservices Date: Thu, 5 Feb 2026 10:26:41 +0300 Subject: [PATCH 43/56] Add note/sign/tnt/moisture/sponge/fluid events --- .../events/PatchBukkitEventFactory.java | 328 ++++++++++++ .../events/PatchBukkitEventManager.java | 102 ++++ proto/patchbukkit/events/block_events.proto | 45 ++ proto/patchbukkit/events/event.proto | 6 + rust/src/events/handler.rs | 467 +++++++++++++++++- rust/src/java/native_callbacks/events.rs | 96 ++++ 6 files changed, 1043 insertions(+), 1 deletion(-) diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index 80ba1db..fff9d50 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -7,6 +7,7 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.Player; +import org.bukkit.entity.Entity; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockDamageAbortEvent; import org.bukkit.event.block.BlockDamageEvent; @@ -28,6 +29,14 @@ import org.bukkit.event.block.BlockIgniteEvent; import org.bukkit.event.block.BlockSpreadEvent; import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.block.NotePlayEvent; +import org.bukkit.event.block.SignChangeEvent; +import org.bukkit.event.block.TNTPrimeEvent; +import org.bukkit.event.block.MoistureChangeEvent; +import org.bukkit.event.block.SpongeAbsorbEvent; +import org.bukkit.event.block.FluidLevelChangeEvent; +import org.bukkit.Instrument; +import org.bukkit.Note; import org.bukkit.event.player.AsyncPlayerChatEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerCommandPreprocessEvent; @@ -1490,6 +1499,173 @@ yield new PlayerStatisticIncrementEvent( : block.getBlockData(); yield new BlockPhysicsEvent(block, data); } + case NOTE_PLAY -> { + patchbukkit.events.NotePlayEvent noteEvent = event.getNotePlay(); + Location location = BridgeUtils.convertLocation(noteEvent.getLocation()); + if (location == null || !(location.getWorld() instanceof PatchBukkitWorld world)) { + yield null; + } + Block block = PatchBukkitBlock.create( + world, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ(), + noteEvent.getBlockKey() + ); + Instrument instrument = Instrument.PIANO; + if (!noteEvent.getInstrument().isEmpty()) { + try { + instrument = Instrument.valueOf(noteEvent.getInstrument()); + } catch (IllegalArgumentException ignored) { + instrument = Instrument.PIANO; + } + } + int rawNote = Math.max(0, Math.min(24, noteEvent.getNote())); + Note note = new Note((byte) rawNote); + yield new NotePlayEvent(block, instrument, note); + } + case SIGN_CHANGE -> { + patchbukkit.events.SignChangeEvent signEvent = event.getSignChange(); + Player player = getPlayer(signEvent.getPlayerUuid().getValue()); + if (player == null) yield null; + + Location location = BridgeUtils.convertLocation(signEvent.getLocation()); + if (location == null || !(location.getWorld() instanceof PatchBukkitWorld world)) { + yield null; + } + Block block = PatchBukkitBlock.create( + world, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ(), + signEvent.getBlockKey() + ); + String[] lines = new String[4]; + java.util.List linesList = signEvent.getLinesList(); + for (int i = 0; i < lines.length; i++) { + lines[i] = i < linesList.size() ? linesList.get(i) : ""; + } + org.bukkit.event.Event constructed = + createSignChangeEvent(block, player, lines, signEvent.getIsFrontText()); + if (constructed instanceof SignChangeEvent signChange) { + yield signChange; + } + yield null; + } + case TNT_PRIME -> { + patchbukkit.events.TNTPrimeEvent tntEvent = event.getTntPrime(); + Location location = BridgeUtils.convertLocation(tntEvent.getLocation()); + if (location == null || !(location.getWorld() instanceof PatchBukkitWorld world)) { + yield null; + } + Block block = PatchBukkitBlock.create( + world, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ(), + tntEvent.getBlockKey() + ); + TNTPrimeEvent.PrimeCause cause = TNTPrimeEvent.PrimeCause.PLAYER; + if (!tntEvent.getCause().isEmpty()) { + try { + cause = TNTPrimeEvent.PrimeCause.valueOf(tntEvent.getCause()); + } catch (IllegalArgumentException ignored) { + cause = TNTPrimeEvent.PrimeCause.PLAYER; + } + } + Player player = null; + if (tntEvent.hasPlayerUuid()) { + player = getPlayer(tntEvent.getPlayerUuid().getValue()); + } + org.bukkit.event.Event constructed = createTntPrimeEvent(block, cause, player); + if (constructed instanceof TNTPrimeEvent tntPrime) { + yield tntPrime; + } + yield null; + } + case MOISTURE_CHANGE -> { + patchbukkit.events.MoistureChangeEvent moistureEvent = event.getMoistureChange(); + Location location = BridgeUtils.convertLocation(moistureEvent.getLocation()); + if (location == null || !(location.getWorld() instanceof PatchBukkitWorld world)) { + yield null; + } + Block block = PatchBukkitBlock.create( + world, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ(), + moistureEvent.getBlockKey() + ); + String newKey = moistureEvent.getNewBlockKey().isEmpty() + ? "minecraft:air" + : moistureEvent.getNewBlockKey(); + Block newBlock = PatchBukkitBlock.create( + world, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ(), + newKey + ); + yield new MoistureChangeEvent(block, newBlock.getState()); + } + case SPONGE_ABSORB -> { + patchbukkit.events.SpongeAbsorbEvent spongeEvent = event.getSpongeAbsorb(); + Location location = BridgeUtils.convertLocation(spongeEvent.getLocation()); + if (location == null || !(location.getWorld() instanceof PatchBukkitWorld world)) { + yield null; + } + Block block = PatchBukkitBlock.create( + world, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ(), + spongeEvent.getBlockKey() + ); + java.util.List states = new java.util.ArrayList<>(); + for (patchbukkit.events.SpongeAbsorbBlockEntry entry : spongeEvent.getBlocksList()) { + Location entryLoc = BridgeUtils.convertLocation(entry.getLocation()); + if (entryLoc == null || !(entryLoc.getWorld() instanceof PatchBukkitWorld entryWorld)) { + continue; + } + String key = entry.getBlockKey().isEmpty() + ? "minecraft:air" + : entry.getBlockKey(); + Block entryBlock = PatchBukkitBlock.create( + entryWorld, + entryLoc.getBlockX(), + entryLoc.getBlockY(), + entryLoc.getBlockZ(), + key + ); + states.add(entryBlock.getState()); + } + yield new SpongeAbsorbEvent(block, states); + } + case FLUID_LEVEL_CHANGE -> { + patchbukkit.events.FluidLevelChangeEvent fluidEvent = event.getFluidLevelChange(); + Location location = BridgeUtils.convertLocation(fluidEvent.getLocation()); + if (location == null || !(location.getWorld() instanceof PatchBukkitWorld world)) { + yield null; + } + Block block = PatchBukkitBlock.create( + world, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ(), + fluidEvent.getBlockKey() + ); + String newKey = fluidEvent.getNewBlockKey().isEmpty() + ? "minecraft:air" + : fluidEvent.getNewBlockKey(); + Block newBlock = PatchBukkitBlock.create( + world, + location.getBlockX(), + location.getBlockY(), + location.getBlockZ(), + newKey + ); + yield new FluidLevelChangeEvent(block, newBlock.getState()); + } case BLOCK_CAN_BUILD -> { patchbukkit.events.BlockCanBuildEvent canBuildEvent = event.getBlockCanBuild(); Player player = getPlayer(canBuildEvent.getPlayerUuid().getValue()); @@ -2680,6 +2856,84 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .setSourceLocation(BridgeUtils.convertLocation(block.getLocation())) .build() ); + } else if (event instanceof NotePlayEvent noteEvent) { + Block block = noteEvent.getBlock(); + eventBuilder.setNotePlay( + patchbukkit.events.NotePlayEvent.newBuilder() + .setBlockKey(block.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(block.getLocation())) + .setInstrument(noteEvent.getInstrument().name()) + .setNote(noteEvent.getNote().getId()) + .build() + ); + } else if (event instanceof SignChangeEvent signEvent) { + Block block = signEvent.getBlock(); + String[] lines = signEvent.getLines(); + var builder = patchbukkit.events.SignChangeEvent.newBuilder() + .setPlayerUuid(UUID.newBuilder() + .setValue(signEvent.getPlayer().getUniqueId().toString()) + .build()) + .setBlockKey(block.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(block.getLocation())); + for (String line : lines) { + builder.addLines(line != null ? line : ""); + } + try { + java.lang.reflect.Method method = signEvent.getClass().getMethod("isFrontText"); + Object value = method.invoke(signEvent); + if (value instanceof Boolean b) { + builder.setIsFrontText(b); + } + } catch (ReflectiveOperationException ignored) { + builder.setIsFrontText(true); + } + eventBuilder.setSignChange(builder.build()); + } else if (event instanceof TNTPrimeEvent tntEvent) { + Block block = tntEvent.getBlock(); + var builder = patchbukkit.events.TNTPrimeEvent.newBuilder() + .setBlockKey(block.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(block.getLocation())) + .setCause(tntEvent.getCause().name()); + if (tntEvent.getPrimingEntity() instanceof Player player) { + builder.setPlayerUuid(UUID.newBuilder() + .setValue(player.getUniqueId().toString()) + .build()); + } + eventBuilder.setTntPrime(builder.build()); + } else if (event instanceof MoistureChangeEvent moistureEvent) { + Block block = moistureEvent.getBlock(); + org.bukkit.block.BlockState newState = moistureEvent.getNewState(); + eventBuilder.setMoistureChange( + patchbukkit.events.MoistureChangeEvent.newBuilder() + .setBlockKey(block.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(block.getLocation())) + .setNewBlockKey(newState.getType().getKey().toString()) + .build() + ); + } else if (event instanceof SpongeAbsorbEvent spongeEvent) { + Block block = spongeEvent.getBlock(); + var builder = patchbukkit.events.SpongeAbsorbEvent.newBuilder() + .setBlockKey(block.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(block.getLocation())); + for (org.bukkit.block.BlockState state : spongeEvent.getBlocks()) { + builder.addBlocks( + patchbukkit.events.SpongeAbsorbBlockEntry.newBuilder() + .setBlockKey(state.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(state.getLocation())) + .build() + ); + } + eventBuilder.setSpongeAbsorb(builder.build()); + } else if (event instanceof FluidLevelChangeEvent fluidEvent) { + Block block = fluidEvent.getBlock(); + org.bukkit.block.BlockState newState = fluidEvent.getNewState(); + eventBuilder.setFluidLevelChange( + patchbukkit.events.FluidLevelChangeEvent.newBuilder() + .setBlockKey(block.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(block.getLocation())) + .setNewBlockKey(newState.getType().getKey().toString()) + .build() + ); } else if (event instanceof BlockCanBuildEvent canBuildEvent) { Block block = canBuildEvent.getBlock(); boolean canBuild = canBuildEvent.isBuildable(); @@ -3009,6 +3263,80 @@ private static BlockCanBuildEvent createBlockCanBuildEvent( return null; } + @Nullable + private static org.bukkit.event.Event createSignChangeEvent( + @NotNull Block block, + @NotNull Player player, + @NotNull String[] lines, + boolean isFrontText + ) { + try { + java.lang.reflect.Constructor ctor = + SignChangeEvent.class.getConstructor(Block.class, Player.class, String[].class); + return ctor.newInstance(block, player, lines); + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + java.lang.reflect.Constructor ctor = + SignChangeEvent.class.getConstructor(Block.class, Player.class, String[].class, boolean.class); + return ctor.newInstance(block, player, lines, isFrontText); + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + Class sideClass = Class.forName("org.bukkit.block.sign.SignSide"); + @SuppressWarnings("unchecked") + Object side = Enum.valueOf((Class) sideClass, isFrontText ? "FRONT" : "BACK"); + java.lang.reflect.Constructor ctor = + SignChangeEvent.class.getConstructor(Block.class, Player.class, String[].class, sideClass); + return (org.bukkit.event.Event) ctor.newInstance(block, player, lines, side); + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + Class sideClass = Class.forName("org.bukkit.block.sign.Side"); + @SuppressWarnings("unchecked") + Object side = Enum.valueOf((Class) sideClass, isFrontText ? "FRONT" : "BACK"); + java.lang.reflect.Constructor ctor = + SignChangeEvent.class.getConstructor(Block.class, Player.class, String[].class, sideClass); + return (org.bukkit.event.Event) ctor.newInstance(block, player, lines, side); + } catch (ReflectiveOperationException ignored) { + // ignore + } + return null; + } + + @Nullable + private static org.bukkit.event.Event createTntPrimeEvent( + @NotNull Block block, + @NotNull TNTPrimeEvent.PrimeCause cause, + @Nullable Entity primer + ) { + try { + java.lang.reflect.Constructor ctor = + TNTPrimeEvent.class.getConstructor(Block.class, TNTPrimeEvent.PrimeCause.class, Entity.class); + return ctor.newInstance(block, cause, primer); + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + java.lang.reflect.Constructor ctor = + TNTPrimeEvent.class.getConstructor(Block.class, TNTPrimeEvent.PrimeCause.class); + return ctor.newInstance(block, cause); + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + java.lang.reflect.Constructor ctor = + TNTPrimeEvent.class.getConstructor(Block.class, TNTPrimeEvent.PrimeCause.class, Entity.class, Block.class); + return ctor.newInstance(block, cause, primer, block); + } catch (ReflectiveOperationException ignored) { + // ignore + } + return null; + } + private static void setIgnitingBlock(@NotNull BlockBurnEvent event, @Nullable String ignitingKey) { if (ignitingKey == null || ignitingKey.isEmpty()) { return; 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 c3b03f1..7a6dd5e 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -55,6 +55,13 @@ import patchbukkit.events.BlockMultiPlaceEvent; import patchbukkit.events.BlockPhysicsEvent; import patchbukkit.events.BlockPlaceEvent; +import patchbukkit.events.NotePlayEvent; +import patchbukkit.events.SignChangeEvent; +import patchbukkit.events.TntPrimeEvent; +import patchbukkit.events.MoistureChangeEvent; +import patchbukkit.events.SpongeAbsorbEvent; +import patchbukkit.events.SpongeAbsorbBlockEntry; +import patchbukkit.events.FluidLevelChangeEvent; import patchbukkit.events.PlayerInteractEvent; import patchbukkit.events.EntitySpawnEvent; import patchbukkit.events.EntityDamageEvent; @@ -1280,6 +1287,101 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.block.NotePlayEvent": + var noteEvent = (org.bukkit.event.block.NotePlayEvent) event; + Block noteBlock = noteEvent.getBlock(); + request.setEvent( + patchbukkit.events.Event.newBuilder().setNotePlay( + NotePlayEvent.newBuilder() + .setBlockKey(noteBlock.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(noteBlock.getLocation())) + .setInstrument(noteEvent.getInstrument().name()) + .setNote(noteEvent.getNote().getId()) + .build() + ).build() + ); + break; + case "org.bukkit.event.block.SignChangeEvent": + var signEvent = (org.bukkit.event.block.SignChangeEvent) event; + Block signBlock = signEvent.getBlock(); + var signBuilder = SignChangeEvent.newBuilder() + .setPlayerUuid(BridgeUtils.convertUuid(signEvent.getPlayer().getUniqueId())) + .setBlockKey(signBlock.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(signBlock.getLocation())); + for (String line : signEvent.getLines()) { + signBuilder.addLines(line != null ? line : ""); + } + try { + Method method = signEvent.getClass().getMethod("isFrontText"); + Object value = method.invoke(signEvent); + if (value instanceof Boolean b) { + signBuilder.setIsFrontText(b); + } + } catch (ReflectiveOperationException ignored) { + signBuilder.setIsFrontText(true); + } + request.setEvent( + patchbukkit.events.Event.newBuilder().setSignChange(signBuilder.build()).build() + ); + break; + case "org.bukkit.event.block.TNTPrimeEvent": + var tntEvent = (org.bukkit.event.block.TNTPrimeEvent) event; + Block tntBlock = tntEvent.getBlock(); + var tntBuilder = TntPrimeEvent.newBuilder() + .setBlockKey(tntBlock.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(tntBlock.getLocation())) + .setCause(tntEvent.getCause().name()); + if (tntEvent.getPrimingEntity() instanceof org.bukkit.entity.Player player) { + tntBuilder.setPlayerUuid(BridgeUtils.convertUuid(player.getUniqueId())); + } + request.setEvent( + patchbukkit.events.Event.newBuilder().setTntPrime(tntBuilder.build()).build() + ); + break; + case "org.bukkit.event.block.MoistureChangeEvent": + var moistureEvent = (org.bukkit.event.block.MoistureChangeEvent) event; + Block moistureBlock = moistureEvent.getBlock(); + request.setEvent( + patchbukkit.events.Event.newBuilder().setMoistureChange( + MoistureChangeEvent.newBuilder() + .setBlockKey(moistureBlock.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(moistureBlock.getLocation())) + .setNewBlockKey(moistureEvent.getNewState().getType().getKey().toString()) + .build() + ).build() + ); + break; + case "org.bukkit.event.block.SpongeAbsorbEvent": + var spongeEvent = (org.bukkit.event.block.SpongeAbsorbEvent) event; + Block spongeBlock = spongeEvent.getBlock(); + var spongeBuilder = SpongeAbsorbEvent.newBuilder() + .setBlockKey(spongeBlock.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(spongeBlock.getLocation())); + for (org.bukkit.block.BlockState state : spongeEvent.getBlocks()) { + spongeBuilder.addBlocks( + SpongeAbsorbBlockEntry.newBuilder() + .setBlockKey(state.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(state.getLocation())) + .build() + ); + } + request.setEvent( + patchbukkit.events.Event.newBuilder().setSpongeAbsorb(spongeBuilder.build()).build() + ); + break; + case "org.bukkit.event.block.FluidLevelChangeEvent": + var fluidEvent = (org.bukkit.event.block.FluidLevelChangeEvent) event; + Block fluidBlock = fluidEvent.getBlock(); + request.setEvent( + patchbukkit.events.Event.newBuilder().setFluidLevelChange( + FluidLevelChangeEvent.newBuilder() + .setBlockKey(fluidBlock.getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(fluidBlock.getLocation())) + .setNewBlockKey(fluidEvent.getNewState().getType().getKey().toString()) + .build() + ).build() + ); + break; case "org.bukkit.event.block.BlockCanBuildEvent": var canBuildEvent = (org.bukkit.event.block.BlockCanBuildEvent) event; Block canBuildBlock = canBuildEvent.getBlock(); diff --git a/proto/patchbukkit/events/block_events.proto b/proto/patchbukkit/events/block_events.proto index 5625090..13ef896 100644 --- a/proto/patchbukkit/events/block_events.proto +++ b/proto/patchbukkit/events/block_events.proto @@ -191,3 +191,48 @@ message PlayerInteractEvent { string item_key = 5; string block_face = 6; } + +message NotePlayEvent { + string block_key = 1; + patchbukkit.common.Location location = 2; + string instrument = 3; + int32 note = 4; +} + +message SignChangeEvent { + patchbukkit.common.UUID player_uuid = 1; + string block_key = 2; + patchbukkit.common.Location location = 3; + repeated string lines = 4; + bool is_front_text = 5; +} + +message TNTPrimeEvent { + patchbukkit.common.UUID player_uuid = 1; + string block_key = 2; + patchbukkit.common.Location location = 3; + string cause = 4; +} + +message MoistureChangeEvent { + string block_key = 1; + patchbukkit.common.Location location = 2; + string new_block_key = 3; +} + +message SpongeAbsorbBlockEntry { + string block_key = 1; + patchbukkit.common.Location location = 2; +} + +message SpongeAbsorbEvent { + string block_key = 1; + patchbukkit.common.Location location = 2; + repeated SpongeAbsorbBlockEntry blocks = 3; +} + +message FluidLevelChangeEvent { + string block_key = 1; + patchbukkit.common.Location location = 2; + string new_block_key = 3; +} diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index de0429e..388d81e 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -91,6 +91,12 @@ message Event { BlockRedstoneEvent block_redstone = 76; BlockMultiPlaceEvent block_multi_place = 77; BlockPhysicsEvent block_physics = 78; + NotePlayEvent note_play = 79; + SignChangeEvent sign_change = 80; + TNTPrimeEvent tnt_prime = 81; + MoistureChangeEvent moisture_change = 82; + SpongeAbsorbEvent sponge_absorb = 83; + FluidLevelChangeEvent fluid_level_change = 84; } } diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index acfc513..eaa0bd6 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -8,6 +8,7 @@ use pumpkin::server::Server; use pumpkin_api_macros::with_runtime; use pumpkin_data::data_component_impl::EquipmentSlot; use pumpkin_data::{Block, BlockDirection}; +use pumpkin_data::block_properties::Instrument; use pumpkin_data::item::Item; use pumpkin_util::Hand; use pumpkin_util::math::vector3::Vector3; @@ -19,7 +20,7 @@ use crate::java::jvm::commands::JvmCommand; use crate::proto::patchbukkit::common::{Location, Uuid, Vec3, World}; use crate::proto::patchbukkit::events::event::Data; use crate::proto::patchbukkit::events::{ - BlockBreakEvent, BlockDamageEvent, BlockDamageAbortEvent, BlockDispenseEvent, BlockDropItemEntry, BlockDropItemEvent, BlockExplodeBlockEntry, BlockExplodeEvent, BlockFadeEvent, BlockFertilizeBlockEntry, BlockFertilizeEvent, BlockFormEvent, BlockFromToEvent, BlockGrowEvent, BlockPistonBlockEntry, BlockPistonExtendEvent, BlockPistonRetractEvent, BlockRedstoneEvent, BlockMultiPlaceBlockEntry, BlockMultiPlaceEvent, BlockPhysicsEvent, BlockPlaceEvent, BlockCanBuildEvent, BlockBurnEvent, BlockIgniteEvent, BlockSpreadEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, + BlockBreakEvent, BlockDamageEvent, BlockDamageAbortEvent, BlockDispenseEvent, BlockDropItemEntry, BlockDropItemEvent, BlockExplodeBlockEntry, BlockExplodeEvent, BlockFadeEvent, BlockFertilizeBlockEntry, BlockFertilizeEvent, BlockFormEvent, BlockFromToEvent, BlockGrowEvent, BlockPistonBlockEntry, BlockPistonExtendEvent, BlockPistonRetractEvent, BlockRedstoneEvent, BlockMultiPlaceBlockEntry, BlockMultiPlaceEvent, BlockPhysicsEvent, BlockPlaceEvent, BlockCanBuildEvent, BlockBurnEvent, BlockIgniteEvent, BlockSpreadEvent, NotePlayEvent, SignChangeEvent, TntPrimeEvent, MoistureChangeEvent, SpongeAbsorbEvent, SpongeAbsorbBlockEntry, FluidLevelChangeEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, PlayerLeaveEvent, PlayerMoveEvent, PlayerInteractEvent, ServerBroadcastEvent, ServerCommandEvent, EntityDamageEvent, EntityDeathEvent, EntitySpawnEvent, PlayerLoginEvent, PlayerTeleportEvent, PlayerChangeWorldEvent, PlayerGamemodeChangeEvent, @@ -3193,6 +3194,413 @@ impl PatchBukkitEvent for pumpkin::plugin::block::block_physics::BlockPhysicsEve } } +impl PatchBukkitEvent for pumpkin::plugin::block::note_play::NotePlayEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + + JvmEventPayload { + event: Event { + data: Some(Data::NotePlay(NotePlayEvent { + block_key: block_to_key(self.block), + location: Some(location), + instrument: instrument_to_bukkit(self.instrument), + note: i32::from(self.note), + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::NotePlay(event) => { + if !event.block_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_key) { + self.block = block; + } + } + if let Some(loc) = event.location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + if let Some(world) = loc.world.and_then(|w| w.uuid) { + if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { + self.world_uuid = uuid; + } + } + } + if !event.instrument.is_empty() { + if let Some(instrument) = instrument_from_bukkit(&event.instrument) { + self.instrument = instrument; + } + } + self.note = event.note.clamp(0, 24) as u8; + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::block::sign_change::SignChangeEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let world_uuid = self.player.world().uuid; + let location = build_location( + world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + + JvmEventPayload { + event: Event { + data: Some(Data::SignChange(SignChangeEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + block_key: block_to_key(self.block), + location: Some(location), + lines: self.lines.clone(), + is_front_text: self.is_front_text, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { + match data { + Data::SignChange(event) => { + if let Some(uuid) = event.player_uuid { + if let Ok(uuid) = uuid::Uuid::from_str(&uuid.value) { + if let Some(player) = server.get_player_by_uuid(uuid) { + self.player = player; + } + } + } + if !event.block_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_key) { + self.block = block; + } + } + if let Some(loc) = event.location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + } + if !event.lines.is_empty() { + self.lines = event.lines; + } + self.is_front_text = event.is_front_text; + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::block::tnt_prime::TNTPrimeEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + let player_uuid = self.player.as_ref().map(|player| Uuid { + value: player.gameprofile.id.to_string(), + }); + + JvmEventPayload { + event: Event { + data: Some(Data::TntPrime(TntPrimeEvent { + player_uuid, + block_key: block_to_key(self.block), + location: Some(location), + cause: self.cause.clone(), + })), + }, + context: EventContext { + server, + player: self.player.clone(), + }, + } + } + + fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { + match data { + Data::TntPrime(event) => { + if let Some(uuid) = event.player_uuid { + if let Ok(uuid) = uuid::Uuid::from_str(&uuid.value) { + self.player = server.get_player_by_uuid(uuid); + } + } else { + self.player = None; + } + if !event.block_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_key) { + self.block = block; + } + } + if let Some(loc) = event.location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + if let Some(world) = loc.world.and_then(|w| w.uuid) { + if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { + self.world_uuid = uuid; + } + } + } + if !event.cause.is_empty() { + self.cause = event.cause; + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::block::moisture_change::MoistureChangeEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + let new_block_key = Block::from_state_id(self.new_state_id) + .map(block_to_key) + .unwrap_or_default(); + + JvmEventPayload { + event: Event { + data: Some(Data::MoistureChange(MoistureChangeEvent { + block_key: block_to_key(self.block), + location: Some(location), + new_block_key, + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::MoistureChange(event) => { + if !event.block_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_key) { + self.block = block; + } + } + if let Some(loc) = event.location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + if let Some(world) = loc.world.and_then(|w| w.uuid) { + if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { + self.world_uuid = uuid; + } + } + } + if !event.new_block_key.is_empty() { + if let Some(block) = Block::from_name(&event.new_block_key) { + self.new_state_id = block.default_state.id; + } + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::block::sponge_absorb::SpongeAbsorbEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + let blocks = self + .blocks + .iter() + .map(|pos| { + let loc = build_location( + self.world_uuid, + &Vector3::new(f64::from(pos.0.x), f64::from(pos.0.y), f64::from(pos.0.z)), + 0.0, + 0.0, + ); + SpongeAbsorbBlockEntry { + block_key: block_to_key(&Block::WATER), + location: Some(loc), + } + }) + .collect(); + + JvmEventPayload { + event: Event { + data: Some(Data::SpongeAbsorb(SpongeAbsorbEvent { + block_key: block_to_key(self.block), + location: Some(location), + blocks, + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::SpongeAbsorb(event) => { + if !event.block_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_key) { + self.block = block; + } + } + if let Some(loc) = event.location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + if let Some(world) = loc.world.and_then(|w| w.uuid) { + if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { + self.world_uuid = uuid; + } + } + } + if !event.blocks.is_empty() { + let mut blocks = Vec::with_capacity(event.blocks.len()); + for entry in event.blocks { + if let Some(loc) = entry.location.and_then(location_to_vec3) { + blocks.push(pumpkin_util::math::position::BlockPos::new( + loc.x.floor() as i32, + loc.y.floor() as i32, + loc.z.floor() as i32, + )); + } + } + self.blocks = blocks; + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::block::fluid_level_change::FluidLevelChangeEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + let new_block_key = Block::from_state_id(self.new_state_id) + .map(block_to_key) + .unwrap_or_default(); + + JvmEventPayload { + event: Event { + data: Some(Data::FluidLevelChange(FluidLevelChangeEvent { + block_key: block_to_key(self.block), + location: Some(location), + new_block_key, + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::FluidLevelChange(event) => { + if !event.block_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_key) { + self.block = block; + } + } + if let Some(loc) = event.location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + if let Some(world) = loc.world.and_then(|w| w.uuid) { + if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { + self.world_uuid = uuid; + } + } + } + if !event.new_block_key.is_empty() { + if let Some(block) = Block::from_name(&event.new_block_key) { + self.new_state_id = block.default_state.id; + } + } + } + _ => {} + } + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::block::block_place::BlockPlaceEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { let player_uuid = self.player.gameprofile.id.to_string(); @@ -3740,6 +4148,63 @@ fn bukkit_main_hand(hand: Hand) -> String { } } +fn instrument_to_bukkit(instrument: Instrument) -> String { + match instrument { + Instrument::Harp => "PIANO".to_string(), + Instrument::Basedrum => "BASS_DRUM".to_string(), + Instrument::Snare => "SNARE_DRUM".to_string(), + Instrument::Hat => "STICKS".to_string(), + Instrument::Bass => "BASS_GUITAR".to_string(), + Instrument::Flute => "FLUTE".to_string(), + Instrument::Bell => "BELL".to_string(), + Instrument::Guitar => "GUITAR".to_string(), + Instrument::Chime => "CHIME".to_string(), + Instrument::Xylophone => "XYLOPHONE".to_string(), + Instrument::IronXylophone => "IRON_XYLOPHONE".to_string(), + Instrument::CowBell => "COW_BELL".to_string(), + Instrument::Didgeridoo => "DIDGERIDOO".to_string(), + Instrument::Bit => "BIT".to_string(), + Instrument::Banjo => "BANJO".to_string(), + Instrument::Pling => "PLING".to_string(), + Instrument::Zombie => "ZOMBIE".to_string(), + Instrument::Skeleton => "SKELETON".to_string(), + Instrument::Creeper => "CREEPER".to_string(), + Instrument::Dragon => "DRAGON".to_string(), + Instrument::WitherSkeleton => "WITHER_SKELETON".to_string(), + Instrument::Piglin => "PIGLIN".to_string(), + Instrument::CustomHead => "CUSTOM_HEAD".to_string(), + } +} + +fn instrument_from_bukkit(name: &str) -> Option { + match name { + "PIANO" => Some(Instrument::Harp), + "BASS_DRUM" => Some(Instrument::Basedrum), + "SNARE_DRUM" => Some(Instrument::Snare), + "STICKS" => Some(Instrument::Hat), + "BASS_GUITAR" => Some(Instrument::Bass), + "FLUTE" => Some(Instrument::Flute), + "BELL" => Some(Instrument::Bell), + "GUITAR" => Some(Instrument::Guitar), + "CHIME" => Some(Instrument::Chime), + "XYLOPHONE" => Some(Instrument::Xylophone), + "IRON_XYLOPHONE" => Some(Instrument::IronXylophone), + "COW_BELL" => Some(Instrument::CowBell), + "DIDGERIDOO" => Some(Instrument::Didgeridoo), + "BIT" => Some(Instrument::Bit), + "BANJO" => Some(Instrument::Banjo), + "PLING" => Some(Instrument::Pling), + "ZOMBIE" => Some(Instrument::Zombie), + "SKELETON" => Some(Instrument::Skeleton), + "CREEPER" => Some(Instrument::Creeper), + "DRAGON" => Some(Instrument::Dragon), + "WITHER_SKELETON" => Some(Instrument::WitherSkeleton), + "PIGLIN" => Some(Instrument::Piglin), + "CUSTOM_HEAD" => Some(Instrument::CustomHead), + _ => None, + } +} + pub struct PatchBukkitEventHandler { plugin_name: String, command_tx: mpsc::Sender, diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index b914585..b1a59a1 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -1239,6 +1239,102 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.block.NotePlayEvent" => { + context + .register_event::< + pumpkin::plugin::block::note_play::NotePlayEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.SignChangeEvent" => { + context + .register_event::< + pumpkin::plugin::block::sign_change::SignChangeEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.TNTPrimeEvent" => { + context + .register_event::< + pumpkin::plugin::block::tnt_prime::TNTPrimeEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.MoistureChangeEvent" => { + context + .register_event::< + pumpkin::plugin::block::moisture_change::MoistureChangeEvent, + PatchBukkitEventHandler< + pumpkin::plugin::block::moisture_change::MoistureChangeEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.SpongeAbsorbEvent" => { + context + .register_event::< + pumpkin::plugin::block::sponge_absorb::SpongeAbsorbEvent, + PatchBukkitEventHandler< + pumpkin::plugin::block::sponge_absorb::SpongeAbsorbEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.FluidLevelChangeEvent" => { + context + .register_event::< + pumpkin::plugin::block::fluid_level_change::FluidLevelChangeEvent, + PatchBukkitEventHandler< + pumpkin::plugin::block::fluid_level_change::FluidLevelChangeEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.block.BlockCanBuildEvent" => { context .register_event::< From 0a23ea00d33c3bbde31bed7deda85f04a9fb4e17 Mon Sep 17 00:00:00 2001 From: yunuservices Date: Thu, 5 Feb 2026 10:48:15 +0300 Subject: [PATCH 44/56] Add SpawnChangeEvent --- .../events/PatchBukkitEventFactory.java | 53 ++++++++++++++++++ .../events/PatchBukkitEventManager.java | 18 +++++++ proto/patchbukkit/events/event.proto | 2 + proto/patchbukkit/events/world_events.proto | 12 +++++ rust/src/events/handler.rs | 54 ++++++++++++++++++- rust/src/java/native_callbacks/events.rs | 15 ++++++ 6 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 proto/patchbukkit/events/world_events.proto diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index fff9d50..bc9959e 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -37,6 +37,7 @@ import org.bukkit.event.block.FluidLevelChangeEvent; import org.bukkit.Instrument; import org.bukkit.Note; +import org.bukkit.event.world.SpawnChangeEvent; import org.bukkit.event.player.AsyncPlayerChatEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerCommandPreprocessEvent; @@ -1666,6 +1667,23 @@ yield new PlayerStatisticIncrementEvent( ); yield new FluidLevelChangeEvent(block, newBlock.getState()); } + case SPAWN_CHANGE -> { + patchbukkit.events.SpawnChangeEvent spawnEvent = event.getSpawnChange(); + Location location = BridgeUtils.convertLocation(spawnEvent.getLocation()); + if (location == null || !(location.getWorld() instanceof PatchBukkitWorld world)) { + yield null; + } + Location previous = BridgeUtils.convertLocation(spawnEvent.getPreviousLocation()); + if (previous == null) { + previous = location; + } + org.bukkit.event.Event constructed = + createSpawnChangeEvent(world, location, previous); + if (constructed instanceof SpawnChangeEvent spawnChange) { + yield spawnChange; + } + yield null; + } case BLOCK_CAN_BUILD -> { patchbukkit.events.BlockCanBuildEvent canBuildEvent = event.getBlockCanBuild(); Player player = getPlayer(canBuildEvent.getPlayerUuid().getValue()); @@ -2934,6 +2952,18 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .setNewBlockKey(newState.getType().getKey().toString()) .build() ); + } else if (event instanceof SpawnChangeEvent spawnEvent) { + Location location = spawnEvent.getLocation(); + Location previous = spawnEvent.getPreviousLocation(); + if (previous == null) { + previous = location; + } + eventBuilder.setSpawnChange( + patchbukkit.events.SpawnChangeEvent.newBuilder() + .setPreviousLocation(BridgeUtils.convertLocation(previous)) + .setLocation(BridgeUtils.convertLocation(location)) + .build() + ); } else if (event instanceof BlockCanBuildEvent canBuildEvent) { Block block = canBuildEvent.getBlock(); boolean canBuild = canBuildEvent.isBuildable(); @@ -3337,6 +3367,29 @@ private static org.bukkit.event.Event createTntPrimeEvent( return null; } + @Nullable + private static org.bukkit.event.Event createSpawnChangeEvent( + @NotNull org.bukkit.World world, + @NotNull Location location, + @NotNull Location previous + ) { + try { + java.lang.reflect.Constructor ctor = + SpawnChangeEvent.class.getConstructor(org.bukkit.World.class, Location.class, Location.class); + return ctor.newInstance(world, location, previous); + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + java.lang.reflect.Constructor ctor = + SpawnChangeEvent.class.getConstructor(org.bukkit.World.class, Location.class); + return ctor.newInstance(world, location); + } catch (ReflectiveOperationException ignored) { + // ignore + } + return null; + } + private static void setIgnitingBlock(@NotNull BlockBurnEvent event, @Nullable String ignitingKey) { if (ignitingKey == null || ignitingKey.isEmpty()) { return; 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 7a6dd5e..1260444 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -15,6 +15,7 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.util.Vector; import org.bukkit.block.Block; +import org.bukkit.Location; import org.patchbukkit.bridge.BridgeUtils; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; @@ -62,6 +63,7 @@ import patchbukkit.events.SpongeAbsorbEvent; import patchbukkit.events.SpongeAbsorbBlockEntry; import patchbukkit.events.FluidLevelChangeEvent; +import patchbukkit.events.SpawnChangeEvent; import patchbukkit.events.PlayerInteractEvent; import patchbukkit.events.EntitySpawnEvent; import patchbukkit.events.EntityDamageEvent; @@ -1382,6 +1384,22 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.world.SpawnChangeEvent": + var spawnEvent = (org.bukkit.event.world.SpawnChangeEvent) event; + Location location = spawnEvent.getLocation(); + Location previous = spawnEvent.getPreviousLocation(); + if (previous == null) { + previous = location; + } + request.setEvent( + patchbukkit.events.Event.newBuilder().setSpawnChange( + SpawnChangeEvent.newBuilder() + .setPreviousLocation(BridgeUtils.convertLocation(previous)) + .setLocation(BridgeUtils.convertLocation(location)) + .build() + ).build() + ); + break; case "org.bukkit.event.block.BlockCanBuildEvent": var canBuildEvent = (org.bukkit.event.block.BlockCanBuildEvent) event; Block canBuildBlock = canBuildEvent.getBlock(); diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index 388d81e..1d67c4e 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -7,6 +7,7 @@ import "patchbukkit/events/player_events.proto"; import "patchbukkit/events/server_events.proto"; import "patchbukkit/events/block_events.proto"; import "patchbukkit/events/entity_events.proto"; +import "patchbukkit/events/world_events.proto"; option java_multiple_files = true; option java_package = "patchbukkit.events"; @@ -97,6 +98,7 @@ message Event { MoistureChangeEvent moisture_change = 82; SpongeAbsorbEvent sponge_absorb = 83; FluidLevelChangeEvent fluid_level_change = 84; + SpawnChangeEvent spawn_change = 85; } } diff --git a/proto/patchbukkit/events/world_events.proto b/proto/patchbukkit/events/world_events.proto new file mode 100644 index 0000000..4c59dda --- /dev/null +++ b/proto/patchbukkit/events/world_events.proto @@ -0,0 +1,12 @@ +syntax = "proto3"; +package patchbukkit.events; + +import "patchbukkit/common/types.proto"; + +option java_multiple_files = true; +option java_package = "patchbukkit.events"; + +message SpawnChangeEvent { + patchbukkit.common.Location previous_location = 1; + patchbukkit.common.Location location = 2; +} diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index eaa0bd6..59bb920 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -20,7 +20,7 @@ use crate::java::jvm::commands::JvmCommand; use crate::proto::patchbukkit::common::{Location, Uuid, Vec3, World}; use crate::proto::patchbukkit::events::event::Data; use crate::proto::patchbukkit::events::{ - BlockBreakEvent, BlockDamageEvent, BlockDamageAbortEvent, BlockDispenseEvent, BlockDropItemEntry, BlockDropItemEvent, BlockExplodeBlockEntry, BlockExplodeEvent, BlockFadeEvent, BlockFertilizeBlockEntry, BlockFertilizeEvent, BlockFormEvent, BlockFromToEvent, BlockGrowEvent, BlockPistonBlockEntry, BlockPistonExtendEvent, BlockPistonRetractEvent, BlockRedstoneEvent, BlockMultiPlaceBlockEntry, BlockMultiPlaceEvent, BlockPhysicsEvent, BlockPlaceEvent, BlockCanBuildEvent, BlockBurnEvent, BlockIgniteEvent, BlockSpreadEvent, NotePlayEvent, SignChangeEvent, TntPrimeEvent, MoistureChangeEvent, SpongeAbsorbEvent, SpongeAbsorbBlockEntry, FluidLevelChangeEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, + BlockBreakEvent, BlockDamageEvent, BlockDamageAbortEvent, BlockDispenseEvent, BlockDropItemEntry, BlockDropItemEvent, BlockExplodeBlockEntry, BlockExplodeEvent, BlockFadeEvent, BlockFertilizeBlockEntry, BlockFertilizeEvent, BlockFormEvent, BlockFromToEvent, BlockGrowEvent, BlockPistonBlockEntry, BlockPistonExtendEvent, BlockPistonRetractEvent, BlockRedstoneEvent, BlockMultiPlaceBlockEntry, BlockMultiPlaceEvent, BlockPhysicsEvent, BlockPlaceEvent, BlockCanBuildEvent, BlockBurnEvent, BlockIgniteEvent, BlockSpreadEvent, NotePlayEvent, SignChangeEvent, TntPrimeEvent, MoistureChangeEvent, SpongeAbsorbEvent, SpongeAbsorbBlockEntry, FluidLevelChangeEvent, SpawnChangeEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, PlayerLeaveEvent, PlayerMoveEvent, PlayerInteractEvent, ServerBroadcastEvent, ServerCommandEvent, EntityDamageEvent, EntityDeathEvent, EntitySpawnEvent, PlayerLoginEvent, PlayerTeleportEvent, PlayerChangeWorldEvent, PlayerGamemodeChangeEvent, @@ -3601,6 +3601,58 @@ impl PatchBukkitEvent for pumpkin::plugin::block::fluid_level_change::FluidLevel } } +impl PatchBukkitEvent for pumpkin::plugin::world::spawn_change::SpawnChangeEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let world_uuid = self.world.uuid; + let previous_location = build_location( + world_uuid, + &Vector3::new( + f64::from(self.previous_position.0.x), + f64::from(self.previous_position.0.y), + f64::from(self.previous_position.0.z), + ), + 0.0, + 0.0, + ); + let location = build_location( + world_uuid, + &Vector3::new( + f64::from(self.new_position.0.x), + f64::from(self.new_position.0.y), + f64::from(self.new_position.0.z), + ), + 0.0, + 0.0, + ); + + JvmEventPayload { + event: Event { + data: Some(Data::SpawnChange(SpawnChangeEvent { + previous_location: Some(previous_location), + location: Some(location), + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::SpawnChange(event) => { + if let Some(loc) = event.location.and_then(location_to_vec3) { + self.new_position = pumpkin_util::math::position::BlockPos::new( + loc.x.floor() as i32, + loc.y.floor() as i32, + loc.z.floor() as i32, + ); + } + } + _ => {} + } + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::block::block_place::BlockPlaceEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { let player_uuid = self.player.gameprofile.id.to_string(); diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index b1a59a1..0a77f96 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -1335,6 +1335,21 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.world.SpawnChangeEvent" => { + context + .register_event::< + pumpkin::plugin::world::spawn_change::SpawnChangeEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.block.BlockCanBuildEvent" => { context .register_event::< From 0b7bf004b130eee0a72fee5291d3a5442b059ff2 Mon Sep 17 00:00:00 2001 From: yunuservices Date: Thu, 5 Feb 2026 10:58:43 +0300 Subject: [PATCH 45/56] Add ServerListPingEvent --- .../events/PatchBukkitEventFactory.java | 83 +++++++++++++++++++ .../events/PatchBukkitEventManager.java | 38 +++++++++ proto/patchbukkit/events/event.proto | 1 + proto/patchbukkit/events/server_events.proto | 7 ++ rust/src/events/handler.rs | 39 ++++++++- rust/src/java/native_callbacks/events.rs | 17 ++++ 6 files changed, 184 insertions(+), 1 deletion(-) diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index bc9959e..c60ed7b 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -38,6 +38,7 @@ import org.bukkit.Instrument; import org.bukkit.Note; import org.bukkit.event.world.SpawnChangeEvent; +import org.bukkit.event.server.ServerListPingEvent; import org.bukkit.event.player.AsyncPlayerChatEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerCommandPreprocessEvent; @@ -1836,6 +1837,19 @@ yield new PlayerStatisticIncrementEvent( String message = PlainTextComponentSerializer.plainText().serialize(messageComponent); yield new BroadcastMessageEvent(message); } + case SERVER_LIST_PING -> { + patchbukkit.events.ServerListPingEvent pingEvent = event.getServerListPing(); + String motd = pingEvent.getMotd(); + int maxPlayers = pingEvent.getMaxPlayers(); + int onlinePlayers = pingEvent.getOnlinePlayers(); + String favicon = pingEvent.getFavicon(); + org.bukkit.event.Event constructed = + createServerListPingEvent(motd, maxPlayers, onlinePlayers, favicon); + if (constructed instanceof ServerListPingEvent serverListPing) { + yield serverListPing; + } + yield null; + } case DATA_NOT_SET -> { LOGGER.warning("EventFactory: Received Event with no data"); yield null; @@ -3082,6 +3096,42 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .setSender(senderJson) .build() ); + } else if (event instanceof ServerListPingEvent pingEvent) { + String motd = pingEvent.getMotd(); + int maxPlayers = pingEvent.getMaxPlayers(); + int onlinePlayers = 0; + try { + java.lang.reflect.Method method = pingEvent.getClass().getMethod("getNumPlayers"); + Object value = method.invoke(pingEvent); + if (value instanceof Integer count) { + onlinePlayers = count; + } + } catch (ReflectiveOperationException ignored) { + onlinePlayers = pingEvent.getServer().getOnlinePlayers().size(); + } + String favicon = ""; + try { + java.lang.reflect.Method method = pingEvent.getClass().getMethod("getServerIcon"); + Object icon = method.invoke(pingEvent); + if (icon != null) { + java.lang.reflect.Method dataMethod = icon.getClass().getMethod("getData"); + Object data = dataMethod.invoke(icon); + if (data instanceof String dataString) { + favicon = dataString; + } + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + + eventBuilder.setServerListPing( + patchbukkit.events.ServerListPingEvent.newBuilder() + .setMotd(motd) + .setMaxPlayers(maxPlayers) + .setOnlinePlayers(onlinePlayers) + .setFavicon(favicon) + .build() + ); } builder.setData(eventBuilder.build()); @@ -3390,6 +3440,39 @@ private static org.bukkit.event.Event createSpawnChangeEvent( return null; } + @Nullable + private static org.bukkit.event.Event createServerListPingEvent( + @NotNull String motd, + int maxPlayers, + int onlinePlayers, + @NotNull String favicon + ) { + java.net.InetAddress address = java.net.InetAddress.getLoopbackAddress(); + try { + java.lang.reflect.Constructor ctor = + ServerListPingEvent.class.getConstructor(java.net.InetAddress.class, String.class, int.class, int.class); + ServerListPingEvent event = ctor.newInstance(address, motd, maxPlayers, onlinePlayers); + return event; + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + java.lang.reflect.Constructor ctor = + ServerListPingEvent.class.getConstructor(java.net.InetAddress.class, String.class, int.class); + ServerListPingEvent event = ctor.newInstance(address, motd, maxPlayers); + try { + java.lang.reflect.Method method = event.getClass().getMethod("setNumPlayers", int.class); + method.invoke(event, onlinePlayers); + } catch (ReflectiveOperationException ignored) { + // ignore + } + return event; + } catch (ReflectiveOperationException ignored) { + // ignore + } + return null; + } + private static void setIgnitingBlock(@NotNull BlockBurnEvent event, @Nullable String ignitingKey) { if (ignitingKey == null || ignitingKey.isEmpty()) { return; 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 1260444..7560e22 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -64,6 +64,7 @@ import patchbukkit.events.SpongeAbsorbBlockEntry; import patchbukkit.events.FluidLevelChangeEvent; import patchbukkit.events.SpawnChangeEvent; +import patchbukkit.events.ServerListPingEvent; import patchbukkit.events.PlayerInteractEvent; import patchbukkit.events.EntitySpawnEvent; import patchbukkit.events.EntityDamageEvent; @@ -1400,6 +1401,43 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.server.ServerListPingEvent": + var pingEvent = (org.bukkit.event.server.ServerListPingEvent) event; + int onlinePlayers = 0; + try { + Method method = pingEvent.getClass().getMethod("getNumPlayers"); + Object value = method.invoke(pingEvent); + if (value instanceof Integer count) { + onlinePlayers = count; + } + } catch (ReflectiveOperationException ignored) { + onlinePlayers = pingEvent.getServer().getOnlinePlayers().size(); + } + String favicon = ""; + try { + Method method = pingEvent.getClass().getMethod("getServerIcon"); + Object icon = method.invoke(pingEvent); + if (icon != null) { + Method dataMethod = icon.getClass().getMethod("getData"); + Object data = dataMethod.invoke(icon); + if (data instanceof String dataString) { + favicon = dataString; + } + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + request.setEvent( + patchbukkit.events.Event.newBuilder().setServerListPing( + ServerListPingEvent.newBuilder() + .setMotd(pingEvent.getMotd()) + .setMaxPlayers(pingEvent.getMaxPlayers()) + .setOnlinePlayers(onlinePlayers) + .setFavicon(favicon) + .build() + ).build() + ); + break; case "org.bukkit.event.block.BlockCanBuildEvent": var canBuildEvent = (org.bukkit.event.block.BlockCanBuildEvent) event; Block canBuildBlock = canBuildEvent.getBlock(); diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index 1d67c4e..5c5d450 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -99,6 +99,7 @@ message Event { SpongeAbsorbEvent sponge_absorb = 83; FluidLevelChangeEvent fluid_level_change = 84; SpawnChangeEvent spawn_change = 85; + ServerListPingEvent server_list_ping = 86; } } diff --git a/proto/patchbukkit/events/server_events.proto b/proto/patchbukkit/events/server_events.proto index bba90a8..cf9d71b 100644 --- a/proto/patchbukkit/events/server_events.proto +++ b/proto/patchbukkit/events/server_events.proto @@ -14,3 +14,10 @@ message ServerBroadcastEvent { string message = 1; string sender = 2; } + +message ServerListPingEvent { + string motd = 1; + int32 max_players = 2; + int32 online_players = 3; + string favicon = 4; +} diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index 59bb920..74f3479 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -20,7 +20,7 @@ use crate::java::jvm::commands::JvmCommand; use crate::proto::patchbukkit::common::{Location, Uuid, Vec3, World}; use crate::proto::patchbukkit::events::event::Data; use crate::proto::patchbukkit::events::{ - BlockBreakEvent, BlockDamageEvent, BlockDamageAbortEvent, BlockDispenseEvent, BlockDropItemEntry, BlockDropItemEvent, BlockExplodeBlockEntry, BlockExplodeEvent, BlockFadeEvent, BlockFertilizeBlockEntry, BlockFertilizeEvent, BlockFormEvent, BlockFromToEvent, BlockGrowEvent, BlockPistonBlockEntry, BlockPistonExtendEvent, BlockPistonRetractEvent, BlockRedstoneEvent, BlockMultiPlaceBlockEntry, BlockMultiPlaceEvent, BlockPhysicsEvent, BlockPlaceEvent, BlockCanBuildEvent, BlockBurnEvent, BlockIgniteEvent, BlockSpreadEvent, NotePlayEvent, SignChangeEvent, TntPrimeEvent, MoistureChangeEvent, SpongeAbsorbEvent, SpongeAbsorbBlockEntry, FluidLevelChangeEvent, SpawnChangeEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, + BlockBreakEvent, BlockDamageEvent, BlockDamageAbortEvent, BlockDispenseEvent, BlockDropItemEntry, BlockDropItemEvent, BlockExplodeBlockEntry, BlockExplodeEvent, BlockFadeEvent, BlockFertilizeBlockEntry, BlockFertilizeEvent, BlockFormEvent, BlockFromToEvent, BlockGrowEvent, BlockPistonBlockEntry, BlockPistonExtendEvent, BlockPistonRetractEvent, BlockRedstoneEvent, BlockMultiPlaceBlockEntry, BlockMultiPlaceEvent, BlockPhysicsEvent, BlockPlaceEvent, BlockCanBuildEvent, BlockBurnEvent, BlockIgniteEvent, BlockSpreadEvent, NotePlayEvent, SignChangeEvent, TntPrimeEvent, MoistureChangeEvent, SpongeAbsorbEvent, SpongeAbsorbBlockEntry, FluidLevelChangeEvent, SpawnChangeEvent, ServerListPingEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, PlayerLeaveEvent, PlayerMoveEvent, PlayerInteractEvent, ServerBroadcastEvent, ServerCommandEvent, EntityDamageEvent, EntityDeathEvent, EntitySpawnEvent, PlayerLoginEvent, PlayerTeleportEvent, PlayerChangeWorldEvent, PlayerGamemodeChangeEvent, @@ -3653,6 +3653,43 @@ impl PatchBukkitEvent for pumpkin::plugin::world::spawn_change::SpawnChangeEvent } } +impl PatchBukkitEvent for pumpkin::plugin::server::server_list_ping::ServerListPingEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::ServerListPing(ServerListPingEvent { + motd: self.motd.clone(), + max_players: self.max_players as i32, + online_players: self.num_players as i32, + favicon: self.favicon.clone().unwrap_or_default(), + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::ServerListPing(event) => { + if !event.motd.is_empty() { + self.motd = event.motd; + } + if event.max_players >= 0 { + self.max_players = event.max_players as u32; + } + if event.online_players >= 0 { + self.num_players = event.online_players as u32; + } + if !event.favicon.is_empty() { + self.favicon = Some(event.favicon); + } + } + _ => {} + } + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::block::block_place::BlockPlaceEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { let player_uuid = self.player.gameprofile.id.to_string(); diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index 0a77f96..29347fe 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -1350,6 +1350,23 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.server.ServerListPingEvent" => { + context + .register_event::< + pumpkin::plugin::server::server_list_ping::ServerListPingEvent, + PatchBukkitEventHandler< + pumpkin::plugin::server::server_list_ping::ServerListPingEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.block.BlockCanBuildEvent" => { context .register_event::< From 37626410407a2aa209b2114a911274efea25899c Mon Sep 17 00:00:00 2001 From: yunuservices Date: Thu, 5 Feb 2026 11:34:09 +0300 Subject: [PATCH 46/56] Bridge plugin and service server events --- .../events/PatchBukkitEventFactory.java | 208 ++++++++++++++++++ .../events/PatchBukkitEventManager.java | 60 +++++ proto/patchbukkit/events/event.proto | 4 + proto/patchbukkit/events/server_events.proto | 18 ++ rust/src/events/handler.rs | 110 ++++++++- rust/src/java/native_callbacks/events.rs | 68 ++++++ 6 files changed, 467 insertions(+), 1 deletion(-) diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index c60ed7b..97f8c59 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -39,6 +39,12 @@ import org.bukkit.Note; import org.bukkit.event.world.SpawnChangeEvent; import org.bukkit.event.server.ServerListPingEvent; +import org.bukkit.event.server.PluginEnableEvent; +import org.bukkit.event.server.PluginDisableEvent; +import org.bukkit.event.server.ServiceRegisterEvent; +import org.bukkit.event.server.ServiceUnregisterEvent; +import org.bukkit.plugin.RegisteredServiceProvider; +import org.bukkit.plugin.ServicePriority; import org.bukkit.event.player.AsyncPlayerChatEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerCommandPreprocessEvent; @@ -1850,6 +1856,38 @@ yield new PlayerStatisticIncrementEvent( } yield null; } + case PLUGIN_ENABLE -> { + patchbukkit.events.PluginEnableEvent enableEvent = event.getPluginEnable(); + String pluginName = enableEvent.getPluginName(); + org.bukkit.plugin.Plugin plugin = Bukkit.getPluginManager().getPlugin(pluginName); + if (plugin == null) yield null; + yield new PluginEnableEvent(plugin); + } + case PLUGIN_DISABLE -> { + patchbukkit.events.PluginDisableEvent disableEvent = event.getPluginDisable(); + String pluginName = disableEvent.getPluginName(); + org.bukkit.plugin.Plugin plugin = Bukkit.getPluginManager().getPlugin(pluginName); + if (plugin == null) yield null; + yield new PluginDisableEvent(plugin); + } + case SERVICE_REGISTER -> { + patchbukkit.events.ServiceRegisterEvent registerEvent = event.getServiceRegister(); + RegisteredServiceProvider provider = resolveServiceProvider( + registerEvent.getServiceName(), + registerEvent.getPluginName() + ); + if (provider == null) yield null; + yield new ServiceRegisterEvent(provider); + } + case SERVICE_UNREGISTER -> { + patchbukkit.events.ServiceUnregisterEvent unregisterEvent = event.getServiceUnregister(); + RegisteredServiceProvider provider = resolveServiceProvider( + unregisterEvent.getServiceName(), + unregisterEvent.getPluginName() + ); + if (provider == null) yield null; + yield new ServiceUnregisterEvent(provider); + } case DATA_NOT_SET -> { LOGGER.warning("EventFactory: Received Event with no data"); yield null; @@ -3132,6 +3170,46 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .setFavicon(favicon) .build() ); + } else if (event instanceof PluginEnableEvent enableEvent) { + eventBuilder.setPluginEnable( + patchbukkit.events.PluginEnableEvent.newBuilder() + .setPluginName(enableEvent.getPlugin().getName()) + .build() + ); + } else if (event instanceof PluginDisableEvent disableEvent) { + eventBuilder.setPluginDisable( + patchbukkit.events.PluginDisableEvent.newBuilder() + .setPluginName(disableEvent.getPlugin().getName()) + .build() + ); + } else if (event instanceof ServiceRegisterEvent registerEvent) { + RegisteredServiceProvider provider = registerEvent.getProvider(); + String pluginName = provider != null && provider.getPlugin() != null + ? provider.getPlugin().getName() + : ""; + String serviceName = provider != null && provider.getService() != null + ? provider.getService().getName() + : ""; + eventBuilder.setServiceRegister( + patchbukkit.events.ServiceRegisterEvent.newBuilder() + .setPluginName(pluginName) + .setServiceName(serviceName) + .build() + ); + } else if (event instanceof ServiceUnregisterEvent unregisterEvent) { + RegisteredServiceProvider provider = unregisterEvent.getProvider(); + String pluginName = provider != null && provider.getPlugin() != null + ? provider.getPlugin().getName() + : ""; + String serviceName = provider != null && provider.getService() != null + ? provider.getService().getName() + : ""; + eventBuilder.setServiceUnregister( + patchbukkit.events.ServiceUnregisterEvent.newBuilder() + .setPluginName(pluginName) + .setServiceName(serviceName) + .build() + ); } builder.setData(eventBuilder.build()); @@ -3473,6 +3551,136 @@ private static org.bukkit.event.Event createServerListPingEvent( return null; } + @Nullable + private static RegisteredServiceProvider resolveServiceProvider( + @NotNull String serviceName, + @NotNull String pluginName + ) { + Class serviceClass = resolveServiceClass(serviceName); + if (serviceClass == null) { + return null; + } + + RegisteredServiceProvider provider = Bukkit.getServicesManager().getRegistration(serviceClass); + if (provider != null) { + if (pluginName.isEmpty() || provider.getPlugin().getName().equals(pluginName)) { + return provider; + } + } + + org.bukkit.plugin.Plugin plugin = Bukkit.getPluginManager().getPlugin(pluginName); + if (plugin == null) { + return provider; + } + return createFallbackServiceProvider(serviceClass, plugin); + } + + @Nullable + private static Class resolveServiceClass(@NotNull String serviceName) { + if (serviceName.isEmpty()) { + return null; + } + try { + return Class.forName(serviceName); + } catch (ClassNotFoundException ignored) { + // ignore + } + for (Class known : Bukkit.getServicesManager().getKnownServices()) { + if (known.getName().equals(serviceName) || known.getSimpleName().equals(serviceName)) { + return known; + } + } + return null; + } + + @Nullable + private static RegisteredServiceProvider createFallbackServiceProvider( + @NotNull Class serviceClass, + @NotNull org.bukkit.plugin.Plugin plugin + ) { + Object instance = createServiceInstance(serviceClass); + if (instance == null) { + return null; + } + try { + java.lang.reflect.Constructor[] ctors = RegisteredServiceProvider.class.getConstructors(); + for (java.lang.reflect.Constructor ctor : ctors) { + Class[] params = ctor.getParameterTypes(); + if (params.length != 4) { + continue; + } + if (!Class.class.isAssignableFrom(params[0])) { + continue; + } + if (!ServicePriority.class.isAssignableFrom(params[2])) { + continue; + } + if (!org.bukkit.plugin.Plugin.class.isAssignableFrom(params[3])) { + continue; + } + try { + Object created = ctor.newInstance(serviceClass, instance, ServicePriority.NORMAL, plugin); + if (created instanceof RegisteredServiceProvider provider) { + return provider; + } + } catch (ReflectiveOperationException ignored) { + // try next constructor + } + } + } catch (SecurityException ignored) { + // ignore + } + return null; + } + + @Nullable + private static Object createServiceInstance(@NotNull Class serviceClass) { + if (serviceClass.isInterface()) { + return java.lang.reflect.Proxy.newProxyInstance( + serviceClass.getClassLoader(), + new Class[] { serviceClass }, + (proxy, method, args) -> defaultValue(method.getReturnType()) + ); + } + try { + return serviceClass.getDeclaredConstructor().newInstance(); + } catch (ReflectiveOperationException ignored) { + return null; + } + } + + @Nullable + private static Object defaultValue(@NotNull Class returnType) { + if (!returnType.isPrimitive()) { + return null; + } + if (returnType == boolean.class) { + return false; + } + if (returnType == byte.class) { + return (byte) 0; + } + if (returnType == short.class) { + return (short) 0; + } + if (returnType == int.class) { + return 0; + } + if (returnType == long.class) { + return 0L; + } + if (returnType == float.class) { + return 0.0f; + } + if (returnType == double.class) { + return 0.0d; + } + if (returnType == char.class) { + return '\0'; + } + return null; + } + private static void setIgnitingBlock(@NotNull BlockBurnEvent event, @Nullable String ignitingKey) { if (ignitingKey == null || ignitingKey.isEmpty()) { return; 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 7560e22..711fc4b 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -65,6 +65,10 @@ import patchbukkit.events.FluidLevelChangeEvent; import patchbukkit.events.SpawnChangeEvent; import patchbukkit.events.ServerListPingEvent; +import patchbukkit.events.PluginEnableEvent; +import patchbukkit.events.PluginDisableEvent; +import patchbukkit.events.ServiceRegisterEvent; +import patchbukkit.events.ServiceUnregisterEvent; import patchbukkit.events.PlayerInteractEvent; import patchbukkit.events.EntitySpawnEvent; import patchbukkit.events.EntityDamageEvent; @@ -1576,6 +1580,62 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ).build() ); break; + case "org.bukkit.event.server.PluginEnableEvent": + var pluginEnableEvent = (org.bukkit.event.server.PluginEnableEvent) event; + request.setEvent( + patchbukkit.events.Event.newBuilder().setPluginEnable( + PluginEnableEvent.newBuilder() + .setPluginName(pluginEnableEvent.getPlugin().getName()) + .build() + ).build() + ); + break; + case "org.bukkit.event.server.PluginDisableEvent": + var pluginDisableEvent = (org.bukkit.event.server.PluginDisableEvent) event; + request.setEvent( + patchbukkit.events.Event.newBuilder().setPluginDisable( + PluginDisableEvent.newBuilder() + .setPluginName(pluginDisableEvent.getPlugin().getName()) + .build() + ).build() + ); + break; + case "org.bukkit.event.server.ServiceRegisterEvent": + var serviceRegisterEvent = (org.bukkit.event.server.ServiceRegisterEvent) event; + var registerProvider = serviceRegisterEvent.getProvider(); + String registerPluginName = registerProvider != null && registerProvider.getPlugin() != null + ? registerProvider.getPlugin().getName() + : ""; + String registerServiceName = registerProvider != null && registerProvider.getService() != null + ? registerProvider.getService().getName() + : ""; + request.setEvent( + patchbukkit.events.Event.newBuilder().setServiceRegister( + ServiceRegisterEvent.newBuilder() + .setPluginName(registerPluginName) + .setServiceName(registerServiceName) + .build() + ).build() + ); + break; + case "org.bukkit.event.server.ServiceUnregisterEvent": + var serviceUnregisterEvent = (org.bukkit.event.server.ServiceUnregisterEvent) event; + var unregisterProvider = serviceUnregisterEvent.getProvider(); + String unregisterPluginName = unregisterProvider != null && unregisterProvider.getPlugin() != null + ? unregisterProvider.getPlugin().getName() + : ""; + String unregisterServiceName = unregisterProvider != null && unregisterProvider.getService() != null + ? unregisterProvider.getService().getName() + : ""; + request.setEvent( + patchbukkit.events.Event.newBuilder().setServiceUnregister( + ServiceUnregisterEvent.newBuilder() + .setPluginName(unregisterPluginName) + .setServiceName(unregisterServiceName) + .build() + ).build() + ); + break; } var response = NativeBridgeFfi.callEvent(request.build()); diff --git a/proto/patchbukkit/events/event.proto b/proto/patchbukkit/events/event.proto index 5c5d450..0536dd6 100644 --- a/proto/patchbukkit/events/event.proto +++ b/proto/patchbukkit/events/event.proto @@ -100,6 +100,10 @@ message Event { FluidLevelChangeEvent fluid_level_change = 84; SpawnChangeEvent spawn_change = 85; ServerListPingEvent server_list_ping = 86; + PluginEnableEvent plugin_enable = 87; + PluginDisableEvent plugin_disable = 88; + ServiceRegisterEvent service_register = 89; + ServiceUnregisterEvent service_unregister = 90; } } diff --git a/proto/patchbukkit/events/server_events.proto b/proto/patchbukkit/events/server_events.proto index cf9d71b..5c0d783 100644 --- a/proto/patchbukkit/events/server_events.proto +++ b/proto/patchbukkit/events/server_events.proto @@ -21,3 +21,21 @@ message ServerListPingEvent { int32 online_players = 3; string favicon = 4; } + +message PluginEnableEvent { + string plugin_name = 1; +} + +message PluginDisableEvent { + string plugin_name = 1; +} + +message ServiceRegisterEvent { + string plugin_name = 1; + string service_name = 2; +} + +message ServiceUnregisterEvent { + string plugin_name = 1; + string service_name = 2; +} diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index 74f3479..01babef 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -20,7 +20,7 @@ use crate::java::jvm::commands::JvmCommand; use crate::proto::patchbukkit::common::{Location, Uuid, Vec3, World}; use crate::proto::patchbukkit::events::event::Data; use crate::proto::patchbukkit::events::{ - BlockBreakEvent, BlockDamageEvent, BlockDamageAbortEvent, BlockDispenseEvent, BlockDropItemEntry, BlockDropItemEvent, BlockExplodeBlockEntry, BlockExplodeEvent, BlockFadeEvent, BlockFertilizeBlockEntry, BlockFertilizeEvent, BlockFormEvent, BlockFromToEvent, BlockGrowEvent, BlockPistonBlockEntry, BlockPistonExtendEvent, BlockPistonRetractEvent, BlockRedstoneEvent, BlockMultiPlaceBlockEntry, BlockMultiPlaceEvent, BlockPhysicsEvent, BlockPlaceEvent, BlockCanBuildEvent, BlockBurnEvent, BlockIgniteEvent, BlockSpreadEvent, NotePlayEvent, SignChangeEvent, TntPrimeEvent, MoistureChangeEvent, SpongeAbsorbEvent, SpongeAbsorbBlockEntry, FluidLevelChangeEvent, SpawnChangeEvent, ServerListPingEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, + BlockBreakEvent, BlockDamageEvent, BlockDamageAbortEvent, BlockDispenseEvent, BlockDropItemEntry, BlockDropItemEvent, BlockExplodeBlockEntry, BlockExplodeEvent, BlockFadeEvent, BlockFertilizeBlockEntry, BlockFertilizeEvent, BlockFormEvent, BlockFromToEvent, BlockGrowEvent, BlockPistonBlockEntry, BlockPistonExtendEvent, BlockPistonRetractEvent, BlockRedstoneEvent, BlockMultiPlaceBlockEntry, BlockMultiPlaceEvent, BlockPhysicsEvent, BlockPlaceEvent, BlockCanBuildEvent, BlockBurnEvent, BlockIgniteEvent, BlockSpreadEvent, NotePlayEvent, SignChangeEvent, TntPrimeEvent, MoistureChangeEvent, SpongeAbsorbEvent, SpongeAbsorbBlockEntry, FluidLevelChangeEvent, SpawnChangeEvent, ServerListPingEvent, PluginEnableEvent, PluginDisableEvent, ServiceRegisterEvent, ServiceUnregisterEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, PlayerLeaveEvent, PlayerMoveEvent, PlayerInteractEvent, ServerBroadcastEvent, ServerCommandEvent, EntityDamageEvent, EntityDeathEvent, EntitySpawnEvent, PlayerLoginEvent, PlayerTeleportEvent, PlayerChangeWorldEvent, PlayerGamemodeChangeEvent, @@ -3690,6 +3690,114 @@ impl PatchBukkitEvent for pumpkin::plugin::server::server_list_ping::ServerListP } } +impl PatchBukkitEvent for pumpkin::plugin::server::plugin_enable::PluginEnableEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PluginEnable(PluginEnableEvent { + plugin_name: self.plugin_name.clone(), + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PluginEnable(event) => { + if !event.plugin_name.is_empty() { + self.plugin_name = event.plugin_name; + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::server::plugin_disable::PluginDisableEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PluginDisable(PluginDisableEvent { + plugin_name: self.plugin_name.clone(), + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PluginDisable(event) => { + if !event.plugin_name.is_empty() { + self.plugin_name = event.plugin_name; + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::server::service_register::ServiceRegisterEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::ServiceRegister(ServiceRegisterEvent { + plugin_name: self.plugin_name.clone(), + service_name: self.service_name.clone(), + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::ServiceRegister(event) => { + if !event.plugin_name.is_empty() { + self.plugin_name = event.plugin_name; + } + if !event.service_name.is_empty() { + self.service_name = event.service_name; + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::server::service_unregister::ServiceUnregisterEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::ServiceUnregister(ServiceUnregisterEvent { + plugin_name: self.plugin_name.clone(), + service_name: self.service_name.clone(), + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::ServiceUnregister(event) => { + if !event.plugin_name.is_empty() { + self.plugin_name = event.plugin_name; + } + if !event.service_name.is_empty() { + self.service_name = event.service_name; + } + } + _ => {} + } + Some(()) + } +} + impl PatchBukkitEvent for pumpkin::plugin::block::block_place::BlockPlaceEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { let player_uuid = self.player.gameprofile.id.to_string(); diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index 29347fe..48f0963 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -1367,6 +1367,74 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } + "org.bukkit.event.server.PluginEnableEvent" => { + context + .register_event::< + pumpkin::plugin::server::plugin_enable::PluginEnableEvent, + PatchBukkitEventHandler< + pumpkin::plugin::server::plugin_enable::PluginEnableEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.server.PluginDisableEvent" => { + context + .register_event::< + pumpkin::plugin::server::plugin_disable::PluginDisableEvent, + PatchBukkitEventHandler< + pumpkin::plugin::server::plugin_disable::PluginDisableEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.server.ServiceRegisterEvent" => { + context + .register_event::< + pumpkin::plugin::server::service_register::ServiceRegisterEvent, + PatchBukkitEventHandler< + pumpkin::plugin::server::service_register::ServiceRegisterEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.server.ServiceUnregisterEvent" => { + context + .register_event::< + pumpkin::plugin::server::service_unregister::ServiceUnregisterEvent, + PatchBukkitEventHandler< + pumpkin::plugin::server::service_unregister::ServiceUnregisterEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } "org.bukkit.event.block.BlockCanBuildEvent" => { context .register_event::< From 60c3925eab8dc071019d03e1d6a4bac3235ee540 Mon Sep 17 00:00:00 2001 From: yunuservices Date: Thu, 5 Feb 2026 14:48:24 +0300 Subject: [PATCH 47/56] Restore rust Cargo.toml to upstream deps --- rust/Cargo.toml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 39fc8e0..65178bf 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -9,11 +9,11 @@ build = "build/main.rs" crate-type = ["cdylib"] [dependencies] -pumpkin = { path = "../../Pumpkin/pumpkin", package = "pumpkin" } -pumpkin-data = { path = "../../Pumpkin/pumpkin-data", package = "pumpkin-data" } -pumpkin-protocol = { path = "../../Pumpkin/pumpkin-protocol", package = "pumpkin-protocol" } -pumpkin-util = { path = "../../Pumpkin/pumpkin-util", package = "pumpkin-util" } -pumpkin-api-macros = { path = "../../Pumpkin/pumpkin-api-macros", package = "pumpkin-api-macros" } +pumpkin = { git = "https://github.com/Pumpkin-MC/Pumpkin.git", branch = "master", package = "pumpkin" } +pumpkin-data = { git = "https://github.com/Pumpkin-MC/Pumpkin.git", branch = "master", package = "pumpkin-data" } +pumpkin-protocol = { git = "https://github.com/Pumpkin-MC/Pumpkin.git", branch = "master", package = "pumpkin-protocol" } +pumpkin-util = { git = "https://github.com/Pumpkin-MC/Pumpkin.git", branch = "master", package = "pumpkin-util" } +pumpkin-api-macros = { git = "https://github.com/Pumpkin-MC/Pumpkin.git", branch = "master", package = "pumpkin-api-macros" } tokio = "1" log = "0.4" From 271da003f856524961611a76901f0c82fd34e540 Mon Sep 17 00:00:00 2001 From: yunuservices Date: Thu, 5 Feb 2026 21:21:26 +0300 Subject: [PATCH 48/56] Fix event compatibility and java bridge helpers --- .../org/patchbukkit/bridge/BridgeUtils.java | 16 + .../entity/PatchBukkitAbstractArrow.java | 26 + .../patchbukkit/entity/PatchBukkitItem.java | 34 + .../events/PatchBukkitEventFactory.java | 801 ++++++++++++++++-- .../events/PatchBukkitEventManager.java | 328 +++++-- .../patchbukkit/world/PatchBukkitBlock.java | 3 +- proto/google/protobuf/empty.proto | 5 + proto/google/protobuf/wrappers.proto | 13 + 8 files changed, 1086 insertions(+), 140 deletions(-) create mode 100644 proto/google/protobuf/empty.proto create mode 100644 proto/google/protobuf/wrappers.proto diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/bridge/BridgeUtils.java b/java/patchbukkit/src/main/java/org/patchbukkit/bridge/BridgeUtils.java index bf3b8b8..3389110 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/bridge/BridgeUtils.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/bridge/BridgeUtils.java @@ -53,4 +53,20 @@ public static patchbukkit.common.Location convertLocation(Location location) { .setPitch(location.getPitch()) .build(); } + + public static PatchBukkitWorld convertWorld(patchbukkit.common.World world) { + if (world == null || world.getUuid() == null) { + return null; + } + return PatchBukkitWorld.getOrCreate(convertUuid(world.getUuid())); + } + + public static patchbukkit.common.World convertWorld(org.bukkit.World world) { + if (world == null) { + return null; + } + return patchbukkit.common.World.newBuilder() + .setUuid(convertUuid(world.getUID())) + .build(); + } } diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitAbstractArrow.java b/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitAbstractArrow.java index 85683c2..a2497d8 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitAbstractArrow.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitAbstractArrow.java @@ -7,6 +7,9 @@ import org.bukkit.block.Block; import org.bukkit.entity.AbstractArrow; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; +import java.util.Collections; +import java.util.List; public class PatchBukkitAbstractArrow extends PatchBukkitProjectile implements AbstractArrow { private PickupStatus pickupStatus = PickupStatus.ALLOWED; @@ -30,6 +33,11 @@ public Block getAttachedBlock() { return null; } + @Override + public @NotNull List getAttachedBlocks() { + return Collections.emptyList(); + } + public double getDamage() { return damage; } @@ -92,6 +100,16 @@ public void setItem(ItemStack item) { } } + @Override + public @NotNull ItemStack getItemStack() { + return getItem(); + } + + @Override + public void setItemStack(@NotNull ItemStack stack) { + setItem(stack); + } + public ItemStack getWeapon() { return weapon != null ? weapon : item; } @@ -125,4 +143,12 @@ public int getLifetimeTicks() { public void setLifetimeTicks(int ticks) { this.lifetimeTicks = ticks; } + + @Override + public void setShooter(org.bukkit.projectiles.ProjectileSource shooter, boolean update) { + setShooter(shooter); + if (update) { + setHasBeenShot(true); + } + } } diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitItem.java b/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitItem.java index 1e5e849..44a7cf1 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitItem.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitItem.java @@ -4,6 +4,7 @@ import org.bukkit.entity.Item; import org.bukkit.inventory.ItemStack; +import net.kyori.adventure.util.TriState; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -15,6 +16,9 @@ public class PatchBukkitItem extends PatchBukkitEntity implements Item { private boolean canPlayerPickup = true; private UUID owner; private UUID thrower; + private int health = 5; + private boolean willAge = true; + private TriState frictionState = TriState.NOT_SET; public PatchBukkitItem(@NotNull UUID uuid, @NotNull ItemStack itemStack) { super(uuid, "ITEM"); @@ -90,4 +94,34 @@ public void setThrower(@Nullable UUID thrower) { public @Nullable UUID getThrower() { return thrower; } + + @Override + public int getHealth() { + return health; + } + + @Override + public void setHealth(int health) { + this.health = health; + } + + @Override + public boolean willAge() { + return willAge; + } + + @Override + public void setWillAge(boolean value) { + this.willAge = value; + } + + @Override + public @NotNull TriState getFrictionState() { + return frictionState; + } + + @Override + public void setFrictionState(@NotNull TriState state) { + this.frictionState = state; + } } diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index 97f8c59..99cdc2b 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -330,7 +330,11 @@ public static org.bukkit.event.Event createEvent(@NotNull Event event) { Location bedLocation = BridgeUtils.convertLocation(bedEvent.getBedLocation()); if (bedLocation == null) yield null; if (bedLocation.getWorld() == null) yield null; - yield new PlayerBedEnterEvent(player, bedLocation.getBlock()); + org.bukkit.event.Event created = createPlayerBedEnterEvent(player, bedLocation.getBlock()); + if (created instanceof PlayerBedEnterEvent) { + yield created; + } + yield null; } case PLAYER_BED_LEAVE -> { patchbukkit.events.PlayerBedLeaveEvent bedEvent = event.getPlayerBedLeave(); @@ -339,7 +343,11 @@ public static org.bukkit.event.Event createEvent(@NotNull Event event) { Location bedLocation = BridgeUtils.convertLocation(bedEvent.getBedLocation()); if (bedLocation == null) yield null; if (bedLocation.getWorld() == null) yield null; - yield new PlayerBedLeaveEvent(player, bedLocation.getBlock()); + org.bukkit.event.Event created = createPlayerBedLeaveEvent(player, bedLocation.getBlock()); + if (created instanceof PlayerBedLeaveEvent) { + yield created; + } + yield null; } case PLAYER_BUCKET_EMPTY -> { patchbukkit.events.PlayerBucketEmptyEvent bucketEvent = event.getPlayerBucketEmpty(); @@ -773,7 +781,12 @@ yield new PlayerEggThrowEvent( PlayerResourcePackStatusEvent statusEvent = new PlayerResourcePackStatusEvent(player, packUuid, status); if (!packEvent.getHash().isEmpty()) { - statusEvent.setHash(packEvent.getHash()); + try { + java.lang.reflect.Method method = statusEvent.getClass().getMethod("setHash", String.class); + method.invoke(statusEvent, packEvent.getHash()); + } catch (ReflectiveOperationException ignored) { + // ignore + } } yield statusEvent; } @@ -864,7 +877,11 @@ yield new PlayerRespawnEvent( if (recipeEvent.getRecipeKey().isEmpty()) yield null; NamespacedKey key = NamespacedKey.fromString(recipeEvent.getRecipeKey()); if (key == null) yield null; - yield new PlayerRecipeDiscoverEvent(player, key); + org.bukkit.event.Event created = createPlayerRecipeDiscoverEvent(player, key); + if (created instanceof PlayerRecipeDiscoverEvent) { + yield created; + } + yield null; } case PLAYER_RIPTIDE -> { patchbukkit.events.PlayerRiptideEvent riptideEvent = event.getPlayerRiptide(); @@ -901,7 +918,11 @@ yield new PlayerRespawnEvent( slot = EquipmentSlot.HAND; } } - yield new PlayerShearEntityEvent(player, entity, item, slot); + org.bukkit.event.Event created = createPlayerShearEntityEvent(player, entity, item, slot); + if (created instanceof PlayerShearEntityEvent) { + yield created; + } + yield null; } case PLAYER_SPAWN_LOCATION -> { patchbukkit.events.PlayerSpawnLocationEvent spawnEvent = event.getPlayerSpawnLocation(); @@ -1083,7 +1104,11 @@ yield new PlayerStatisticIncrementEvent( } } - yield new BlockDamageEvent(block, player, item, damageEvent.getInstaBreak()); + org.bukkit.event.Event created = createBlockDamageEvent(block, player, item, damageEvent.getInstaBreak()); + if (created instanceof BlockDamageEvent) { + yield created; + } + yield null; } case BLOCK_DAMAGE_ABORT -> { patchbukkit.events.BlockDamageAbortEvent damageAbortEvent = event.getBlockDamageAbort(); @@ -1114,7 +1139,11 @@ yield new PlayerStatisticIncrementEvent( } } - yield new BlockDamageAbortEvent(block, player, item); + org.bukkit.event.Event created = createBlockDamageAbortEvent(block, player, item); + if (created instanceof BlockDamageAbortEvent) { + yield created; + } + yield null; } case BLOCK_DISPENSE -> { patchbukkit.events.BlockDispenseEvent dispenseEvent = event.getBlockDispense(); @@ -1184,7 +1213,11 @@ yield new PlayerStatisticIncrementEvent( items.add(itemEntity); } - yield new BlockDropItemEvent(block, player, items); + org.bukkit.event.Event created = createBlockDropItemEvent(block, player, items); + if (created instanceof BlockDropItemEvent) { + yield created; + } + yield null; } case BLOCK_EXPLODE -> { patchbukkit.events.BlockExplodeEvent explodeEvent = event.getBlockExplode(); @@ -1220,7 +1253,11 @@ yield new PlayerStatisticIncrementEvent( blockList.add(entryBlock); } - yield new BlockExplodeEvent(block, blockList, explodeEvent.getYield()); + org.bukkit.event.Event created = createBlockExplodeEvent(block, blockList, explodeEvent.getYield()); + if (created instanceof BlockExplodeEvent) { + yield created; + } + yield null; } case BLOCK_FADE -> { patchbukkit.events.BlockFadeEvent fadeEvent = event.getBlockFade(); @@ -1400,7 +1437,24 @@ yield new PlayerStatisticIncrementEvent( ); blocks.add(entryBlock); } - yield new BlockPistonExtendEvent(block, blocks, extendEvent.getLength()); + BlockFace face = BlockFace.SELF; + if (!extendEvent.getDirection().isEmpty()) { + try { + face = BlockFace.valueOf(extendEvent.getDirection()); + } catch (IllegalArgumentException ignored) { + face = BlockFace.SELF; + } + } + org.bukkit.event.Event created = createBlockPistonExtendEvent( + block, + blocks, + extendEvent.getLength(), + face + ); + if (created instanceof BlockPistonExtendEvent) { + yield created; + } + yield null; } case BLOCK_PISTON_RETRACT -> { patchbukkit.events.BlockPistonRetractEvent retractEvent = event.getBlockPistonRetract(); @@ -1433,7 +1487,24 @@ yield new PlayerStatisticIncrementEvent( ); blocks.add(entryBlock); } - yield new BlockPistonRetractEvent(block, blocks, retractEvent.getLength()); + BlockFace face = BlockFace.SELF; + if (!retractEvent.getDirection().isEmpty()) { + try { + face = BlockFace.valueOf(retractEvent.getDirection()); + } catch (IllegalArgumentException ignored) { + face = BlockFace.SELF; + } + } + org.bukkit.event.Event created = createBlockPistonRetractEvent( + block, + blocks, + retractEvent.getLength(), + face + ); + if (created instanceof BlockPistonRetractEvent) { + yield created; + } + yield null; } case BLOCK_REDSTONE -> { patchbukkit.events.BlockRedstoneEvent redstoneEvent = event.getBlockRedstone(); @@ -1672,7 +1743,11 @@ yield new PlayerStatisticIncrementEvent( location.getBlockZ(), newKey ); - yield new FluidLevelChangeEvent(block, newBlock.getState()); + org.bukkit.event.Event created = createFluidLevelChangeEvent(block, newBlock); + if (created instanceof FluidLevelChangeEvent) { + yield created; + } + yield null; } case SPAWN_CHANGE -> { patchbukkit.events.SpawnChangeEvent spawnEvent = event.getSpawnChange(); @@ -1831,7 +1906,11 @@ yield new PlayerStatisticIncrementEvent( patchbukkit.events.EntityDeathEvent deathEvent = event.getEntityDeath(); java.util.UUID entityUuid = java.util.UUID.fromString(deathEvent.getEntityUuid().getValue()); PatchBukkitLivingEntity entity = new PatchBukkitLivingEntity(entityUuid, "Entity"); - yield new EntityDeathEvent(entity, java.util.Collections.emptyList(), 0); + org.bukkit.event.Event created = createEntityDeathEvent(entity); + if (created instanceof EntityDeathEvent) { + yield created; + } + yield null; } case SERVER_COMMAND -> { patchbukkit.events.ServerCommandEvent commandEvent = event.getServerCommand(); @@ -1841,7 +1920,11 @@ yield new PlayerStatisticIncrementEvent( patchbukkit.events.ServerBroadcastEvent broadcastEvent = event.getServerBroadcast(); Component messageComponent = GsonComponentSerializer.gson().deserialize(broadcastEvent.getMessage()); String message = PlainTextComponentSerializer.plainText().serialize(messageComponent); - yield new BroadcastMessageEvent(message); + org.bukkit.event.Event created = createBroadcastMessageEvent(messageComponent, message); + if (created instanceof BroadcastMessageEvent) { + yield created; + } + yield null; } case SERVER_LIST_PING -> { patchbukkit.events.ServerListPingEvent pingEvent = event.getServerListPing(); @@ -2219,7 +2302,7 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) String itemKey = item != null ? item.getType().getKey().toString() : "minecraft:air"; int itemAmount = item != null ? item.getAmount() : 0; String slot = mendEvent.getSlot() != null ? mendEvent.getSlot().name() : "HAND"; - var builder = patchbukkit.events.PlayerItemMendEvent.newBuilder() + var eventBuilderLocal = patchbukkit.events.PlayerItemMendEvent.newBuilder() .setPlayerUuid(UUID.newBuilder() .setValue(mendEvent.getPlayer().getUniqueId().toString()) .build()) @@ -2228,11 +2311,11 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .setSlot(slot) .setRepairAmount(mendEvent.getRepairAmount()); if (mendEvent.getExperienceOrb() != null) { - builder.setOrbUuid(UUID.newBuilder() + eventBuilderLocal.setOrbUuid(UUID.newBuilder() .setValue(mendEvent.getExperienceOrb().getUniqueId().toString()) .build()); } - eventBuilder.setPlayerItemMend(builder.build()); + eventBuilder.setPlayerItemMend(eventBuilderLocal.build()); } else if (event instanceof PlayerLevelChangeEvent levelEvent) { eventBuilder.setPlayerLevelChange( patchbukkit.events.PlayerLevelChangeEvent.newBuilder() @@ -2541,12 +2624,12 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .build() ); } else if (event instanceof PlayerCommandSendEvent commandSendEvent) { - var builder = patchbukkit.events.PlayerCommandSendEvent.newBuilder() + var eventBuilderLocal = patchbukkit.events.PlayerCommandSendEvent.newBuilder() .setPlayerUuid(UUID.newBuilder() .setValue(commandSendEvent.getPlayer().getUniqueId().toString()) .build()); - builder.addAllCommands(commandSendEvent.getCommands()); - eventBuilder.setPlayerCommandSend(builder.build()); + eventBuilderLocal.addAllCommands(commandSendEvent.getCommands()); + eventBuilder.setPlayerCommandSend(eventBuilderLocal.build()); } else if (event instanceof PlayerDropItemEvent dropEvent) { var item = dropEvent.getItemDrop(); String itemKey = "minecraft:air"; @@ -2642,7 +2725,7 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) } else if (event instanceof PlayerInteractAtEntityEvent interactEvent) { var entity = interactEvent.getRightClicked(); var pos = interactEvent.getClickedPosition(); - var builder = patchbukkit.events.PlayerInteractAtEntityEvent.newBuilder() + var eventBuilderLocal = patchbukkit.events.PlayerInteractAtEntityEvent.newBuilder() .setPlayerUuid(UUID.newBuilder() .setValue(interactEvent.getPlayer().getUniqueId().toString()) .build()) @@ -2651,19 +2734,19 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .build()) .setEntityType(entity.getType().name()); if (interactEvent.getHand() != null) { - builder.setHand(interactEvent.getHand().name()); + eventBuilderLocal.setHand(interactEvent.getHand().name()); } if (pos != null) { - builder.setClickedPosition(patchbukkit.common.Vec3.newBuilder() + eventBuilderLocal.setClickedPosition(patchbukkit.common.Vec3.newBuilder() .setX(pos.getX()) .setY(pos.getY()) .setZ(pos.getZ()) .build()); } - eventBuilder.setPlayerInteractAtEntity(builder.build()); + eventBuilder.setPlayerInteractAtEntity(eventBuilderLocal.build()); } else if (event instanceof PlayerInteractEntityEvent interactEvent) { var entity = interactEvent.getRightClicked(); - var builder = patchbukkit.events.PlayerInteractEntityEvent.newBuilder() + var eventBuilderLocal = patchbukkit.events.PlayerInteractEntityEvent.newBuilder() .setPlayerUuid(UUID.newBuilder() .setValue(interactEvent.getPlayer().getUniqueId().toString()) .build()) @@ -2672,9 +2755,9 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .build()) .setEntityType(entity.getType().name()); if (interactEvent.getHand() != null) { - builder.setHand(interactEvent.getHand().name()); + eventBuilderLocal.setHand(interactEvent.getHand().name()); } - eventBuilder.setPlayerInteractEntity(builder.build()); + eventBuilder.setPlayerInteractEntity(eventBuilderLocal.build()); } else if (event instanceof PlayerInteractEvent interactEvent) { var block = interactEvent.getClickedBlock(); var location = block != null ? block.getLocation() : null; @@ -2722,7 +2805,7 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) .setBlockKey(block.getType().getKey().toString()) .setLocation(BridgeUtils.convertLocation(block.getLocation())) .setItemKey(itemKey) - .setInstaBreak(damageEvent.isInstaBreak()) + .setInstaBreak(resolveInstaBreak(damageEvent)) .build() ); } else if (event instanceof BlockDamageAbortEvent damageAbortEvent) { @@ -2760,7 +2843,7 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) ); } else if (event instanceof BlockDropItemEvent dropItemEvent) { var block = dropItemEvent.getBlock(); - var builder = patchbukkit.events.BlockDropItemEvent.newBuilder() + var eventBuilderLocal = patchbukkit.events.BlockDropItemEvent.newBuilder() .setPlayerUuid(UUID.newBuilder() .setValue(dropItemEvent.getPlayer().getUniqueId().toString()) .build()) @@ -2770,7 +2853,7 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) for (org.bukkit.entity.Item item : dropItemEvent.getItems()) { ItemStack stack = item.getItemStack(); if (stack == null) continue; - builder.addItems( + eventBuilderLocal.addItems( patchbukkit.events.BlockDropItemEntry.newBuilder() .setItemKey(stack.getType().getKey().toString()) .setItemAmount(stack.getAmount()) @@ -2778,22 +2861,22 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) ); } - eventBuilder.setBlockDropItem(builder.build()); + eventBuilder.setBlockDropItem(eventBuilderLocal.build()); } else if (event instanceof BlockExplodeEvent explodeEvent) { var block = explodeEvent.getBlock(); - var builder = patchbukkit.events.BlockExplodeEvent.newBuilder() + var eventBuilderLocal = patchbukkit.events.BlockExplodeEvent.newBuilder() .setBlockKey(block.getType().getKey().toString()) .setLocation(BridgeUtils.convertLocation(block.getLocation())) .setYield(explodeEvent.getYield()); for (Block b : explodeEvent.blockList()) { - builder.addBlocks( + eventBuilderLocal.addBlocks( patchbukkit.events.BlockExplodeBlockEntry.newBuilder() .setBlockKey(b.getType().getKey().toString()) .setLocation(BridgeUtils.convertLocation(b.getLocation())) .build() ); } - eventBuilder.setBlockExplode(builder.build()); + eventBuilder.setBlockExplode(eventBuilderLocal.build()); } else if (event instanceof BlockFadeEvent fadeEvent) { var block = fadeEvent.getBlock(); var newState = fadeEvent.getNewState(); @@ -2806,21 +2889,21 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) ); } else if (event instanceof BlockFertilizeEvent fertilizeEvent) { var block = fertilizeEvent.getBlock(); - var builder = patchbukkit.events.BlockFertilizeEvent.newBuilder() + var eventBuilderLocal = patchbukkit.events.BlockFertilizeEvent.newBuilder() .setPlayerUuid(UUID.newBuilder() .setValue(fertilizeEvent.getPlayer().getUniqueId().toString()) .build()) .setBlockKey(block.getType().getKey().toString()) .setLocation(BridgeUtils.convertLocation(block.getLocation())); for (org.bukkit.block.BlockState state : fertilizeEvent.getBlocks()) { - builder.addBlocks( + eventBuilderLocal.addBlocks( patchbukkit.events.BlockFertilizeBlockEntry.newBuilder() .setBlockKey(state.getType().getKey().toString()) .setLocation(BridgeUtils.convertLocation(state.getLocation())) .build() ); } - eventBuilder.setBlockFertilize(builder.build()); + eventBuilder.setBlockFertilize(eventBuilderLocal.build()); } else if (event instanceof BlockFormEvent formEvent) { var block = formEvent.getBlock(); var newState = formEvent.getNewState(); @@ -2857,37 +2940,37 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) } else if (event instanceof BlockPistonExtendEvent extendEvent) { var block = extendEvent.getBlock(); String direction = extendEvent.getDirection() != null ? extendEvent.getDirection().name() : ""; - var builder = patchbukkit.events.BlockPistonExtendEvent.newBuilder() + var eventBuilderLocal = patchbukkit.events.BlockPistonExtendEvent.newBuilder() .setBlockKey(block.getType().getKey().toString()) .setLocation(BridgeUtils.convertLocation(block.getLocation())) .setDirection(direction) - .setLength(extendEvent.getLength()); + .setLength(resolvePistonLength(extendEvent)); for (Block b : extendEvent.getBlocks()) { - builder.addBlocks( + eventBuilderLocal.addBlocks( patchbukkit.events.BlockPistonBlockEntry.newBuilder() .setBlockKey(b.getType().getKey().toString()) .setLocation(BridgeUtils.convertLocation(b.getLocation())) .build() ); } - eventBuilder.setBlockPistonExtend(builder.build()); + eventBuilder.setBlockPistonExtend(eventBuilderLocal.build()); } else if (event instanceof BlockPistonRetractEvent retractEvent) { var block = retractEvent.getBlock(); String direction = retractEvent.getDirection() != null ? retractEvent.getDirection().name() : ""; - var builder = patchbukkit.events.BlockPistonRetractEvent.newBuilder() + var eventBuilderLocal = patchbukkit.events.BlockPistonRetractEvent.newBuilder() .setBlockKey(block.getType().getKey().toString()) .setLocation(BridgeUtils.convertLocation(block.getLocation())) .setDirection(direction) - .setLength(retractEvent.getLength()); + .setLength(resolvePistonLength(retractEvent)); for (Block b : retractEvent.getBlocks()) { - builder.addBlocks( + eventBuilderLocal.addBlocks( patchbukkit.events.BlockPistonBlockEntry.newBuilder() .setBlockKey(b.getType().getKey().toString()) .setLocation(BridgeUtils.convertLocation(b.getLocation())) .build() ); } - eventBuilder.setBlockPistonRetract(builder.build()); + eventBuilder.setBlockPistonRetract(eventBuilderLocal.build()); } else if (event instanceof BlockRedstoneEvent redstoneEvent) { var block = redstoneEvent.getBlock(); eventBuilder.setBlockRedstone( @@ -2900,29 +2983,29 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) ); } else if (event instanceof BlockMultiPlaceEvent multiEvent) { var block = multiEvent.getBlock(); - var builder = patchbukkit.events.BlockMultiPlaceEvent.newBuilder() + var eventBuilderLocal = patchbukkit.events.BlockMultiPlaceEvent.newBuilder() .setPlayerUuid(UUID.newBuilder() .setValue(multiEvent.getPlayer().getUniqueId().toString()) .build()) .setBlockKey(block.getType().getKey().toString()) .setLocation(BridgeUtils.convertLocation(block.getLocation())); - for (org.bukkit.block.BlockState state : multiEvent.getBlockStates()) { - builder.addBlocks( + for (org.bukkit.block.BlockState state : resolveMultiPlaceStates(multiEvent)) { + eventBuilderLocal.addBlocks( patchbukkit.events.BlockMultiPlaceBlockEntry.newBuilder() .setBlockKey(state.getType().getKey().toString()) .setLocation(BridgeUtils.convertLocation(state.getLocation())) .build() ); } - eventBuilder.setBlockMultiPlace(builder.build()); + eventBuilder.setBlockMultiPlace(eventBuilderLocal.build()); } else if (event instanceof BlockPhysicsEvent physicsEvent) { var block = physicsEvent.getBlock(); - var data = physicsEvent.getChangedType(); + Material sourceMaterial = resolvePhysicsChangedMaterial(physicsEvent); eventBuilder.setBlockPhysics( patchbukkit.events.BlockPhysicsEvent.newBuilder() .setBlockKey(block.getType().getKey().toString()) .setLocation(BridgeUtils.convertLocation(block.getLocation())) - .setSourceBlockKey(data.getMaterial().getKey().toString()) + .setSourceBlockKey(sourceMaterial.getKey().toString()) .setSourceLocation(BridgeUtils.convertLocation(block.getLocation())) .build() ); @@ -2939,37 +3022,37 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) } else if (event instanceof SignChangeEvent signEvent) { Block block = signEvent.getBlock(); String[] lines = signEvent.getLines(); - var builder = patchbukkit.events.SignChangeEvent.newBuilder() + var eventBuilderLocal = patchbukkit.events.SignChangeEvent.newBuilder() .setPlayerUuid(UUID.newBuilder() .setValue(signEvent.getPlayer().getUniqueId().toString()) .build()) .setBlockKey(block.getType().getKey().toString()) .setLocation(BridgeUtils.convertLocation(block.getLocation())); for (String line : lines) { - builder.addLines(line != null ? line : ""); + eventBuilderLocal.addLines(line != null ? line : ""); } try { java.lang.reflect.Method method = signEvent.getClass().getMethod("isFrontText"); Object value = method.invoke(signEvent); if (value instanceof Boolean b) { - builder.setIsFrontText(b); + eventBuilderLocal.setIsFrontText(b); } } catch (ReflectiveOperationException ignored) { - builder.setIsFrontText(true); + eventBuilderLocal.setIsFrontText(true); } - eventBuilder.setSignChange(builder.build()); + eventBuilder.setSignChange(eventBuilderLocal.build()); } else if (event instanceof TNTPrimeEvent tntEvent) { Block block = tntEvent.getBlock(); - var builder = patchbukkit.events.TNTPrimeEvent.newBuilder() + var eventBuilderLocal = patchbukkit.events.TNTPrimeEvent.newBuilder() .setBlockKey(block.getType().getKey().toString()) .setLocation(BridgeUtils.convertLocation(block.getLocation())) .setCause(tntEvent.getCause().name()); if (tntEvent.getPrimingEntity() instanceof Player player) { - builder.setPlayerUuid(UUID.newBuilder() + eventBuilderLocal.setPlayerUuid(UUID.newBuilder() .setValue(player.getUniqueId().toString()) .build()); } - eventBuilder.setTntPrime(builder.build()); + eventBuilder.setTntPrime(eventBuilderLocal.build()); } else if (event instanceof MoistureChangeEvent moistureEvent) { Block block = moistureEvent.getBlock(); org.bukkit.block.BlockState newState = moistureEvent.getNewState(); @@ -2982,31 +3065,31 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) ); } else if (event instanceof SpongeAbsorbEvent spongeEvent) { Block block = spongeEvent.getBlock(); - var builder = patchbukkit.events.SpongeAbsorbEvent.newBuilder() + var eventBuilderLocal = patchbukkit.events.SpongeAbsorbEvent.newBuilder() .setBlockKey(block.getType().getKey().toString()) .setLocation(BridgeUtils.convertLocation(block.getLocation())); for (org.bukkit.block.BlockState state : spongeEvent.getBlocks()) { - builder.addBlocks( + eventBuilderLocal.addBlocks( patchbukkit.events.SpongeAbsorbBlockEntry.newBuilder() .setBlockKey(state.getType().getKey().toString()) .setLocation(BridgeUtils.convertLocation(state.getLocation())) .build() ); } - eventBuilder.setSpongeAbsorb(builder.build()); + eventBuilder.setSpongeAbsorb(eventBuilderLocal.build()); } else if (event instanceof FluidLevelChangeEvent fluidEvent) { Block block = fluidEvent.getBlock(); - org.bukkit.block.BlockState newState = fluidEvent.getNewState(); + String newBlockKey = resolveFluidNewBlockKey(fluidEvent); eventBuilder.setFluidLevelChange( patchbukkit.events.FluidLevelChangeEvent.newBuilder() .setBlockKey(block.getType().getKey().toString()) .setLocation(BridgeUtils.convertLocation(block.getLocation())) - .setNewBlockKey(newState.getType().getKey().toString()) + .setNewBlockKey(newBlockKey) .build() ); } else if (event instanceof SpawnChangeEvent spawnEvent) { - Location location = spawnEvent.getLocation(); - Location previous = spawnEvent.getPreviousLocation(); + Location location = resolveSpawnChangeLocation(spawnEvent); + Location previous = resolveSpawnChangePreviousLocation(spawnEvent, location); if (previous == null) { previous = location; } @@ -3145,7 +3228,7 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) onlinePlayers = count; } } catch (ReflectiveOperationException ignored) { - onlinePlayers = pingEvent.getServer().getOnlinePlayers().size(); + onlinePlayers = Bukkit.getOnlinePlayers().size(); } String favicon = ""; try { @@ -3356,6 +3439,200 @@ static Block resolveIgnitingBlock(@NotNull BlockBurnEvent event) { return null; } + @Nullable + static Block resolveIgnitingBlock(@NotNull BlockIgniteEvent event) { + try { + java.lang.reflect.Method method = event.getClass().getMethod("getIgnitingBlock"); + Object value = method.invoke(event); + if (value instanceof Block block) { + return block; + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + return null; + } + + private static boolean resolveInstaBreak(@NotNull BlockDamageEvent event) { + try { + java.lang.reflect.Method method = event.getClass().getMethod("isInstaBreak"); + Object value = method.invoke(event); + if (value instanceof Boolean bool) { + return bool; + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + return false; + } + + private static int resolvePistonLength(@NotNull Object pistonEvent) { + try { + java.lang.reflect.Method method = pistonEvent.getClass().getMethod("getLength"); + Object value = method.invoke(pistonEvent); + if (value instanceof Integer len) { + return len; + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + java.lang.reflect.Method method = pistonEvent.getClass().getMethod("getBlocks"); + Object value = method.invoke(pistonEvent); + if (value instanceof java.util.List list) { + return list.size(); + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + return 0; + } + + @NotNull + private static java.util.List resolveMultiPlaceStates(@NotNull BlockMultiPlaceEvent event) { + try { + java.lang.reflect.Method method = event.getClass().getMethod("getBlockStates"); + Object value = method.invoke(event); + if (value instanceof java.util.List list) { + java.util.List states = new java.util.ArrayList<>(); + for (Object entry : list) { + if (entry instanceof org.bukkit.block.BlockState state) { + states.add(state); + } + } + return states; + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + java.lang.reflect.Method method = event.getClass().getMethod("getReplacedBlockStates"); + Object value = method.invoke(event); + if (value instanceof java.util.List list) { + java.util.List states = new java.util.ArrayList<>(); + for (Object entry : list) { + if (entry instanceof org.bukkit.block.BlockState state) { + states.add(state); + } + } + return states; + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + return java.util.Collections.emptyList(); + } + + @NotNull + private static Material resolvePhysicsChangedMaterial(@NotNull BlockPhysicsEvent event) { + try { + Object changed = event.getChangedType(); + if (changed instanceof Material material) { + return material; + } + if (changed != null) { + java.lang.reflect.Method method = changed.getClass().getMethod("getMaterial"); + Object value = method.invoke(changed); + if (value instanceof Material material) { + return material; + } + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + return event.getBlock().getType(); + } + + @NotNull + private static String resolveFluidNewBlockKey(@NotNull FluidLevelChangeEvent event) { + try { + java.lang.reflect.Method method = event.getClass().getMethod("getNewState"); + Object value = method.invoke(event); + if (value instanceof org.bukkit.block.BlockState state) { + return state.getType().getKey().toString(); + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + java.lang.reflect.Method method = event.getClass().getMethod("getNewData"); + Object value = method.invoke(event); + if (value instanceof org.bukkit.block.data.BlockData data) { + return data.getMaterial().getKey().toString(); + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + java.lang.reflect.Method method = event.getClass().getMethod("getNewBlockData"); + Object value = method.invoke(event); + if (value instanceof org.bukkit.block.data.BlockData data) { + return data.getMaterial().getKey().toString(); + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + return event.getBlock().getType().getKey().toString(); + } + + @Nullable + private static Location resolveSpawnChangeLocation(@NotNull SpawnChangeEvent event) { + try { + java.lang.reflect.Method method = event.getClass().getMethod("getLocation"); + Object value = method.invoke(event); + if (value instanceof Location location) { + return location; + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + java.lang.reflect.Method method = event.getClass().getMethod("getNewLocation"); + Object value = method.invoke(event); + if (value instanceof Location location) { + return location; + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + java.lang.reflect.Method method = event.getClass().getMethod("getNewSpawn"); + Object value = method.invoke(event); + if (value instanceof Location location) { + return location; + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + return event.getWorld() != null ? event.getWorld().getSpawnLocation() : null; + } + + @Nullable + private static Location resolveSpawnChangePreviousLocation( + @NotNull SpawnChangeEvent event, + @Nullable Location fallback + ) { + try { + java.lang.reflect.Method method = event.getClass().getMethod("getPreviousLocation"); + Object value = method.invoke(event); + if (value instanceof Location location) { + return location; + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + java.lang.reflect.Method method = event.getClass().getMethod("getPreviousSpawn"); + Object value = method.invoke(event); + if (value instanceof Location location) { + return location; + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + return fallback; + } + @Nullable private static org.bukkit.event.Event createHarvestBlockEvent( @NotNull Player player, @@ -3551,6 +3828,391 @@ private static org.bukkit.event.Event createServerListPingEvent( return null; } + @Nullable + private static org.bukkit.event.Event createPlayerBedEnterEvent( + @NotNull Player player, + @NotNull Block bed + ) { + try { + java.lang.reflect.Constructor ctor = + PlayerBedEnterEvent.class.getConstructor(Player.class, Block.class); + return ctor.newInstance(player, bed); + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + Class resultClass = Class.forName("org.bukkit.event.player.PlayerBedEnterEvent$BedEnterResult"); + Class actionClass = Class.forName("org.bukkit.event.player.PlayerBedEnterEvent$BedEnterAction"); + Object result = firstEnumConstant(resultClass, "OK"); + Object action = firstEnumConstant(actionClass, "RIGHT_CLICK"); + java.lang.reflect.Constructor ctor = + PlayerBedEnterEvent.class.getConstructor(Player.class, Block.class, resultClass, actionClass); + return ctor.newInstance(player, bed, result, action); + } catch (ReflectiveOperationException ignored) { + // ignore + } + return null; + } + + @Nullable + private static org.bukkit.event.Event createPlayerBedLeaveEvent( + @NotNull Player player, + @NotNull Block bed + ) { + try { + java.lang.reflect.Constructor ctor = + PlayerBedLeaveEvent.class.getConstructor(Player.class, Block.class, boolean.class); + return ctor.newInstance(player, bed, false); + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + java.lang.reflect.Constructor ctor = + PlayerBedLeaveEvent.class.getConstructor(Player.class, Block.class); + return ctor.newInstance(player, bed); + } catch (ReflectiveOperationException ignored) { + // ignore + } + return null; + } + + @Nullable + private static org.bukkit.event.Event createPlayerRecipeDiscoverEvent( + @NotNull Player player, + @NotNull NamespacedKey key + ) { + try { + java.lang.reflect.Constructor ctor = + PlayerRecipeDiscoverEvent.class.getConstructor(Player.class, NamespacedKey.class, boolean.class); + return ctor.newInstance(player, key, false); + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + java.lang.reflect.Constructor ctor = + PlayerRecipeDiscoverEvent.class.getConstructor(Player.class, NamespacedKey.class); + return ctor.newInstance(player, key); + } catch (ReflectiveOperationException ignored) { + // ignore + } + return null; + } + + @Nullable + private static org.bukkit.event.Event createPlayerShearEntityEvent( + @NotNull Player player, + @NotNull Entity entity, + @NotNull ItemStack item, + @NotNull EquipmentSlot slot + ) { + try { + java.lang.reflect.Constructor ctor = + PlayerShearEntityEvent.class.getConstructor( + Player.class, + Entity.class, + ItemStack.class, + EquipmentSlot.class, + java.util.List.class + ); + return ctor.newInstance(player, entity, item, slot, java.util.Collections.emptyList()); + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + java.lang.reflect.Constructor ctor = + PlayerShearEntityEvent.class.getConstructor(Player.class, Entity.class, ItemStack.class, EquipmentSlot.class); + return ctor.newInstance(player, entity, item, slot); + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + java.lang.reflect.Constructor ctor = + PlayerShearEntityEvent.class.getConstructor(Player.class, Entity.class); + return ctor.newInstance(player, entity); + } catch (ReflectiveOperationException ignored) { + // ignore + } + return null; + } + + @Nullable + private static org.bukkit.event.Event createBlockDamageEvent( + @NotNull Block block, + @NotNull Player player, + @Nullable ItemStack item, + boolean instaBreak + ) { + try { + java.lang.reflect.Constructor ctor = + BlockDamageEvent.class.getConstructor(Player.class, Block.class, ItemStack.class, boolean.class); + return ctor.newInstance(player, block, item, instaBreak); + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + java.lang.reflect.Constructor ctor = + BlockDamageEvent.class.getConstructor(Block.class, Player.class, ItemStack.class, boolean.class); + return ctor.newInstance(block, player, item, instaBreak); + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + java.lang.reflect.Constructor ctor = + BlockDamageEvent.class.getConstructor(Block.class, Player.class, ItemStack.class); + return ctor.newInstance(block, player, item); + } catch (ReflectiveOperationException ignored) { + // ignore + } + return null; + } + + @Nullable + private static org.bukkit.event.Event createBlockDamageAbortEvent( + @NotNull Block block, + @NotNull Player player, + @Nullable ItemStack item + ) { + try { + java.lang.reflect.Constructor ctor = + BlockDamageAbortEvent.class.getConstructor(Player.class, Block.class, ItemStack.class); + return ctor.newInstance(player, block, item); + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + java.lang.reflect.Constructor ctor = + BlockDamageAbortEvent.class.getConstructor(Block.class, Player.class, ItemStack.class); + return ctor.newInstance(block, player, item); + } catch (ReflectiveOperationException ignored) { + // ignore + } + return null; + } + + @Nullable + private static org.bukkit.event.Event createBlockDropItemEvent( + @NotNull Block block, + @NotNull Player player, + @NotNull java.util.List items + ) { + try { + java.lang.reflect.Constructor ctor = + BlockDropItemEvent.class.getConstructor(Block.class, org.bukkit.block.BlockState.class, Player.class, java.util.List.class); + return ctor.newInstance(block, block.getState(), player, items); + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + java.lang.reflect.Constructor ctor = + BlockDropItemEvent.class.getConstructor(Block.class, Player.class, java.util.List.class); + return ctor.newInstance(block, player, items); + } catch (ReflectiveOperationException ignored) { + // ignore + } + return null; + } + + @Nullable + private static org.bukkit.event.Event createBlockExplodeEvent( + @NotNull Block block, + @NotNull java.util.List blocks, + float yield + ) { + try { + java.lang.reflect.Constructor ctor = + BlockExplodeEvent.class.getConstructor(Block.class, org.bukkit.block.BlockState.class, java.util.List.class, float.class); + return ctor.newInstance(block, block.getState(), blocks, yield); + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + Class resultClass = Class.forName("org.bukkit.event.block.BlockExplodeEvent$ExplosionResult"); + Object result = firstEnumConstant(resultClass, "DESTROY"); + java.lang.reflect.Constructor ctor = + BlockExplodeEvent.class.getConstructor(Block.class, org.bukkit.block.BlockState.class, java.util.List.class, float.class, resultClass); + return ctor.newInstance(block, block.getState(), blocks, yield, result); + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + java.lang.reflect.Constructor ctor = + BlockExplodeEvent.class.getConstructor(Block.class, java.util.List.class, float.class); + return ctor.newInstance(block, blocks, yield); + } catch (ReflectiveOperationException ignored) { + // ignore + } + return null; + } + + @Nullable + private static org.bukkit.event.Event createBlockPistonExtendEvent( + @NotNull Block block, + @NotNull java.util.List blocks, + int length, + @NotNull BlockFace face + ) { + try { + java.lang.reflect.Constructor ctor = + BlockPistonExtendEvent.class.getConstructor(Block.class, java.util.List.class, BlockFace.class); + return ctor.newInstance(block, blocks, face); + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + java.lang.reflect.Constructor ctor = + BlockPistonExtendEvent.class.getConstructor(Block.class, int.class, BlockFace.class); + return ctor.newInstance(block, length, face); + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + java.lang.reflect.Constructor ctor = + BlockPistonExtendEvent.class.getConstructor(Block.class, java.util.List.class, int.class); + return ctor.newInstance(block, blocks, length); + } catch (ReflectiveOperationException ignored) { + // ignore + } + return null; + } + + @Nullable + private static org.bukkit.event.Event createBlockPistonRetractEvent( + @NotNull Block block, + @NotNull java.util.List blocks, + int length, + @NotNull BlockFace face + ) { + try { + java.lang.reflect.Constructor ctor = + BlockPistonRetractEvent.class.getConstructor(Block.class, java.util.List.class, BlockFace.class); + return ctor.newInstance(block, blocks, face); + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + java.lang.reflect.Constructor ctor = + BlockPistonRetractEvent.class.getConstructor(Block.class, int.class, BlockFace.class); + return ctor.newInstance(block, length, face); + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + java.lang.reflect.Constructor ctor = + BlockPistonRetractEvent.class.getConstructor(Block.class, java.util.List.class, int.class); + return ctor.newInstance(block, blocks, length); + } catch (ReflectiveOperationException ignored) { + // ignore + } + return null; + } + + @Nullable + private static org.bukkit.event.Event createFluidLevelChangeEvent( + @NotNull Block block, + @NotNull Block newBlock + ) { + try { + java.lang.reflect.Constructor ctor = + FluidLevelChangeEvent.class.getConstructor(Block.class, org.bukkit.block.data.BlockData.class); + return ctor.newInstance(block, newBlock.getBlockData()); + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + java.lang.reflect.Constructor ctor = + FluidLevelChangeEvent.class.getConstructor(Block.class, org.bukkit.block.BlockState.class); + return ctor.newInstance(block, newBlock.getState()); + } catch (ReflectiveOperationException ignored) { + // ignore + } + return null; + } + + @Nullable + private static org.bukkit.event.Event createEntityDeathEvent(@NotNull org.bukkit.entity.LivingEntity entity) { + java.util.List drops = java.util.Collections.emptyList(); + int exp = 0; + try { + java.lang.reflect.Constructor ctor = + EntityDeathEvent.class.getConstructor(org.bukkit.entity.LivingEntity.class, java.util.List.class, int.class); + return ctor.newInstance(entity, drops, exp); + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + Class damageSourceClass = Class.forName("org.bukkit.damage.DamageSource"); + java.lang.reflect.Constructor ctor = + EntityDeathEvent.class.getConstructor( + org.bukkit.entity.LivingEntity.class, + java.util.List.class, + int.class, + damageSourceClass + ); + return ctor.newInstance(entity, drops, exp, null); + } catch (ReflectiveOperationException ignored) { + // ignore + } + return null; + } + + @Nullable + private static org.bukkit.event.Event createBroadcastMessageEvent( + @NotNull Component messageComponent, + @NotNull String message + ) { + java.util.Set recipients = java.util.Collections.emptySet(); + try { + java.lang.reflect.Constructor ctor = + BroadcastMessageEvent.class.getConstructor(String.class, java.util.Set.class); + return ctor.newInstance(message, recipients); + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + java.lang.reflect.Constructor ctor = + BroadcastMessageEvent.class.getConstructor(boolean.class, String.class, java.util.Set.class); + return ctor.newInstance(false, message, recipients); + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + java.lang.reflect.Constructor ctor = + BroadcastMessageEvent.class.getConstructor(Component.class, java.util.Set.class); + return ctor.newInstance(messageComponent, recipients); + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + java.lang.reflect.Constructor ctor = + BroadcastMessageEvent.class.getConstructor(boolean.class, Component.class, java.util.Set.class); + return ctor.newInstance(false, messageComponent, recipients); + } catch (ReflectiveOperationException ignored) { + // ignore + } + return null; + } + + @Nullable + private static Object firstEnumConstant(@NotNull Class enumClass, @Nullable String preferredName) { + if (!enumClass.isEnum()) { + return null; + } + Object[] values = enumClass.getEnumConstants(); + if (values == null || values.length == 0) { + return null; + } + if (preferredName != null) { + try { + @SuppressWarnings("unchecked") + Object value = Enum.valueOf((Class) enumClass, preferredName); + return value; + } catch (IllegalArgumentException ignored) { + // ignore + } + } + return values[0]; + } + @Nullable private static RegisteredServiceProvider resolveServiceProvider( @NotNull String serviceName, @@ -3619,7 +4281,10 @@ private static RegisteredServiceProvider createFallbackServiceProvider( continue; } try { - Object created = ctor.newInstance(serviceClass, instance, ServicePriority.NORMAL, plugin); + ServicePriority priority = ServicePriority.values().length > 0 + ? ServicePriority.values()[0] + : null; + Object created = ctor.newInstance(serviceClass, instance, priority, plugin); if (created instanceof RegisteredServiceProvider provider) { return provider; } 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 711fc4b..67625e3 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -1,6 +1,8 @@ package org.patchbukkit.events; import org.bukkit.Server; +import org.bukkit.Bukkit; +import org.bukkit.Material; import org.bukkit.Warning; import org.bukkit.event.Event; import org.bukkit.event.EventHandler; @@ -25,6 +27,7 @@ import co.aikar.timings.TimedEventExecutor; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import patchbukkit.bridge.NativeBridgeFfi; import patchbukkit.events.CallEventRequest; import patchbukkit.events.PlayerChatEvent; @@ -58,7 +61,7 @@ import patchbukkit.events.BlockPlaceEvent; import patchbukkit.events.NotePlayEvent; import patchbukkit.events.SignChangeEvent; -import patchbukkit.events.TntPrimeEvent; +import patchbukkit.events.TNTPrimeEvent; import patchbukkit.events.MoistureChangeEvent; import patchbukkit.events.SpongeAbsorbEvent; import patchbukkit.events.SpongeAbsorbBlockEntry; @@ -569,8 +572,8 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ); break; case "org.bukkit.event.player.PlayerItemDamageEvent": - var damageEvent = (org.bukkit.event.player.PlayerItemDamageEvent) event; - var damageItem = damageEvent.getItem(); + var playerItemDamageEvent = (org.bukkit.event.player.PlayerItemDamageEvent) event; + var damageItem = playerItemDamageEvent.getItem(); String damageKey = damageItem != null ? damageItem.getType().getKey().toString() : "minecraft:air"; @@ -578,17 +581,17 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { request.setEvent( patchbukkit.events.Event.newBuilder().setPlayerItemDamage( patchbukkit.events.PlayerItemDamageEvent.newBuilder() - .setPlayerUuid(BridgeUtils.convertUuid(damageEvent.getPlayer().getUniqueId())) + .setPlayerUuid(BridgeUtils.convertUuid(playerItemDamageEvent.getPlayer().getUniqueId())) .setItemKey(damageKey) .setItemAmount(damageAmount) - .setDamage(damageEvent.getDamage()) + .setDamage(playerItemDamageEvent.getDamage()) .build() ).build() ); break; case "org.bukkit.event.player.PlayerItemBreakEvent": - var breakEvent = (org.bukkit.event.player.PlayerItemBreakEvent) event; - var brokenItem = breakEvent.getBrokenItem(); + var playerItemBreakEvent = (org.bukkit.event.player.PlayerItemBreakEvent) event; + var brokenItem = playerItemBreakEvent.getBrokenItem(); String breakKey = brokenItem != null ? brokenItem.getType().getKey().toString() : "minecraft:air"; @@ -596,7 +599,7 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { request.setEvent( patchbukkit.events.Event.newBuilder().setPlayerItemBreak( patchbukkit.events.PlayerItemBreakEvent.newBuilder() - .setPlayerUuid(BridgeUtils.convertUuid(breakEvent.getPlayer().getUniqueId())) + .setPlayerUuid(BridgeUtils.convertUuid(playerItemBreakEvent.getPlayer().getUniqueId())) .setItemKey(breakKey) .setItemAmount(breakAmount) .build() @@ -665,16 +668,16 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { break; case "org.bukkit.event.player.PlayerKickEvent": var kickEvent = (org.bukkit.event.player.PlayerKickEvent) event; - String reason = GsonComponentSerializer.gson().serialize(kickEvent.reason()); + String kickReason = GsonComponentSerializer.gson().serialize(kickEvent.reason()); String leaveMessage = GsonComponentSerializer.gson().serialize(kickEvent.leaveMessage()); - String cause = kickEvent.getCause() != null ? kickEvent.getCause().name() : "UNKNOWN"; + String kickCause = kickEvent.getCause() != null ? kickEvent.getCause().name() : "UNKNOWN"; request.setEvent( patchbukkit.events.Event.newBuilder().setPlayerKick( patchbukkit.events.PlayerKickEvent.newBuilder() .setPlayerUuid(BridgeUtils.convertUuid(kickEvent.getPlayer().getUniqueId())) - .setReason(reason) + .setReason(kickReason) .setLeaveMessage(leaveMessage) - .setCause(cause) + .setCause(kickCause) .build() ).build() ); @@ -714,10 +717,10 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { break; case "org.bukkit.event.player.PlayerSwapHandItemsEvent": var swapEvent = (org.bukkit.event.player.PlayerSwapHandItemsEvent) event; - var mainHand = swapEvent.getMainHandItem(); + var swapMainHandItem = swapEvent.getMainHandItem(); var offHand = swapEvent.getOffHandItem(); - String mainKey = mainHand != null ? mainHand.getType().getKey().toString() : "minecraft:air"; - int mainAmount = mainHand != null ? mainHand.getAmount() : 0; + String mainKey = swapMainHandItem != null ? swapMainHandItem.getType().getKey().toString() : "minecraft:air"; + int mainAmount = swapMainHandItem != null ? swapMainHandItem.getAmount() : 0; String offKey = offHand != null ? offHand.getType().getKey().toString() : "minecraft:air"; int offAmount = offHand != null ? offHand.getAmount() : 0; request.setEvent( @@ -750,7 +753,7 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { break; case "org.bukkit.event.player.PlayerRespawnEvent": var respawnEvent = (org.bukkit.event.player.PlayerRespawnEvent) event; - String reason = respawnEvent.getRespawnReason() != null + String respawnReason = respawnEvent.getRespawnReason() != null ? respawnEvent.getRespawnReason().name() : "DEATH"; request.setEvent( @@ -761,27 +764,27 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { .setIsBedSpawn(respawnEvent.isBedSpawn()) .setIsAnchorSpawn(respawnEvent.isAnchorSpawn()) .setIsMissingRespawnBlock(respawnEvent.isMissingRespawnBlock()) - .setRespawnReason(reason) + .setRespawnReason(respawnReason) .build() ).build() ); break; case "org.bukkit.event.player.PlayerPickupArrowEvent": var pickupEvent = (org.bukkit.event.player.PlayerPickupArrowEvent) event; - var item = pickupEvent.getItem(); - String itemKey = "minecraft:air"; + var pickupItem = pickupEvent.getItem(); + String pickupItemKey = "minecraft:air"; int itemAmount = 0; - if (item != null && item.getItemStack() != null) { - itemKey = item.getItemStack().getType().getKey().toString(); - itemAmount = item.getItemStack().getAmount(); + if (pickupItem != null && pickupItem.getItemStack() != null) { + pickupItemKey = pickupItem.getItemStack().getType().getKey().toString(); + itemAmount = pickupItem.getItemStack().getAmount(); } request.setEvent( patchbukkit.events.Event.newBuilder().setPlayerPickupArrow( patchbukkit.events.PlayerPickupArrowEvent.newBuilder() .setPlayerUuid(BridgeUtils.convertUuid(pickupEvent.getPlayer().getUniqueId())) .setArrowUuid(BridgeUtils.convertUuid(pickupEvent.getArrow().getUniqueId())) - .setItemUuid(BridgeUtils.convertUuid(item != null ? item.getUniqueId() : java.util.UUID.randomUUID())) - .setItemKey(itemKey) + .setItemUuid(BridgeUtils.convertUuid(pickupItem != null ? pickupItem.getUniqueId() : java.util.UUID.randomUUID())) + .setItemKey(pickupItemKey) .setItemAmount(itemAmount) .setRemaining(pickupEvent.getRemaining()) .build() @@ -1000,10 +1003,10 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { case "org.bukkit.event.player.PlayerInteractEvent": var interactEvent = (org.bukkit.event.player.PlayerInteractEvent) event; var clicked = interactEvent.getClickedBlock(); - String itemKey = interactEvent.getItem() != null + String interactItemKey = interactEvent.getItem() != null ? interactEvent.getItem().getType().getKey().toString() : "minecraft:air"; - String face = interactEvent.getBlockFace() != null + String interactFace = interactEvent.getBlockFace() != null ? interactEvent.getBlockFace().name() : ""; request.setEvent( @@ -1013,39 +1016,40 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { .setAction(interactEvent.getAction().name()) .setBlockKey(clicked != null ? clicked.getType().getKey().toString() : "minecraft:air") .setClicked(BridgeUtils.convertLocation(clicked != null ? clicked.getLocation() : null)) - .setItemKey(itemKey) - .setBlockFace(face) + .setItemKey(interactItemKey) + .setBlockFace(interactFace) .build() ).build() ); break; case "org.bukkit.event.block.BlockBreakEvent": - var breakEvent = (org.bukkit.event.block.BlockBreakEvent) event; + var blockBreakEvent = (org.bukkit.event.block.BlockBreakEvent) event; request.setEvent( patchbukkit.events.Event.newBuilder().setBlockBreak( BlockBreakEvent.newBuilder() - .setPlayerUuid(BridgeUtils.convertUuid(breakEvent.getPlayer().getUniqueId())) - .setBlockKey(breakEvent.getBlock().getType().getKey().toString()) - .setLocation(BridgeUtils.convertLocation(breakEvent.getBlock().getLocation())) - .setExp(breakEvent.getExpToDrop()) - .setDrop(breakEvent.isDropItems()) + .setPlayerUuid(BridgeUtils.convertUuid(blockBreakEvent.getPlayer().getUniqueId())) + .setBlockKey(blockBreakEvent.getBlock().getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(blockBreakEvent.getBlock().getLocation())) + .setExp(blockBreakEvent.getExpToDrop()) + .setDrop(blockBreakEvent.isDropItems()) .build() ).build() ); break; case "org.bukkit.event.block.BlockDamageEvent": - var damageEvent = (org.bukkit.event.block.BlockDamageEvent) event; - String damageItemKey = damageEvent.getItemInHand() != null - ? damageEvent.getItemInHand().getType().getKey().toString() + var blockDamageEvent = (org.bukkit.event.block.BlockDamageEvent) event; + String damageItemKey = blockDamageEvent.getItemInHand() != null + ? blockDamageEvent.getItemInHand().getType().getKey().toString() : "minecraft:air"; + boolean instaBreak = resolveInstaBreak(blockDamageEvent); request.setEvent( patchbukkit.events.Event.newBuilder().setBlockDamage( BlockDamageEvent.newBuilder() - .setPlayerUuid(BridgeUtils.convertUuid(damageEvent.getPlayer().getUniqueId())) - .setBlockKey(damageEvent.getBlock().getType().getKey().toString()) - .setLocation(BridgeUtils.convertLocation(damageEvent.getBlock().getLocation())) + .setPlayerUuid(BridgeUtils.convertUuid(blockDamageEvent.getPlayer().getUniqueId())) + .setBlockKey(blockDamageEvent.getBlock().getType().getKey().toString()) + .setLocation(BridgeUtils.convertLocation(blockDamageEvent.getBlock().getLocation())) .setItemKey(damageItemKey) - .setInstaBreak(damageEvent.isInstaBreak()) + .setInstaBreak(instaBreak) .build() ).build() ); @@ -1074,7 +1078,7 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { int dispenseAmount = dispenseEvent.getItem() != null ? dispenseEvent.getItem().getAmount() : 0; - var velocity = dispenseEvent.getVelocity(); + var dispenseVelocity = dispenseEvent.getVelocity(); request.setEvent( patchbukkit.events.Event.newBuilder().setBlockDispense( BlockDispenseEvent.newBuilder() @@ -1083,9 +1087,9 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { .setItemKey(dispenseItemKey) .setItemAmount(dispenseAmount) .setVelocity(patchbukkit.common.Vec3.newBuilder() - .setX(velocity.getX()) - .setY(velocity.getY()) - .setZ(velocity.getZ()) + .setX(dispenseVelocity.getX()) + .setY(dispenseVelocity.getY()) + .setZ(dispenseVelocity.getZ()) .build()) .build() ).build() @@ -1098,12 +1102,12 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { .setPlayerUuid(BridgeUtils.convertUuid(dropItemEvent.getPlayer().getUniqueId())) .setBlockKey(dropBlock.getType().getKey().toString()) .setLocation(BridgeUtils.convertLocation(dropBlock.getLocation())); - for (org.bukkit.entity.Item item : dropItemEvent.getItems()) { - if (item.getItemStack() == null) continue; + for (org.bukkit.entity.Item dropItem : dropItemEvent.getItems()) { + if (dropItem.getItemStack() == null) continue; dropBuilder.addItems( BlockDropItemEntry.newBuilder() - .setItemKey(item.getItemStack().getType().getKey().toString()) - .setItemAmount(item.getItemStack().getAmount()) + .setItemKey(dropItem.getItemStack().getType().getKey().toString()) + .setItemAmount(dropItem.getItemStack().getAmount()) .build() ); } @@ -1179,7 +1183,7 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { var fromToEvent = (org.bukkit.event.block.BlockFromToEvent) event; Block fromBlock = fromToEvent.getBlock(); Block toBlock = fromToEvent.getToBlock(); - String face = fromToEvent.getFace() != null ? fromToEvent.getFace().name() : ""; + String fromToFace = fromToEvent.getFace() != null ? fromToEvent.getFace().name() : ""; request.setEvent( patchbukkit.events.Event.newBuilder().setBlockFromTo( BlockFromToEvent.newBuilder() @@ -1187,7 +1191,7 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { .setLocation(BridgeUtils.convertLocation(fromBlock.getLocation())) .setToBlockKey(toBlock.getType().getKey().toString()) .setToLocation(BridgeUtils.convertLocation(toBlock.getLocation())) - .setFace(face) + .setFace(fromToFace) .build() ).build() ); @@ -1213,7 +1217,7 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { .setBlockKey(extendBlock.getType().getKey().toString()) .setLocation(BridgeUtils.convertLocation(extendBlock.getLocation())) .setDirection(extendDir) - .setLength(extendEvent.getLength()); + .setLength(resolvePistonLength(extendEvent)); for (Block b : extendEvent.getBlocks()) { extendBuilder.addBlocks( BlockPistonBlockEntry.newBuilder() @@ -1234,7 +1238,7 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { .setBlockKey(retractBlock.getType().getKey().toString()) .setLocation(BridgeUtils.convertLocation(retractBlock.getLocation())) .setDirection(retractDir) - .setLength(retractEvent.getLength()); + .setLength(resolvePistonLength(retractEvent)); for (Block b : retractEvent.getBlocks()) { retractBuilder.addBlocks( BlockPistonBlockEntry.newBuilder() @@ -1268,7 +1272,7 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { .setPlayerUuid(BridgeUtils.convertUuid(multiEvent.getPlayer().getUniqueId())) .setBlockKey(multiBlock.getType().getKey().toString()) .setLocation(BridgeUtils.convertLocation(multiBlock.getLocation())); - for (org.bukkit.block.BlockState state : multiEvent.getBlockStates()) { + for (org.bukkit.block.BlockState state : resolveMultiPlaceStates(multiEvent)) { multiBuilder.addBlocks( BlockMultiPlaceBlockEntry.newBuilder() .setBlockKey(state.getType().getKey().toString()) @@ -1283,12 +1287,13 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { case "org.bukkit.event.block.BlockPhysicsEvent": var physicsEvent = (org.bukkit.event.block.BlockPhysicsEvent) event; Block physicsBlock = physicsEvent.getBlock(); + Material physicsSourceMaterial = resolvePhysicsChangedMaterial(physicsEvent); request.setEvent( patchbukkit.events.Event.newBuilder().setBlockPhysics( BlockPhysicsEvent.newBuilder() .setBlockKey(physicsBlock.getType().getKey().toString()) .setLocation(BridgeUtils.convertLocation(physicsBlock.getLocation())) - .setSourceBlockKey(physicsEvent.getChangedType().getMaterial().getKey().toString()) + .setSourceBlockKey(physicsSourceMaterial.getKey().toString()) .setSourceLocation(BridgeUtils.convertLocation(physicsBlock.getLocation())) .build() ).build() @@ -1334,7 +1339,7 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { case "org.bukkit.event.block.TNTPrimeEvent": var tntEvent = (org.bukkit.event.block.TNTPrimeEvent) event; Block tntBlock = tntEvent.getBlock(); - var tntBuilder = TntPrimeEvent.newBuilder() + var tntBuilder = TNTPrimeEvent.newBuilder() .setBlockKey(tntBlock.getType().getKey().toString()) .setLocation(BridgeUtils.convertLocation(tntBlock.getLocation())) .setCause(tntEvent.getCause().name()); @@ -1379,28 +1384,29 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { case "org.bukkit.event.block.FluidLevelChangeEvent": var fluidEvent = (org.bukkit.event.block.FluidLevelChangeEvent) event; Block fluidBlock = fluidEvent.getBlock(); + String newBlockKey = resolveFluidNewBlockKey(fluidEvent); request.setEvent( patchbukkit.events.Event.newBuilder().setFluidLevelChange( FluidLevelChangeEvent.newBuilder() .setBlockKey(fluidBlock.getType().getKey().toString()) .setLocation(BridgeUtils.convertLocation(fluidBlock.getLocation())) - .setNewBlockKey(fluidEvent.getNewState().getType().getKey().toString()) + .setNewBlockKey(newBlockKey) .build() ).build() ); break; case "org.bukkit.event.world.SpawnChangeEvent": - var spawnEvent = (org.bukkit.event.world.SpawnChangeEvent) event; - Location location = spawnEvent.getLocation(); - Location previous = spawnEvent.getPreviousLocation(); + var worldSpawnChangeEvent = (org.bukkit.event.world.SpawnChangeEvent) event; + Location spawnLocation = resolveSpawnChangeLocation(worldSpawnChangeEvent); + Location previous = resolveSpawnChangePreviousLocation(worldSpawnChangeEvent, spawnLocation); if (previous == null) { - previous = location; + previous = spawnLocation; } request.setEvent( patchbukkit.events.Event.newBuilder().setSpawnChange( SpawnChangeEvent.newBuilder() .setPreviousLocation(BridgeUtils.convertLocation(previous)) - .setLocation(BridgeUtils.convertLocation(location)) + .setLocation(BridgeUtils.convertLocation(spawnLocation)) .build() ).build() ); @@ -1415,7 +1421,7 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { onlinePlayers = count; } } catch (ReflectiveOperationException ignored) { - onlinePlayers = pingEvent.getServer().getOnlinePlayers().size(); + onlinePlayers = Bukkit.getOnlinePlayers().size(); } String favicon = ""; try { @@ -1524,24 +1530,24 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { ); break; case "org.bukkit.event.entity.EntitySpawnEvent": - var spawnEvent = (org.bukkit.event.entity.EntitySpawnEvent) event; + var entitySpawnEvent = (org.bukkit.event.entity.EntitySpawnEvent) event; request.setEvent( patchbukkit.events.Event.newBuilder().setEntitySpawn( EntitySpawnEvent.newBuilder() - .setEntityUuid(BridgeUtils.convertUuid(spawnEvent.getEntity().getUniqueId())) - .setEntityType(spawnEvent.getEntity().getType().name()) + .setEntityUuid(BridgeUtils.convertUuid(entitySpawnEvent.getEntity().getUniqueId())) + .setEntityType(entitySpawnEvent.getEntity().getType().name()) .build() ).build() ); break; case "org.bukkit.event.entity.EntityDamageEvent": - var damageEvent = (org.bukkit.event.entity.EntityDamageEvent) event; + var entityDamageEvent = (org.bukkit.event.entity.EntityDamageEvent) event; request.setEvent( patchbukkit.events.Event.newBuilder().setEntityDamage( EntityDamageEvent.newBuilder() - .setEntityUuid(BridgeUtils.convertUuid(damageEvent.getEntity().getUniqueId())) - .setDamage((float) damageEvent.getFinalDamage()) - .setDamageType(damageEvent.getCause().name()) + .setEntityUuid(BridgeUtils.convertUuid(entityDamageEvent.getEntity().getUniqueId())) + .setDamage((float) entityDamageEvent.getFinalDamage()) + .setDamageType(entityDamageEvent.getCause().name()) .build() ).build() ); @@ -1841,4 +1847,186 @@ public Map, Set> createRegisteredList public void clearEvents() { HandlerList.unregisterAll(); } + + private static boolean resolveInstaBreak(@NotNull org.bukkit.event.block.BlockDamageEvent event) { + try { + Method method = event.getClass().getMethod("isInstaBreak"); + Object value = method.invoke(event); + if (value instanceof Boolean b) { + return b; + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + return false; + } + + private static int resolvePistonLength(@NotNull Object pistonEvent) { + try { + Method method = pistonEvent.getClass().getMethod("getLength"); + Object value = method.invoke(pistonEvent); + if (value instanceof Integer len) { + return len; + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + Method method = pistonEvent.getClass().getMethod("getBlocks"); + Object value = method.invoke(pistonEvent); + if (value instanceof java.util.List list) { + return list.size(); + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + return 0; + } + + @NotNull + private static java.util.List resolveMultiPlaceStates( + @NotNull org.bukkit.event.block.BlockMultiPlaceEvent event + ) { + try { + Method method = event.getClass().getMethod("getBlockStates"); + Object value = method.invoke(event); + if (value instanceof java.util.List list) { + java.util.List states = new java.util.ArrayList<>(); + for (Object entry : list) { + if (entry instanceof org.bukkit.block.BlockState state) { + states.add(state); + } + } + return states; + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + Method method = event.getClass().getMethod("getReplacedBlockStates"); + Object value = method.invoke(event); + if (value instanceof java.util.List list) { + java.util.List states = new java.util.ArrayList<>(); + for (Object entry : list) { + if (entry instanceof org.bukkit.block.BlockState state) { + states.add(state); + } + } + return states; + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + return java.util.Collections.emptyList(); + } + + @NotNull + private static Material resolvePhysicsChangedMaterial(@NotNull org.bukkit.event.block.BlockPhysicsEvent event) { + try { + Object changed = event.getChangedType(); + if (changed instanceof Material material) { + return material; + } + if (changed != null) { + Method method = changed.getClass().getMethod("getMaterial"); + Object value = method.invoke(changed); + if (value instanceof Material material) { + return material; + } + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + return event.getBlock().getType(); + } + + @NotNull + private static String resolveFluidNewBlockKey(@NotNull org.bukkit.event.block.FluidLevelChangeEvent event) { + try { + Method method = event.getClass().getMethod("getNewState"); + Object value = method.invoke(event); + if (value instanceof org.bukkit.block.BlockState state) { + return state.getType().getKey().toString(); + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + Method method = event.getClass().getMethod("getNewData"); + Object value = method.invoke(event); + if (value instanceof org.bukkit.block.data.BlockData data) { + return data.getMaterial().getKey().toString(); + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + Method method = event.getClass().getMethod("getNewBlockData"); + Object value = method.invoke(event); + if (value instanceof org.bukkit.block.data.BlockData data) { + return data.getMaterial().getKey().toString(); + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + return event.getBlock().getType().getKey().toString(); + } + + @Nullable + private static Location resolveSpawnChangeLocation(@NotNull org.bukkit.event.world.SpawnChangeEvent event) { + try { + Method method = event.getClass().getMethod("getLocation"); + Object value = method.invoke(event); + if (value instanceof Location location) { + return location; + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + Method method = event.getClass().getMethod("getNewLocation"); + Object value = method.invoke(event); + if (value instanceof Location location) { + return location; + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + Method method = event.getClass().getMethod("getNewSpawn"); + Object value = method.invoke(event); + if (value instanceof Location location) { + return location; + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + return event.getWorld() != null ? event.getWorld().getSpawnLocation() : null; + } + + @Nullable + private static Location resolveSpawnChangePreviousLocation( + @NotNull org.bukkit.event.world.SpawnChangeEvent event, + @Nullable Location fallback + ) { + try { + Method method = event.getClass().getMethod("getPreviousLocation"); + Object value = method.invoke(event); + if (value instanceof Location location) { + return location; + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + try { + Method method = event.getClass().getMethod("getPreviousSpawn"); + Object value = method.invoke(event); + if (value instanceof Location location) { + return location; + } + } catch (ReflectiveOperationException ignored) { + // ignore + } + return fallback; + } } diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/world/PatchBukkitBlock.java b/java/patchbukkit/src/main/java/org/patchbukkit/world/PatchBukkitBlock.java index aff60fe..3ff7096 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/world/PatchBukkitBlock.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/world/PatchBukkitBlock.java @@ -84,12 +84,11 @@ public Object invoke(Object proxy, Method method, Object[] args) { case "isEmpty": return material.isAir(); case "isLiquid": - return material.isLiquid(); + return material == Material.WATER || material == Material.LAVA; case "getRelative": return getRelative(args); case "getChunk": throw new UnsupportedOperationException("Unimplemented method 'getChunk'"); - throw new UnsupportedOperationException("Unimplemented method '" + name + "'"); case "equals": return proxy == args[0]; case "hashCode": diff --git a/proto/google/protobuf/empty.proto b/proto/google/protobuf/empty.proto new file mode 100644 index 0000000..a1406e1 --- /dev/null +++ b/proto/google/protobuf/empty.proto @@ -0,0 +1,5 @@ +syntax = "proto3"; + +package google.protobuf; + +message Empty {} diff --git a/proto/google/protobuf/wrappers.proto b/proto/google/protobuf/wrappers.proto new file mode 100644 index 0000000..da1755a --- /dev/null +++ b/proto/google/protobuf/wrappers.proto @@ -0,0 +1,13 @@ +syntax = "proto3"; + +package google.protobuf; + +message DoubleValue { double value = 1; } +message FloatValue { float value = 1; } +message Int64Value { int64 value = 1; } +message UInt64Value { uint64 value = 1; } +message Int32Value { int32 value = 1; } +message UInt32Value { uint32 value = 1; } +message BoolValue { bool value = 1; } +message StringValue { string value = 1; } +message BytesValue { bytes value = 1; } From 0b95ca16ea0645297f39d88d1a57572942026a13 Mon Sep 17 00:00:00 2001 From: yunuservices Date: Thu, 5 Feb 2026 21:57:31 +0300 Subject: [PATCH 49/56] Align PatchBukkit runtime with current event support --- .../org/patchbukkit/PatchBukkitServer.java | 5 +- proto/google/protobuf/empty.proto | 4 + proto/google/protobuf/wrappers.proto | 4 + rust/Cargo.lock | 1 + rust/Cargo.toml | 1 + rust/src/events/handler.rs | 4246 ++-------------- rust/src/events/handler_legacy.rs | 4459 +++++++++++++++++ rust/src/java/native_callbacks/events.rs | 3401 +------------ .../java/native_callbacks/events_legacy.rs | 3458 +++++++++++++ 9 files changed, 8515 insertions(+), 7064 deletions(-) create mode 100644 rust/src/events/handler_legacy.rs create mode 100644 rust/src/java/native_callbacks/events_legacy.rs diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/PatchBukkitServer.java b/java/patchbukkit/src/main/java/org/patchbukkit/PatchBukkitServer.java index a982154..dea19e6 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/PatchBukkitServer.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/PatchBukkitServer.java @@ -1238,10 +1238,7 @@ public void setMotd(@NotNull String motd) { @Override public @NotNull WarningState getWarningState() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException( - "Unimplemented method 'getWarningState'" - ); + return WarningState.DEFAULT; } @Override diff --git a/proto/google/protobuf/empty.proto b/proto/google/protobuf/empty.proto index a1406e1..47eb5aa 100644 --- a/proto/google/protobuf/empty.proto +++ b/proto/google/protobuf/empty.proto @@ -2,4 +2,8 @@ package google.protobuf; +option java_package = "com.google.protobuf"; +option java_outer_classname = "EmptyProto"; +option java_multiple_files = true; + message Empty {} diff --git a/proto/google/protobuf/wrappers.proto b/proto/google/protobuf/wrappers.proto index da1755a..feb2e09 100644 --- a/proto/google/protobuf/wrappers.proto +++ b/proto/google/protobuf/wrappers.proto @@ -2,6 +2,10 @@ package google.protobuf; +option java_package = "com.google.protobuf"; +option java_outer_classname = "WrappersProto"; +option java_multiple_files = true; + message DoubleValue { double value = 1; } message FloatValue { float value = 1; } message Int64Value { int64 value = 1; } diff --git a/rust/Cargo.lock b/rust/Cargo.lock index af1e654..b538281 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -1921,6 +1921,7 @@ dependencies = [ "pumpkin-data", "pumpkin-protocol", "pumpkin-util", + "pumpkin-world", "rand", "rust-embed", "serde", diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 65178bf..c82d7e4 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -13,6 +13,7 @@ pumpkin = { git = "https://github.com/Pumpkin-MC/Pumpkin.git", branch = "master" pumpkin-data = { git = "https://github.com/Pumpkin-MC/Pumpkin.git", branch = "master", package = "pumpkin-data" } pumpkin-protocol = { git = "https://github.com/Pumpkin-MC/Pumpkin.git", branch = "master", package = "pumpkin-protocol" } pumpkin-util = { git = "https://github.com/Pumpkin-MC/Pumpkin.git", branch = "master", package = "pumpkin-util" } +pumpkin-world = { git = "https://github.com/Pumpkin-MC/Pumpkin.git", branch = "master", package = "pumpkin-world" } pumpkin-api-macros = { git = "https://github.com/Pumpkin-MC/Pumpkin.git", branch = "master", package = "pumpkin-api-macros" } tokio = "1" diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index 01babef..1ae08d8 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -1,44 +1,24 @@ -use std::marker::PhantomData; +use std::marker::PhantomData; use std::str::FromStr; use std::sync::Arc; use pumpkin::entity::player::Player; use pumpkin::plugin::{BoxFuture, Cancellable, EventHandler, Payload}; use pumpkin::server::Server; +use pumpkin::world::World as PumpkinWorld; use pumpkin_api_macros::with_runtime; -use pumpkin_data::data_component_impl::EquipmentSlot; -use pumpkin_data::{Block, BlockDirection}; -use pumpkin_data::block_properties::Instrument; -use pumpkin_data::item::Item; -use pumpkin_util::Hand; +use pumpkin_data::Block; use pumpkin_util::math::vector3::Vector3; use pumpkin_util::text::TextComponent; -use pumpkin_world::item::ItemStack; use tokio::sync::{mpsc, oneshot}; use crate::java::jvm::commands::JvmCommand; -use crate::proto::patchbukkit::common::{Location, Uuid, Vec3, World}; +use crate::proto::patchbukkit::common::{Location, Uuid, Vec3, World as ProtoWorld}; use crate::proto::patchbukkit::events::event::Data; use crate::proto::patchbukkit::events::{ - BlockBreakEvent, BlockDamageEvent, BlockDamageAbortEvent, BlockDispenseEvent, BlockDropItemEntry, BlockDropItemEvent, BlockExplodeBlockEntry, BlockExplodeEvent, BlockFadeEvent, BlockFertilizeBlockEntry, BlockFertilizeEvent, BlockFormEvent, BlockFromToEvent, BlockGrowEvent, BlockPistonBlockEntry, BlockPistonExtendEvent, BlockPistonRetractEvent, BlockRedstoneEvent, BlockMultiPlaceBlockEntry, BlockMultiPlaceEvent, BlockPhysicsEvent, BlockPlaceEvent, BlockCanBuildEvent, BlockBurnEvent, BlockIgniteEvent, BlockSpreadEvent, NotePlayEvent, SignChangeEvent, TntPrimeEvent, MoistureChangeEvent, SpongeAbsorbEvent, SpongeAbsorbBlockEntry, FluidLevelChangeEvent, SpawnChangeEvent, ServerListPingEvent, PluginEnableEvent, PluginDisableEvent, ServiceRegisterEvent, ServiceUnregisterEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, - PlayerLeaveEvent, PlayerMoveEvent, PlayerInteractEvent, ServerBroadcastEvent, ServerCommandEvent, - EntityDamageEvent, EntityDeathEvent, EntitySpawnEvent, - PlayerLoginEvent, PlayerTeleportEvent, PlayerChangeWorldEvent, PlayerGamemodeChangeEvent, - AsyncPlayerPreLoginEvent, PlayerAdvancementDoneEvent, PlayerAnimationEvent, - PlayerArmorStandManipulateEvent, - PlayerBedEnterEvent, PlayerBedLeaveEvent, - PlayerBucketEmptyEvent, PlayerBucketFillEvent, PlayerBucketEntityEvent, - PlayerChangedMainHandEvent, - PlayerRegisterChannelEvent, PlayerUnregisterChannelEvent, PlayerDropItemEvent, - PlayerEditBookEvent, PlayerEggThrowEvent, PlayerExpChangeEvent, PlayerFishEvent, - PlayerInteractEntityEvent, PlayerInteractAtEntityEvent, PlayerItemHeldEvent, - PlayerItemDamageEvent, PlayerItemBreakEvent, PlayerItemConsumeEvent, PlayerItemMendEvent, - PlayerLevelChangeEvent, PlayerKickEvent, - PlayerToggleSneakEvent, PlayerToggleSprintEvent, PlayerToggleFlightEvent, - PlayerSwapHandItemsEvent, PlayerResourcePackStatusEvent, PlayerRespawnEvent, - PlayerPickupArrowEvent, PlayerPortalEvent, PlayerRecipeDiscoverEvent, PlayerRiptideEvent, - PlayerShearEntityEvent, PlayerSpawnLocationEvent, PlayerStatisticIncrementEvent, - PlayerVelocityEvent, PlayerHarvestBlockEvent, + BlockBreakEvent, BlockBurnEvent, BlockCanBuildEvent, BlockPlaceEvent, Event, PlayerChangeWorldEvent, + PlayerChatEvent, PlayerCommandSendEvent, PlayerGamemodeChangeEvent, PlayerInteractEvent, PlayerJoinEvent, + PlayerLeaveEvent, PlayerLoginEvent, PlayerMoveEvent, PlayerTeleportEvent, ServerBroadcastEvent, ServerCommandEvent, }; pub struct EventContext { @@ -56,7 +36,7 @@ pub trait PatchBukkitEvent { fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()>; } -impl PatchBukkitEvent for pumpkin::plugin::player::player_join::PlayerJoinEvent { +impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_join::PlayerJoinEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { JvmEventPayload { event: Event { @@ -87,7 +67,7 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_join::PlayerJoinEvent } } -impl PatchBukkitEvent for pumpkin::plugin::player::player_login::PlayerLoginEvent { +impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_login::PlayerLoginEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { JvmEventPayload { event: Event { @@ -118,50 +98,7 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_login::PlayerLoginEven } } -impl PatchBukkitEvent for pumpkin::plugin::player::player_pre_login::PlayerPreLoginEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::AsyncPlayerPreLogin(AsyncPlayerPreLoginEvent { - name: self.name.clone(), - player_uuid: Some(Uuid { - value: self.player_uuid.to_string(), - }), - address: self.address.clone(), - result: self.result.clone(), - kick_message: self.kick_message.clone(), - })), - }, - context: EventContext { - server, - player: None, - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::AsyncPlayerPreLogin(event) => { - self.result = event.result; - self.kick_message = event.kick_message; - if let Some(uuid) = event.player_uuid { - self.player_uuid = uuid::Uuid::from_str(&uuid.value).ok()?; - } - if !event.name.is_empty() { - self.name = event.name; - } - if !event.address.is_empty() { - self.address = event.address; - } - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_leave::PlayerLeaveEvent { +impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_leave::PlayerLeaveEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { JvmEventPayload { event: Event { @@ -192,15 +129,17 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_leave::PlayerLeaveEven } } -impl PatchBukkitEvent for pumpkin::plugin::player::player_advancement_done::PlayerAdvancementDoneEvent { +impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_move::PlayerMoveEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { + let world_uuid = self.player.world().uuid; JvmEventPayload { event: Event { - data: Some(Data::PlayerAdvancementDone(PlayerAdvancementDoneEvent { + data: Some(Data::PlayerMove(PlayerMoveEvent { player_uuid: Some(Uuid { value: self.player.gameprofile.id.to_string(), }), - advancement_key: self.advancement_key.clone(), + from: Some(build_location(world_uuid, &self.from, 0.0, 0.0)), + to: Some(build_location(world_uuid, &self.to, 0.0, 0.0)), })), }, context: EventContext { @@ -210,20 +149,35 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_advancement_done::Play } } - fn apply_modifications(&mut self, _server: &Arc, _data: Data) -> Option<()> { + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerMove(event) => { + if let Some(from) = event.from.and_then(location_to_vec3) { + self.from = from; + } + if let Some(to) = event.to.and_then(location_to_vec3) { + self.to = to; + } + } + _ => {} + } + Some(()) } } -impl PatchBukkitEvent for pumpkin::plugin::player::player_animation::PlayerAnimationEvent { +impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_teleport::PlayerTeleportEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { + let world_uuid = self.player.world().uuid; JvmEventPayload { event: Event { - data: Some(Data::PlayerAnimation(PlayerAnimationEvent { + data: Some(Data::PlayerTeleport(PlayerTeleportEvent { player_uuid: Some(Uuid { value: self.player.gameprofile.id.to_string(), }), - animation_type: self.animation_type.clone(), + from: Some(build_location(world_uuid, &self.from, 0.0, 0.0)), + to: Some(build_location(world_uuid, &self.to, 0.0, 0.0)), + cause: String::new(), })), }, context: EventContext { @@ -233,28 +187,45 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_animation::PlayerAnima } } - fn apply_modifications(&mut self, _server: &Arc, _data: Data) -> Option<()> { + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerTeleport(event) => { + if let Some(from) = event.from.and_then(location_to_vec3) { + self.from = from; + } + if let Some(to) = event.to.and_then(location_to_vec3) { + self.to = to; + } + } + _ => {} + } + Some(()) } } -impl PatchBukkitEvent for pumpkin::plugin::player::player_armor_stand_manipulate::PlayerArmorStandManipulateEvent { +impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_change_world::PlayerChangeWorldEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { JvmEventPayload { event: Event { - data: Some(Data::PlayerArmorStandManipulate( - PlayerArmorStandManipulateEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), + data: Some(Data::PlayerChangeWorld(PlayerChangeWorldEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + previous_world: Some(ProtoWorld { + uuid: Some(Uuid { + value: self.previous_world.uuid.to_string(), }), - armor_stand_uuid: Some(Uuid { - value: self.armor_stand_uuid.to_string(), + }), + new_world: Some(ProtoWorld { + uuid: Some(Uuid { + value: self.new_world.uuid.to_string(), }), - item_key: self.item_key.clone(), - armor_stand_item_key: self.armor_stand_item_key.clone(), - slot: self.slot.clone(), - }, - )), + }), + position: Some(build_location(self.new_world.uuid, &self.position, self.yaw, self.pitch)), + yaw: self.yaw, + pitch: self.pitch, + })), }, context: EventContext { server, @@ -263,20 +234,25 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_armor_stand_manipulate } } - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { match data { - Data::PlayerArmorStandManipulate(event) => { - if !event.item_key.is_empty() { - self.item_key = event.item_key; + Data::PlayerChangeWorld(event) => { + if let Some(world) = event.previous_world.and_then(|w| w.uuid) { + self.previous_world = + find_world_by_uuid(server, uuid::Uuid::from_str(&world.value).ok()?)?; + } + if let Some(world) = event.new_world.and_then(|w| w.uuid) { + self.new_world = + find_world_by_uuid(server, uuid::Uuid::from_str(&world.value).ok()?)?; } - if !event.armor_stand_item_key.is_empty() { - self.armor_stand_item_key = event.armor_stand_item_key; + if let Some(position) = event.position.and_then(location_to_vec3) { + self.position = position; } - if !event.slot.is_empty() { - self.slot = event.slot; + if event.yaw != 0.0 { + self.yaw = event.yaw; } - if let Some(uuid) = event.armor_stand_uuid { - self.armor_stand_uuid = uuid::Uuid::from_str(&uuid.value).ok()?; + if event.pitch != 0.0 { + self.pitch = event.pitch; } } _ => {} @@ -286,17 +262,16 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_armor_stand_manipulate } } -impl PatchBukkitEvent for pumpkin::plugin::player::player_bed_enter::PlayerBedEnterEvent { +impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_gamemode_change::PlayerGamemodeChangeEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { - let world_uuid = self.player.world().uuid; - JvmEventPayload { event: Event { - data: Some(Data::PlayerBedEnter(PlayerBedEnterEvent { + data: Some(Data::PlayerGamemodeChange(PlayerGamemodeChangeEvent { player_uuid: Some(Uuid { value: self.player.gameprofile.id.to_string(), }), - bed_location: Some(build_location(world_uuid, &self.bed_position, 0.0, 0.0)), + previous_gamemode: gamemode_to_bukkit(self.previous_gamemode), + new_gamemode: gamemode_to_bukkit(self.new_gamemode), })), }, context: EventContext { @@ -308,31 +283,37 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_bed_enter::PlayerBedEn fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { match data { - Data::PlayerBedEnter(event) => { - if let Some(location) = event.bed_location { - if let Some(pos) = location_to_vec3(location) { - self.bed_position = pos; - } + Data::PlayerGamemodeChange(event) => { + if let Some(mode) = gamemode_from_bukkit(&event.previous_gamemode) { + self.previous_gamemode = mode; + } + if let Some(mode) = gamemode_from_bukkit(&event.new_gamemode) { + self.new_gamemode = mode; } } _ => {} } - Some(()) } } -impl PatchBukkitEvent for pumpkin::plugin::player::player_bed_leave::PlayerBedLeaveEvent { +impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_chat::PlayerChatEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { - let world_uuid = self.player.world().uuid; - + let recipients = self + .recipients + .iter() + .map(|player| Uuid { + value: player.gameprofile.id.to_string(), + }) + .collect(); JvmEventPayload { event: Event { - data: Some(Data::PlayerBedLeave(PlayerBedLeaveEvent { + data: Some(Data::PlayerChat(PlayerChatEvent { player_uuid: Some(Uuid { value: self.player.gameprofile.id.to_string(), }), - bed_location: Some(build_location(world_uuid, &self.bed_position, 0.0, 0.0)), + message: self.message.clone(), + recipients, })), }, context: EventContext { @@ -342,36 +323,38 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_bed_leave::PlayerBedLe } } - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { match data { - Data::PlayerBedLeave(event) => { - if let Some(location) = event.bed_location { - if let Some(pos) = location_to_vec3(location) { - self.bed_position = pos; + Data::PlayerChat(event) => { + if !event.message.is_empty() { + self.message = event.message; + } + if !event.recipients.is_empty() { + let mut recipients = Vec::new(); + for uuid in event.recipients { + let player_uuid = uuid::Uuid::from_str(&uuid.value).ok()?; + if let Some(player) = server.get_player_by_uuid(player_uuid) { + recipients.push(player); + } } + self.recipients = recipients; } } _ => {} } - Some(()) } } -impl PatchBukkitEvent for pumpkin::plugin::player::player_bucket_empty::PlayerBucketEmptyEvent { +impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_command_send::PlayerCommandSendEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { - let world_uuid = self.player.world().uuid; JvmEventPayload { event: Event { - data: Some(Data::PlayerBucketEmpty(PlayerBucketEmptyEvent { + data: Some(Data::PlayerCommandSend(PlayerCommandSendEvent { player_uuid: Some(Uuid { value: self.player.gameprofile.id.to_string(), }), - location: Some(build_location(world_uuid, &self.position, 0.0, 0.0)), - block_key: self.block_key.clone(), - block_face: block_face_to_bukkit(self.face), - bucket_item_key: self.bucket_item_key.clone(), - hand: self.hand.clone(), + commands: vec![self.command.clone()], })), }, context: EventContext { @@ -383,22 +366,10 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_bucket_empty::PlayerBu fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { match data { - Data::PlayerBucketEmpty(event) => { - if let Some(location) = event.location { - if let Some(pos) = location_to_vec3(location) { - self.position = pos; - } - } - if !event.block_key.is_empty() { - self.block_key = event.block_key; - } - if !event.bucket_item_key.is_empty() { - self.bucket_item_key = event.bucket_item_key; - } - if !event.hand.is_empty() { - self.hand = event.hand; + Data::PlayerCommandSend(event) => { + if let Some(command) = event.commands.first() { + self.command = command.clone(); } - self.face = bukkit_block_face_from_string(&event.block_face); } _ => {} } @@ -406,20 +377,35 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_bucket_empty::PlayerBu } } -impl PatchBukkitEvent for pumpkin::plugin::player::player_bucket_fill::PlayerBucketFillEvent { +impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_interact_event::PlayerInteractEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { let world_uuid = self.player.world().uuid; + let clicked = self.clicked_pos.as_ref().map(|pos| { + build_location( + world_uuid, + &Vector3::new(f64::from(pos.0.x), f64::from(pos.0.y), f64::from(pos.0.z)), + 0.0, + 0.0, + ) + }); + let item_key = self + .item + .try_lock() + .ok() + .map(|item| item_to_key(item.get_item())) + .unwrap_or_default(); + JvmEventPayload { event: Event { - data: Some(Data::PlayerBucketFill(PlayerBucketFillEvent { + data: Some(Data::PlayerInteract(PlayerInteractEvent { player_uuid: Some(Uuid { value: self.player.gameprofile.id.to_string(), }), - location: Some(build_location(world_uuid, &self.position, 0.0, 0.0)), - block_key: self.block_key.clone(), - block_face: block_face_to_bukkit(self.face), - bucket_item_key: self.bucket_item_key.clone(), - hand: self.hand.clone(), + action: interact_action_to_bukkit(&self.action), + block_key: block_to_key(self.block), + clicked, + item_key, + block_face: String::new(), })), }, context: EventContext { @@ -431,22 +417,22 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_bucket_fill::PlayerBuc fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { match data { - Data::PlayerBucketFill(event) => { - if let Some(location) = event.location { - if let Some(pos) = location_to_vec3(location) { - self.position = pos; - } - } - if !event.block_key.is_empty() { - self.block_key = event.block_key; + Data::PlayerInteract(event) => { + if let Some(action) = interact_action_from_bukkit(&event.action) { + self.action = action; } - if !event.bucket_item_key.is_empty() { - self.bucket_item_key = event.bucket_item_key; + if let Some(loc) = event.clicked.and_then(location_to_vec3) { + self.clicked_pos = Some(pumpkin_util::math::position::BlockPos::new( + loc.x.floor() as i32, + loc.y.floor() as i32, + loc.z.floor() as i32, + )); } - if !event.hand.is_empty() { - self.hand = event.hand; + if !event.block_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_key) { + self.block = block; + } } - self.face = bukkit_block_face_from_string(&event.block_face); } _ => {} } @@ -454,48 +440,54 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_bucket_fill::PlayerBuc } } -impl PatchBukkitEvent for pumpkin::plugin::player::player_bucket_entity::PlayerBucketEntityEvent { +impl PatchBukkitEvent for pumpkin::plugin::api::events::block::block_break::BlockBreakEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { + let world_uuid = self + .player + .as_ref() + .map(|p| p.world().uuid) + .or_else(|| server.worlds.load().first().map(|w| w.uuid)) + .unwrap_or_else(uuid::Uuid::new_v4); + let location = build_location( + world_uuid, + &Vector3::new( + f64::from(self.block_position.0.x), + f64::from(self.block_position.0.y), + f64::from(self.block_position.0.z), + ), + 0.0, + 0.0, + ); + JvmEventPayload { event: Event { - data: Some(Data::PlayerBucketEntity(PlayerBucketEntityEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - entity_uuid: Some(Uuid { - value: self.entity_uuid.to_string(), + data: Some(Data::BlockBreak(BlockBreakEvent { + player_uuid: self.player.as_ref().map(|p| Uuid { + value: p.gameprofile.id.to_string(), }), - entity_type: self.entity_type.clone(), - original_bucket_key: self.original_bucket_key.clone(), - entity_bucket_key: self.entity_bucket_key.clone(), - hand: self.hand.clone(), + block_key: block_to_key(self.block), + location: Some(location), + exp: self.exp, + drop: self.drop, })), }, context: EventContext { server, - player: Some(self.player.clone()), + player: self.player.clone(), }, } } fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { match data { - Data::PlayerBucketEntity(event) => { - if let Some(uuid) = event.entity_uuid { - self.entity_uuid = uuid::Uuid::from_str(&uuid.value).ok()?; - } - if !event.entity_type.is_empty() { - self.entity_type = event.entity_type; - } - if !event.original_bucket_key.is_empty() { - self.original_bucket_key = event.original_bucket_key; - } - if !event.entity_bucket_key.is_empty() { - self.entity_bucket_key = event.entity_bucket_key; - } - if !event.hand.is_empty() { - self.hand = event.hand; + Data::BlockBreak(event) => { + if !event.block_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_key) { + self.block = block; + } } + self.exp = event.exp; + self.drop = event.drop; } _ => {} } @@ -503,29 +495,32 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_bucket_entity::PlayerB } } -impl PatchBukkitEvent for pumpkin::plugin::player::player_changed_main_hand::PlayerChangedMainHandEvent { +impl PatchBukkitEvent for pumpkin::plugin::api::events::block::block_burn::BlockBurnEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { JvmEventPayload { event: Event { - data: Some(Data::PlayerChangedMainHand(PlayerChangedMainHandEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - main_hand: bukkit_main_hand(self.main_hand), + data: Some(Data::BlockBurn(BlockBurnEvent { + block_key: block_to_key(self.block), + igniting_block_key: block_to_key(self.igniting_block), + location: None, })), }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, + context: EventContext { server, player: None }, } } - fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { match data { - Data::PlayerChangedMainHand(event) => { - if let Ok(uuid) = uuid::Uuid::from_str(&event.player_uuid?.value) { - server.get_player_by_uuid(uuid)?; + Data::BlockBurn(event) => { + if !event.block_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_key) { + self.block = block; + } + } + if !event.igniting_block_key.is_empty() { + if let Some(block) = Block::from_name(&event.igniting_block_key) { + self.igniting_block = block; + } } } _ => {} @@ -534,15 +529,26 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_changed_main_hand::Pla } } -impl PatchBukkitEvent for pumpkin::plugin::player::player_register_channel::PlayerRegisterChannelEvent { +impl PatchBukkitEvent for pumpkin::plugin::api::events::block::block_can_build::BlockCanBuildEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { + let world_uuid = self.player.world().uuid; + let position = self.player.position(); + let location = build_location( + world_uuid, + &Vector3::new(position.x, position.y, position.z), + 0.0, + 0.0, + ); JvmEventPayload { event: Event { - data: Some(Data::PlayerRegisterChannel(PlayerRegisterChannelEvent { + data: Some(Data::BlockCanBuild(BlockCanBuildEvent { player_uuid: Some(Uuid { value: self.player.gameprofile.id.to_string(), }), - channel: self.channel.clone(), + block_key: block_to_key(self.block_to_build), + block_against_key: block_to_key(self.block), + location: Some(location), + can_build: self.buildable, })), }, context: EventContext { @@ -552,15 +558,20 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_register_channel::Play } } - fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { match data { - Data::PlayerRegisterChannel(event) => { - if let Ok(uuid) = uuid::Uuid::from_str(&event.player_uuid?.value) { - server.get_player_by_uuid(uuid)?; + Data::BlockCanBuild(event) => { + if !event.block_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_key) { + self.block_to_build = block; + } } - if !event.channel.is_empty() { - self.channel = event.channel; + if !event.block_against_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_against_key) { + self.block = block; + } } + self.buildable = event.can_build; } _ => {} } @@ -568,15 +579,26 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_register_channel::Play } } -impl PatchBukkitEvent for pumpkin::plugin::player::player_unregister_channel::PlayerUnregisterChannelEvent { +impl PatchBukkitEvent for pumpkin::plugin::api::events::block::block_place::BlockPlaceEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { + let world_uuid = self.player.world().uuid; + let position = self.player.position(); + let location = build_location( + world_uuid, + &Vector3::new(position.x, position.y, position.z), + 0.0, + 0.0, + ); JvmEventPayload { event: Event { - data: Some(Data::PlayerUnregisterChannel(PlayerUnregisterChannelEvent { + data: Some(Data::BlockPlace(BlockPlaceEvent { player_uuid: Some(Uuid { value: self.player.gameprofile.id.to_string(), }), - channel: self.channel.clone(), + block_key: block_to_key(self.block_placed), + block_against_key: block_to_key(self.block_placed_against), + location: Some(location), + can_build: self.can_build, })), }, context: EventContext { @@ -586,15 +608,20 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_unregister_channel::Pl } } - fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { match data { - Data::PlayerUnregisterChannel(event) => { - if let Ok(uuid) = uuid::Uuid::from_str(&event.player_uuid?.value) { - server.get_player_by_uuid(uuid)?; + Data::BlockPlace(event) => { + if !event.block_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_key) { + self.block_placed = block; + } } - if !event.channel.is_empty() { - self.channel = event.channel; + if !event.block_against_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_against_key) { + self.block_placed_against = block; + } } + self.can_build = event.can_build; } _ => {} } @@ -602,3587 +629,30 @@ impl PatchBukkitEvent for pumpkin::plugin::player::player_unregister_channel::Pl } } -impl PatchBukkitEvent for pumpkin::plugin::player::player_move::PlayerMoveEvent { +impl PatchBukkitEvent for pumpkin::plugin::api::events::server::server_command::ServerCommandEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { - let world_uuid = self.player.world().uuid; - let yaw = self.player.living_entity.entity.yaw.load(); - let pitch = self.player.living_entity.entity.pitch.load(); - JvmEventPayload { event: Event { - data: Some(Data::PlayerMove(PlayerMoveEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - from: Some(build_location(world_uuid, &self.from, yaw, pitch)), - to: Some(build_location(world_uuid, &self.to, yaw, pitch)), + data: Some(Data::ServerCommand(ServerCommandEvent { + command: self.command.clone(), })), }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, + context: EventContext { server, player: None }, } } - fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { match data { - Data::PlayerMove(event) => { - server.get_player_by_uuid(uuid::Uuid::from_str(&event.player_uuid?.value).ok()?)?; - if let Some(from) = event.from { - if let Some(from_vec) = location_to_vec3(from) { - self.from = from_vec; - } - } - if let Some(to) = event.to { - if let Some(to_vec) = location_to_vec3(to) { - self.to = to_vec; - } - } + Data::ServerCommand(event) => { + self.command = event.command; } _ => {} } - Some(()) } } -impl PatchBukkitEvent for pumpkin::plugin::player::player_teleport::PlayerTeleportEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let world_uuid = self.player.world().uuid; - let yaw = self.player.living_entity.entity.yaw.load(); - let pitch = self.player.living_entity.entity.pitch.load(); - - JvmEventPayload { - event: Event { - data: Some(Data::PlayerTeleport(PlayerTeleportEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - from: Some(build_location(world_uuid, &self.from, yaw, pitch)), - to: Some(build_location(world_uuid, &self.to, yaw, pitch)), - cause: String::new(), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerTeleport(event) => { - server.get_player_by_uuid(uuid::Uuid::from_str(&event.player_uuid?.value).ok()?)?; - if let Some(from) = event.from { - if let Some(from_vec) = location_to_vec3(from) { - self.from = from_vec; - } - } - if let Some(to) = event.to { - if let Some(to_vec) = location_to_vec3(to) { - self.to = to_vec; - } - } - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_change_world::PlayerChangeWorldEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let location = build_location(self.new_world.uuid, &self.position, self.yaw, self.pitch); - - JvmEventPayload { - event: Event { - data: Some(Data::PlayerChangeWorld(PlayerChangeWorldEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - previous_world: Some(World { - uuid: Some(Uuid { - value: self.previous_world.uuid.to_string(), - }), - }), - new_world: Some(World { - uuid: Some(Uuid { - value: self.new_world.uuid.to_string(), - }), - }), - position: Some(location), - yaw: self.yaw, - pitch: self.pitch, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerChangeWorld(event) => { - if let Some(position) = event.position.and_then(location_to_vec3) { - self.position = position; - } - self.yaw = event.yaw; - self.pitch = event.pitch; - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_gamemode_change::PlayerGamemodeChangeEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerGamemodeChange(PlayerGamemodeChangeEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - previous_gamemode: gamemode_to_bukkit(self.previous_gamemode), - new_gamemode: gamemode_to_bukkit(self.new_gamemode), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerGamemodeChange(event) => { - if let Some(prev) = gamemode_from_bukkit(&event.previous_gamemode) { - self.previous_gamemode = prev; - } - if let Some(next) = gamemode_from_bukkit(&event.new_gamemode) { - self.new_gamemode = next; - } - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_chat::PlayerChatEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let recipients = self - .recipients - .iter() - .map(|player| Uuid { - value: player.gameprofile.id.to_string(), - }) - .collect(); - - JvmEventPayload { - event: Event { - data: Some(Data::PlayerChat(PlayerChatEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - message: self.message.clone(), - recipients, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerChat(event) => { - self.message = event.message; - if !event.recipients.is_empty() { - let mut recipients = Vec::new(); - for recipient in event.recipients { - let uuid = uuid::Uuid::from_str(&recipient.value).ok()?; - if let Some(player) = server.get_player_by_uuid(uuid) { - recipients.push(player); - } - } - self.recipients = recipients; - } - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_command_preprocess::PlayerCommandPreprocessEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerCommand(PlayerCommandEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - command: self.command.clone(), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerCommand(event) => { - if !event.command.is_empty() { - self.command = event.command; - } - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_command_send::PlayerCommandSendEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerCommandSend(crate::proto::patchbukkit::events::PlayerCommandSendEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - commands: self.commands.clone(), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerCommandSend(event) => { - self.commands = event.commands; - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_drop_item::PlayerDropItemEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerDropItem(PlayerDropItemEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - item_uuid: Some(Uuid { - value: self.item_uuid.to_string(), - }), - item_key: item_to_key(self.item_stack.item), - item_amount: i32::from(self.item_stack.item_count), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerDropItem(event) => { - if let Some(uuid) = event.item_uuid { - if let Ok(item_uuid) = uuid::Uuid::from_str(&uuid.value) { - self.item_uuid = item_uuid; - } - } - let mut key = if event.item_key.is_empty() { - None - } else { - Some(event.item_key) - }; - let mut amount = if event.item_amount > 0 { - Some(event.item_amount as u8) - } else { - None - }; - - if key.is_some() || amount.is_some() { - let fallback_key = item_to_key(self.item_stack.item); - let key = key.take().unwrap_or(fallback_key); - let count = amount.take().unwrap_or(self.item_stack.item_count); - self.item_stack = item_stack_from_key(&key, count); - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_edit_book::PlayerEditBookEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerEditBook(PlayerEditBookEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - slot: self.slot, - pages: self.pages.clone(), - title: self.title.clone().unwrap_or_default(), - is_signing: self.is_signing, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerEditBook(event) => { - self.slot = event.slot; - self.pages = event.pages; - self.is_signing = event.is_signing; - self.title = if event.title.is_empty() { - None - } else { - Some(event.title) - }; - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_egg_throw::PlayerEggThrowEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerEggThrow(PlayerEggThrowEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - egg_uuid: Some(Uuid { - value: self.egg_uuid.to_string(), - }), - hatching: self.hatching, - num_hatches: i32::from(self.num_hatches), - hatching_type: self.hatching_type.clone(), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerEggThrow(event) => { - if let Some(uuid) = event.egg_uuid { - if let Ok(egg_uuid) = uuid::Uuid::from_str(&uuid.value) { - self.egg_uuid = egg_uuid; - } - } - self.hatching = event.hatching; - if event.num_hatches >= 0 { - self.num_hatches = event.num_hatches.min(u8::MAX as i32) as u8; - } - if !event.hatching_type.is_empty() { - self.hatching_type = event.hatching_type; - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_exp_change::PlayerExpChangeEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerExpChange(PlayerExpChangeEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - amount: self.amount, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerExpChange(event) => { - self.amount = event.amount; - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_fish::PlayerFishEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerFish(PlayerFishEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - caught_uuid: self.caught_uuid.map(|uuid| Uuid { - value: uuid.to_string(), - }), - caught_type: self.caught_type.clone(), - hook_uuid: Some(Uuid { - value: self.hook_uuid.to_string(), - }), - state: self.state.clone(), - hand: self.hand.clone(), - exp_to_drop: self.exp_to_drop, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerFish(event) => { - self.caught_uuid = event - .caught_uuid - .and_then(|uuid| uuid::Uuid::from_str(&uuid.value).ok()); - if !event.caught_type.is_empty() { - self.caught_type = event.caught_type; - } - if let Some(uuid) = event.hook_uuid { - if let Ok(hook_uuid) = uuid::Uuid::from_str(&uuid.value) { - self.hook_uuid = hook_uuid; - } - } - if !event.state.is_empty() { - self.state = event.state; - } - if !event.hand.is_empty() { - self.hand = event.hand; - } - self.exp_to_drop = event.exp_to_drop; - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_interact_entity::PlayerInteractEntityEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerInteractEntity(PlayerInteractEntityEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - entity_uuid: Some(Uuid { - value: self.entity_uuid.to_string(), - }), - entity_type: self.entity_type.clone(), - hand: self.hand.clone(), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerInteractEntity(event) => { - if let Some(uuid) = event.entity_uuid { - if let Ok(entity_uuid) = uuid::Uuid::from_str(&uuid.value) { - self.entity_uuid = entity_uuid; - } - } - if !event.entity_type.is_empty() { - self.entity_type = event.entity_type; - } - if !event.hand.is_empty() { - self.hand = event.hand; - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_interact_at_entity::PlayerInteractAtEntityEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerInteractAtEntity(PlayerInteractAtEntityEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - entity_uuid: Some(Uuid { - value: self.entity_uuid.to_string(), - }), - entity_type: self.entity_type.clone(), - hand: self.hand.clone(), - clicked_position: Some(Vec3 { - x: f64::from(self.clicked_position.x), - y: f64::from(self.clicked_position.y), - z: f64::from(self.clicked_position.z), - }), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerInteractAtEntity(event) => { - if let Some(uuid) = event.entity_uuid { - if let Ok(entity_uuid) = uuid::Uuid::from_str(&uuid.value) { - self.entity_uuid = entity_uuid; - } - } - if !event.entity_type.is_empty() { - self.entity_type = event.entity_type; - } - if !event.hand.is_empty() { - self.hand = event.hand; - } - if let Some(pos) = event.clicked_position { - self.clicked_position = Vector3::new(pos.x as f32, pos.y as f32, pos.z as f32); - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_item_held::PlayerItemHeldEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerItemHeld(PlayerItemHeldEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - previous_slot: self.previous_slot, - new_slot: self.new_slot, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerItemHeld(event) => { - self.previous_slot = event.previous_slot; - self.new_slot = event.new_slot; - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_item_damage::PlayerItemDamageEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerItemDamage(PlayerItemDamageEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - item_key: item_to_key(self.item_stack.item), - item_amount: i32::from(self.item_stack.item_count), - damage: self.damage, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerItemDamage(event) => { - self.damage = event.damage; - let mut key = if event.item_key.is_empty() { - None - } else { - Some(event.item_key) - }; - let mut amount = if event.item_amount > 0 { - Some(event.item_amount as u8) - } else { - None - }; - - if key.is_some() || amount.is_some() { - let fallback_key = item_to_key(self.item_stack.item); - let key = key.take().unwrap_or(fallback_key); - let count = amount.take().unwrap_or(self.item_stack.item_count); - self.item_stack = item_stack_from_key(&key, count); - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_item_break::PlayerItemBreakEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerItemBreak(PlayerItemBreakEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - item_key: item_to_key(self.item_stack.item), - item_amount: i32::from(self.item_stack.item_count), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerItemBreak(event) => { - let mut key = if event.item_key.is_empty() { - None - } else { - Some(event.item_key) - }; - let mut amount = if event.item_amount > 0 { - Some(event.item_amount as u8) - } else { - None - }; - - if key.is_some() || amount.is_some() { - let fallback_key = item_to_key(self.item_stack.item); - let key = key.take().unwrap_or(fallback_key); - let count = amount.take().unwrap_or(self.item_stack.item_count); - self.item_stack = item_stack_from_key(&key, count); - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_item_consume::PlayerItemConsumeEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let hand = match self.hand { - Hand::Left => "OFF_HAND", - Hand::Right => "HAND", - }; - JvmEventPayload { - event: Event { - data: Some(Data::PlayerItemConsume(PlayerItemConsumeEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - item_key: item_to_key(self.item_stack.item), - item_amount: i32::from(self.item_stack.item_count), - hand: hand.to_string(), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerItemConsume(event) => { - if !event.hand.is_empty() { - self.hand = if event.hand == "OFF_HAND" { - Hand::Left - } else { - Hand::Right - }; - } - - let mut key = if event.item_key.is_empty() { - None - } else { - Some(event.item_key) - }; - let mut amount = if event.item_amount > 0 { - Some(event.item_amount as u8) - } else { - None - }; - - if key.is_some() || amount.is_some() { - let fallback_key = item_to_key(self.item_stack.item); - let key = key.take().unwrap_or(fallback_key); - let count = amount.take().unwrap_or(self.item_stack.item_count); - self.item_stack = item_stack_from_key(&key, count); - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_item_mend::PlayerItemMendEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerItemMend(PlayerItemMendEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - item_key: item_to_key(self.item_stack.item), - item_amount: i32::from(self.item_stack.item_count), - slot: equipment_slot_to_bukkit(&self.slot), - repair_amount: self.repair_amount, - orb_uuid: self.orb_uuid.map(|id| Uuid { value: id.to_string() }), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerItemMend(event) => { - self.repair_amount = event.repair_amount; - if !event.slot.is_empty() { - if let Some(slot) = equipment_slot_from_bukkit(&event.slot) { - self.slot = slot; - } - } - if let Some(uuid) = event.orb_uuid { - if let Ok(orb_uuid) = uuid::Uuid::from_str(&uuid.value) { - self.orb_uuid = Some(orb_uuid); - } - } - let mut key = if event.item_key.is_empty() { - None - } else { - Some(event.item_key) - }; - let mut amount = if event.item_amount > 0 { - Some(event.item_amount as u8) - } else { - None - }; - - if key.is_some() || amount.is_some() { - let fallback_key = item_to_key(self.item_stack.item); - let key = key.take().unwrap_or(fallback_key); - let count = amount.take().unwrap_or(self.item_stack.item_count); - self.item_stack = item_stack_from_key(&key, count); - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_level_change::PlayerLevelChangeEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerLevelChange(PlayerLevelChangeEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - old_level: self.old_level, - new_level: self.new_level, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerLevelChange(event) => { - self.old_level = event.old_level; - self.new_level = event.new_level; - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_kick::PlayerKickEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerKick(PlayerKickEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - reason: serde_json::to_string(&self.reason).unwrap_or_default(), - leave_message: serde_json::to_string(&self.leave_message).unwrap_or_default(), - cause: self.cause.clone(), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerKick(event) => { - if !event.reason.is_empty() { - if let Ok(reason) = serde_json::from_str(&event.reason) { - self.reason = reason; - } - } - if !event.leave_message.is_empty() { - if let Ok(msg) = serde_json::from_str(&event.leave_message) { - self.leave_message = msg; - } - } - if !event.cause.is_empty() { - self.cause = event.cause; - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_toggle_sneak::PlayerToggleSneakEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerToggleSneak(PlayerToggleSneakEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - is_sneaking: self.is_sneaking, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerToggleSneak(event) => { - self.is_sneaking = event.is_sneaking; - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_toggle_sprint::PlayerToggleSprintEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerToggleSprint(PlayerToggleSprintEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - is_sprinting: self.is_sprinting, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerToggleSprint(event) => { - self.is_sprinting = event.is_sprinting; - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_toggle_flight::PlayerToggleFlightEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerToggleFlight(PlayerToggleFlightEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - is_flying: self.is_flying, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerToggleFlight(event) => { - self.is_flying = event.is_flying; - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_swap_hand_items::PlayerSwapHandItemsEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerSwapHandItems(PlayerSwapHandItemsEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - main_hand_item_key: item_to_key(self.main_hand_item.item), - main_hand_item_amount: i32::from(self.main_hand_item.item_count), - off_hand_item_key: item_to_key(self.off_hand_item.item), - off_hand_item_amount: i32::from(self.off_hand_item.item_count), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerSwapHandItems(event) => { - if !event.main_hand_item_key.is_empty() || event.main_hand_item_amount > 0 { - let key = if event.main_hand_item_key.is_empty() { - item_to_key(self.main_hand_item.item) - } else { - event.main_hand_item_key - }; - let count = if event.main_hand_item_amount > 0 { - event.main_hand_item_amount as u8 - } else { - self.main_hand_item.item_count - }; - self.main_hand_item = item_stack_from_key(&key, count); - } - if !event.off_hand_item_key.is_empty() || event.off_hand_item_amount > 0 { - let key = if event.off_hand_item_key.is_empty() { - item_to_key(self.off_hand_item.item) - } else { - event.off_hand_item_key - }; - let count = if event.off_hand_item_amount > 0 { - event.off_hand_item_amount as u8 - } else { - self.off_hand_item.item_count - }; - self.off_hand_item = item_stack_from_key(&key, count); - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_resource_pack_status::PlayerResourcePackStatusEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerResourcePackStatus(PlayerResourcePackStatusEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - pack_uuid: Some(Uuid { - value: self.pack_uuid.to_string(), - }), - status: self.status.clone(), - hash: self.pack_hash.clone(), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerResourcePackStatus(event) => { - if let Some(uuid) = event.pack_uuid { - if let Ok(pack_uuid) = uuid::Uuid::from_str(&uuid.value) { - self.pack_uuid = pack_uuid; - } - } - if !event.status.is_empty() { - self.status = event.status; - } - if !event.hash.is_empty() { - self.pack_hash = event.hash; - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_respawn::PlayerRespawnEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let yaw = self.player.living_entity.entity.yaw.load(); - let pitch = self.player.living_entity.entity.pitch.load(); - JvmEventPayload { - event: Event { - data: Some(Data::PlayerRespawn(PlayerRespawnEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - respawn_location: Some(build_location( - self.world_uuid, - &Vector3::new( - self.respawn_position.x, - self.respawn_position.y, - self.respawn_position.z, - ), - yaw, - pitch, - )), - is_bed_spawn: self.is_bed_spawn, - is_anchor_spawn: self.is_anchor_spawn, - is_missing_respawn_block: self.is_missing_respawn_block, - respawn_reason: self.reason.clone(), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerRespawn(event) => { - if let Some(loc) = event.respawn_location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.respawn_position = pos; - } - if let Some(world) = loc.world.and_then(|w| w.uuid) { - if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { - self.world_uuid = uuid; - } - } - } - self.is_bed_spawn = event.is_bed_spawn; - self.is_anchor_spawn = event.is_anchor_spawn; - self.is_missing_respawn_block = event.is_missing_respawn_block; - if !event.respawn_reason.is_empty() { - self.reason = event.respawn_reason; - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_pickup_arrow::PlayerPickupArrowEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerPickupArrow(PlayerPickupArrowEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - arrow_uuid: Some(Uuid { - value: self.arrow_uuid.to_string(), - }), - item_uuid: Some(Uuid { - value: self.item_uuid.to_string(), - }), - item_key: item_to_key(self.item_stack.item), - item_amount: self.item_stack.item_count as i32, - remaining: self.remaining, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerPickupArrow(event) => { - if let Some(uuid) = event.arrow_uuid { - if let Ok(arrow_uuid) = uuid::Uuid::from_str(&uuid.value) { - self.arrow_uuid = arrow_uuid; - } - } - if let Some(uuid) = event.item_uuid { - if let Ok(item_uuid) = uuid::Uuid::from_str(&uuid.value) { - self.item_uuid = item_uuid; - } - } - if !event.item_key.is_empty() || event.item_amount > 0 { - let key = if event.item_key.is_empty() { - item_to_key(self.item_stack.item) - } else { - event.item_key - }; - let count = if event.item_amount > 0 { - event.item_amount as u8 - } else { - self.item_stack.item_count - }; - self.item_stack = item_stack_from_key(&key, count); - } - self.remaining = event.remaining; - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_portal::PlayerPortalEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let yaw = self.player.living_entity.entity.yaw.load(); - let pitch = self.player.living_entity.entity.pitch.load(); - JvmEventPayload { - event: Event { - data: Some(Data::PlayerPortal(PlayerPortalEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - from: Some(build_location( - self.from_world_uuid, - &self.from_position, - yaw, - pitch, - )), - to: Some(build_location( - self.to_world_uuid, - &self.to_position, - yaw, - pitch, - )), - cause: self.cause.clone(), - search_radius: self.search_radius, - can_create_portal: self.can_create_portal, - creation_radius: self.creation_radius, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerPortal(event) => { - if let Some(from) = event.from { - if let Some(pos) = location_to_vec3(from.clone()) { - self.from_position = pos; - } - if let Some(world) = from.world.and_then(|w| w.uuid) { - if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { - self.from_world_uuid = uuid; - } - } - } - if let Some(to) = event.to { - if let Some(pos) = location_to_vec3(to.clone()) { - self.to_position = pos; - } - if let Some(world) = to.world.and_then(|w| w.uuid) { - if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { - self.to_world_uuid = uuid; - } - } - } - if !event.cause.is_empty() { - self.cause = event.cause; - } - self.search_radius = event.search_radius; - self.can_create_portal = event.can_create_portal; - self.creation_radius = event.creation_radius; - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_recipe_discover::PlayerRecipeDiscoverEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerRecipeDiscover(PlayerRecipeDiscoverEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - recipe_key: self.recipe_key.clone(), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerRecipeDiscover(event) => { - if !event.recipe_key.is_empty() { - self.recipe_key = event.recipe_key; - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_riptide::PlayerRiptideEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerRiptide(PlayerRiptideEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - item_key: item_to_key(self.item_stack.item), - item_amount: self.item_stack.item_count as i32, - velocity: Some(Vec3 { - x: self.velocity.x, - y: self.velocity.y, - z: self.velocity.z, - }), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerRiptide(event) => { - if !event.item_key.is_empty() || event.item_amount > 0 { - let key = if event.item_key.is_empty() { - item_to_key(self.item_stack.item) - } else { - event.item_key - }; - let count = if event.item_amount > 0 { - event.item_amount as u8 - } else { - self.item_stack.item_count - }; - self.item_stack = item_stack_from_key(&key, count); - } - if let Some(velocity) = event.velocity { - self.velocity = Vector3::new(velocity.x, velocity.y, velocity.z); - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_shear_entity::PlayerShearEntityEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerShearEntity(PlayerShearEntityEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - entity_uuid: Some(Uuid { - value: self.entity_uuid.to_string(), - }), - entity_type: self.entity_type.clone(), - item_key: item_to_key(self.item_stack.item), - item_amount: self.item_stack.item_count as i32, - hand: self.hand.clone(), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerShearEntity(event) => { - if let Some(uuid) = event.entity_uuid { - if let Ok(entity_uuid) = uuid::Uuid::from_str(&uuid.value) { - self.entity_uuid = entity_uuid; - } - } - if !event.entity_type.is_empty() { - self.entity_type = event.entity_type; - } - if !event.item_key.is_empty() || event.item_amount > 0 { - let key = if event.item_key.is_empty() { - item_to_key(self.item_stack.item) - } else { - event.item_key - }; - let count = if event.item_amount > 0 { - event.item_amount as u8 - } else { - self.item_stack.item_count - }; - self.item_stack = item_stack_from_key(&key, count); - } - if !event.hand.is_empty() { - self.hand = event.hand; - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_spawn_location::PlayerSpawnLocationEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let yaw = self.player.living_entity.entity.yaw.load(); - let pitch = self.player.living_entity.entity.pitch.load(); - JvmEventPayload { - event: Event { - data: Some(Data::PlayerSpawnLocation(PlayerSpawnLocationEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - spawn_location: Some(build_location( - self.world_uuid, - &self.spawn_position, - yaw, - pitch, - )), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerSpawnLocation(event) => { - if let Some(loc) = event.spawn_location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.spawn_position = pos; - } - if let Some(world) = loc.world.and_then(|w| w.uuid) { - if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { - self.world_uuid = uuid; - } - } - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_statistic_increment::PlayerStatisticIncrementEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerStatisticIncrement(PlayerStatisticIncrementEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - statistic: self.statistic.clone(), - initial_value: self.initial_value, - new_value: self.new_value, - entity_type: self.entity_type.clone(), - material_key: self.material_key.clone(), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerStatisticIncrement(event) => { - if !event.statistic.is_empty() { - self.statistic = event.statistic; - } - self.initial_value = event.initial_value; - self.new_value = event.new_value; - if !event.entity_type.is_empty() { - self.entity_type = event.entity_type; - } - if !event.material_key.is_empty() { - self.material_key = event.material_key; - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_velocity::PlayerVelocityEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerVelocity(PlayerVelocityEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - velocity: Some(Vec3 { - x: self.velocity.x, - y: self.velocity.y, - z: self.velocity.z, - }), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerVelocity(event) => { - if let Some(velocity) = event.velocity { - self.velocity = Vector3::new(velocity.x, velocity.y, velocity.z); - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_harvest_block::PlayerHarvestBlockEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let yaw = self.player.living_entity.entity.yaw.load(); - let pitch = self.player.living_entity.entity.pitch.load(); - JvmEventPayload { - event: Event { - data: Some(Data::PlayerHarvestBlock(PlayerHarvestBlockEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - block_location: Some(build_location( - self.player.world().uuid, - &Vector3::new( - f64::from(self.block_pos.0.x), - f64::from(self.block_pos.0.y), - f64::from(self.block_pos.0.z), - ), - yaw, - pitch, - )), - block_key: self.block_key.clone(), - item_key: item_to_key(self.item_stack.item), - item_amount: self.item_stack.item_count as i32, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerHarvestBlock(event) => { - if let Some(loc) = event.block_location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.block_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - } - if let Some(world) = loc.world.and_then(|w| w.uuid) { - if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { - if uuid != self.player.world().uuid { - // World changes are not supported for harvest event. - } - } - } - } - if !event.block_key.is_empty() { - self.block_key = event.block_key; - } - if !event.item_key.is_empty() || event.item_amount > 0 { - let key = if event.item_key.is_empty() { - item_to_key(self.item_stack.item) - } else { - event.item_key - }; - let count = if event.item_amount > 0 { - event.item_amount as u8 - } else { - self.item_stack.item_count - }; - self.item_stack = item_stack_from_key(&key, count); - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_interact_event::PlayerInteractEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let world_uuid = self.player.world().uuid; - let yaw = self.player.living_entity.entity.yaw.load(); - let pitch = self.player.living_entity.entity.pitch.load(); - - let clicked = self.clicked_pos.map(|pos| { - build_location( - world_uuid, - &Vector3::new( - f64::from(pos.0.x), - f64::from(pos.0.y), - f64::from(pos.0.z), - ), - yaw, - pitch, - ) - }); - - JvmEventPayload { - event: Event { - data: Some(Data::PlayerInteract(PlayerInteractEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - action: interact_action_to_bukkit(&self.action), - block_key: block_to_key(self.block), - clicked, - item_key: self.item_key.clone(), - block_face: block_face_to_bukkit(self.face), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, _data: Data) -> Option<()> { - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_break::BlockBreakEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let (player_uuid, world_uuid) = if let Some(player) = &self.player { - (player.gameprofile.id.to_string(), Some(player.world().uuid)) - } else { - ("00000000-0000-0000-0000-000000000000".to_string(), None) - }; - - let location = world_uuid.map(|world_uuid| { - build_location( - world_uuid, - &Vector3::new( - f64::from(self.block_position.0.x), - f64::from(self.block_position.0.y), - f64::from(self.block_position.0.z), - ), - 0.0, - 0.0, - ) - }); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockBreak(BlockBreakEvent { - player_uuid: Some(Uuid { value: player_uuid }), - block_key: block_to_key(self.block), - location, - exp: self.exp, - drop: self.drop, - })), - }, - context: EventContext { - server, - player: self.player.clone(), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockBreak(event) => { - self.exp = event.exp; - self.drop = event.drop; - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_damage::BlockDamageEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let player_uuid = self.player.gameprofile.id.to_string(); - let world_uuid = self.player.world().uuid; - let location = build_location( - world_uuid, - &Vector3::new( - f64::from(self.block_position.0.x), - f64::from(self.block_position.0.y), - f64::from(self.block_position.0.z), - ), - 0.0, - 0.0, - ); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockDamage(BlockDamageEvent { - player_uuid: Some(Uuid { value: player_uuid }), - block_key: block_to_key(self.block), - location: Some(location), - item_key: item_to_key(self.item_stack.item), - insta_break: self.insta_break, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockDamage(event) => { - self.insta_break = event.insta_break; - if !event.item_key.is_empty() { - let count = self.item_stack.item_count; - self.item_stack = item_stack_from_key(&event.item_key, count); - } - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_damage_abort::BlockDamageAbortEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let player_uuid = self.player.gameprofile.id.to_string(); - let world_uuid = self.player.world().uuid; - let location = build_location( - world_uuid, - &Vector3::new( - f64::from(self.block_position.0.x), - f64::from(self.block_position.0.y), - f64::from(self.block_position.0.z), - ), - 0.0, - 0.0, - ); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockDamageAbort(BlockDamageAbortEvent { - player_uuid: Some(Uuid { value: player_uuid }), - block_key: block_to_key(self.block), - location: Some(location), - item_key: item_to_key(self.item_stack.item), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockDamageAbort(event) => { - if !event.item_key.is_empty() { - let count = self.item_stack.item_count; - self.item_stack = item_stack_from_key(&event.item_key, count); - } - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_dispense::BlockDispenseEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let world_uuid = server - .worlds - .load() - .first() - .map(|world| world.uuid) - .unwrap_or_default(); - let location = build_location( - world_uuid, - &Vector3::new( - f64::from(self.block_position.0.x), - f64::from(self.block_position.0.y), - f64::from(self.block_position.0.z), - ), - 0.0, - 0.0, - ); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockDispense(BlockDispenseEvent { - block_key: block_to_key(self.block), - location: Some(location), - item_key: item_to_key(self.item_stack.item), - item_amount: i32::from(self.item_stack.item_count), - velocity: Some(Vec3 { - x: self.velocity.x, - y: self.velocity.y, - z: self.velocity.z, - }), - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockDispense(event) => { - if !event.item_key.is_empty() || event.item_amount > 0 { - let key = if event.item_key.is_empty() { - item_to_key(self.item_stack.item) - } else { - event.item_key - }; - let count = if event.item_amount > 0 { - event.item_amount as u8 - } else { - self.item_stack.item_count - }; - self.item_stack = item_stack_from_key(&key, count); - } - if let Some(vel) = event.velocity { - self.velocity = Vector3::new(vel.x, vel.y, vel.z); - } - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_drop_item::BlockDropItemEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let world_uuid = self.player.world().uuid; - let location = build_location( - world_uuid, - &Vector3::new( - f64::from(self.block_position.0.x), - f64::from(self.block_position.0.y), - f64::from(self.block_position.0.z), - ), - 0.0, - 0.0, - ); - let items = self - .items - .iter() - .map(|item| BlockDropItemEntry { - item_key: item_to_key(item.item), - item_amount: i32::from(item.item_count), - }) - .collect(); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockDropItem(BlockDropItemEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - block_key: block_to_key(self.block), - location: Some(location), - items, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockDropItem(event) => { - if !event.items.is_empty() { - let mut items = Vec::with_capacity(event.items.len()); - for entry in event.items { - if entry.item_key.is_empty() && entry.item_amount <= 0 { - continue; - } - let key = if entry.item_key.is_empty() { - "minecraft:air" - } else { - entry.item_key.as_str() - }; - let stack = item_stack_from_key(key, entry.item_amount.clamp(0, u8::MAX as i32) as u8); - if !stack.is_empty() { - items.push(stack); - } - } - self.items = items; - } - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_explode::BlockExplodeEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let location = build_location( - self.world_uuid, - &Vector3::new( - f64::from(self.block_position.0.x), - f64::from(self.block_position.0.y), - f64::from(self.block_position.0.z), - ), - 0.0, - 0.0, - ); - let blocks = self - .blocks - .iter() - .map(|pos| { - let loc = build_location( - self.world_uuid, - &Vector3::new(f64::from(pos.0.x), f64::from(pos.0.y), f64::from(pos.0.z)), - 0.0, - 0.0, - ); - BlockExplodeBlockEntry { - block_key: String::new(), - location: Some(loc), - } - }) - .collect(); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockExplode(BlockExplodeEvent { - block_key: block_to_key(self.block), - location: Some(location), - yield_: self.yield_rate, - blocks, - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockExplode(event) => { - self.yield_rate = event.yield_; - if !event.blocks.is_empty() { - let mut blocks = Vec::with_capacity(event.blocks.len()); - for entry in event.blocks { - if let Some(loc) = entry.location - && let Some(pos) = location_to_vec3(loc.clone()) - { - blocks.push(pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - )); - } - } - self.blocks = blocks; - } - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_fade::BlockFadeEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let location = build_location( - self.world_uuid, - &Vector3::new( - f64::from(self.block_pos.0.x), - f64::from(self.block_pos.0.y), - f64::from(self.block_pos.0.z), - ), - 0.0, - 0.0, - ); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockFade(BlockFadeEvent { - block_key: block_to_key(self.block), - new_block_key: block_to_key(self.new_block), - location: Some(location), - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockFade(event) => { - if !event.new_block_key.is_empty() { - if let Some(block) = Block::from_name(&event.new_block_key) { - self.new_block = block; - } - } - if let Some(loc) = event.location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.block_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - } - } - if !event.block_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_key) { - self.block = block; - } - } - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_fertilize::BlockFertilizeEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let world_uuid = self.player.world().uuid; - let location = build_location( - world_uuid, - &Vector3::new( - f64::from(self.block_pos.0.x), - f64::from(self.block_pos.0.y), - f64::from(self.block_pos.0.z), - ), - 0.0, - 0.0, - ); - let blocks = self - .blocks - .iter() - .map(|pos| { - let loc = build_location( - world_uuid, - &Vector3::new(f64::from(pos.0.x), f64::from(pos.0.y), f64::from(pos.0.z)), - 0.0, - 0.0, - ); - BlockFertilizeBlockEntry { - block_key: block_to_key(self.block), - location: Some(loc), - } - }) - .collect(); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockFertilize(BlockFertilizeEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - block_key: block_to_key(self.block), - location: Some(location), - blocks, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockFertilize(event) => { - if !event.blocks.is_empty() { - let mut blocks = Vec::with_capacity(event.blocks.len()); - for entry in event.blocks { - if let Some(loc) = entry.location - && let Some(pos) = location_to_vec3(loc.clone()) - { - blocks.push(pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - )); - } - } - self.blocks = blocks; - } - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_form::BlockFormEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let location = build_location( - self.world_uuid, - &Vector3::new( - f64::from(self.block_pos.0.x), - f64::from(self.block_pos.0.y), - f64::from(self.block_pos.0.z), - ), - 0.0, - 0.0, - ); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockForm(BlockFormEvent { - block_key: block_to_key(self.old_block), - new_block_key: block_to_key(self.new_block), - location: Some(location), - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockForm(event) => { - if !event.new_block_key.is_empty() { - if let Some(block) = Block::from_name(&event.new_block_key) { - self.new_block = block; - } - } - if let Some(loc) = event.location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.block_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - } - } - if !event.block_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_key) { - self.old_block = block; - } - } - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_from_to::BlockFromToEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let location = build_location( - self.world_uuid, - &Vector3::new( - f64::from(self.block_pos.0.x), - f64::from(self.block_pos.0.y), - f64::from(self.block_pos.0.z), - ), - 0.0, - 0.0, - ); - let to_location = build_location( - self.world_uuid, - &Vector3::new( - f64::from(self.to_pos.0.x), - f64::from(self.to_pos.0.y), - f64::from(self.to_pos.0.z), - ), - 0.0, - 0.0, - ); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockFromTo(BlockFromToEvent { - block_key: block_to_key(self.block), - location: Some(location), - to_block_key: block_to_key(self.to_block), - to_location: Some(to_location), - face: block_face_to_bukkit(Some(self.face)), - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockFromTo(event) => { - if !event.to_block_key.is_empty() { - if let Some(block) = Block::from_name(&event.to_block_key) { - self.to_block = block; - } - } - if let Some(loc) = event.to_location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.to_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - } - } - if let Some(face) = bukkit_block_face_from_string(&event.face) { - self.face = face; - } - if !event.block_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_key) { - self.block = block; - } - } - if let Some(loc) = event.location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.block_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - } - } - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_grow::BlockGrowEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let location = build_location( - self.world_uuid, - &Vector3::new( - f64::from(self.block_pos.0.x), - f64::from(self.block_pos.0.y), - f64::from(self.block_pos.0.z), - ), - 0.0, - 0.0, - ); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockGrow(BlockGrowEvent { - block_key: block_to_key(self.block), - new_block_key: block_to_key(self.new_block), - location: Some(location), - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockGrow(event) => { - if !event.new_block_key.is_empty() { - if let Some(block) = Block::from_name(&event.new_block_key) { - self.new_block = block; - } - } - if let Some(loc) = event.location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.block_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - } - } - if !event.block_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_key) { - self.block = block; - } - } - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_piston_extend::BlockPistonExtendEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let location = build_location( - self.world_uuid, - &Vector3::new( - f64::from(self.block_pos.0.x), - f64::from(self.block_pos.0.y), - f64::from(self.block_pos.0.z), - ), - 0.0, - 0.0, - ); - let blocks = self - .blocks - .iter() - .map(|pos| { - let loc = build_location( - self.world_uuid, - &Vector3::new(f64::from(pos.0.x), f64::from(pos.0.y), f64::from(pos.0.z)), - 0.0, - 0.0, - ); - BlockPistonBlockEntry { - block_key: String::new(), - location: Some(loc), - } - }) - .collect(); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockPistonExtend(BlockPistonExtendEvent { - block_key: block_to_key(self.block), - location: Some(location), - direction: block_face_to_bukkit(Some(self.direction)), - length: self.length, - blocks, - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockPistonExtend(event) => { - self.length = event.length; - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_piston_retract::BlockPistonRetractEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let location = build_location( - self.world_uuid, - &Vector3::new( - f64::from(self.block_pos.0.x), - f64::from(self.block_pos.0.y), - f64::from(self.block_pos.0.z), - ), - 0.0, - 0.0, - ); - let blocks = self - .blocks - .iter() - .map(|pos| { - let loc = build_location( - self.world_uuid, - &Vector3::new(f64::from(pos.0.x), f64::from(pos.0.y), f64::from(pos.0.z)), - 0.0, - 0.0, - ); - BlockPistonBlockEntry { - block_key: String::new(), - location: Some(loc), - } - }) - .collect(); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockPistonRetract(BlockPistonRetractEvent { - block_key: block_to_key(self.block), - location: Some(location), - direction: block_face_to_bukkit(Some(self.direction)), - length: self.length, - blocks, - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockPistonRetract(event) => { - self.length = event.length; - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_redstone::BlockRedstoneEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let world_uuid = server - .worlds - .load() - .first() - .map(|world| world.uuid) - .unwrap_or_default(); - let location = build_location( - world_uuid, - &Vector3::new( - f64::from(self.block_pos.0.x), - f64::from(self.block_pos.0.y), - f64::from(self.block_pos.0.z), - ), - 0.0, - 0.0, - ); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockRedstone(BlockRedstoneEvent { - block_key: block_to_key(self.block), - location: Some(location), - old_current: self.old_current, - new_current: self.new_current, - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockRedstone(event) => { - self.new_current = event.new_current; - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_multi_place::BlockMultiPlaceEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let world_uuid = self.player.world().uuid; - let origin = self - .positions - .first() - .copied() - .unwrap_or_else(|| self.player.position().to_block_pos()); - let location = build_location( - world_uuid, - &Vector3::new( - f64::from(origin.0.x), - f64::from(origin.0.y), - f64::from(origin.0.z), - ), - 0.0, - 0.0, - ); - let blocks = self - .positions - .iter() - .map(|pos| { - let loc = build_location( - world_uuid, - &Vector3::new(f64::from(pos.0.x), f64::from(pos.0.y), f64::from(pos.0.z)), - 0.0, - 0.0, - ); - BlockMultiPlaceBlockEntry { - block_key: block_to_key(self.block_placed), - location: Some(loc), - } - }) - .collect(); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockMultiPlace(BlockMultiPlaceEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - block_key: block_to_key(self.block_placed), - location: Some(location), - blocks, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, _data: Data) -> Option<()> { - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_physics::BlockPhysicsEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let location = build_location( - self.world_uuid, - &Vector3::new( - f64::from(self.block_pos.0.x), - f64::from(self.block_pos.0.y), - f64::from(self.block_pos.0.z), - ), - 0.0, - 0.0, - ); - let source_location = build_location( - self.world_uuid, - &Vector3::new( - f64::from(self.source_pos.0.x), - f64::from(self.source_pos.0.y), - f64::from(self.source_pos.0.z), - ), - 0.0, - 0.0, - ); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockPhysics(BlockPhysicsEvent { - block_key: block_to_key(self.block), - location: Some(location), - source_block_key: block_to_key(self.source_block), - source_location: Some(source_location), - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, _data: Data) -> Option<()> { - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::note_play::NotePlayEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let location = build_location( - self.world_uuid, - &Vector3::new( - f64::from(self.block_pos.0.x), - f64::from(self.block_pos.0.y), - f64::from(self.block_pos.0.z), - ), - 0.0, - 0.0, - ); - - JvmEventPayload { - event: Event { - data: Some(Data::NotePlay(NotePlayEvent { - block_key: block_to_key(self.block), - location: Some(location), - instrument: instrument_to_bukkit(self.instrument), - note: i32::from(self.note), - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::NotePlay(event) => { - if !event.block_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_key) { - self.block = block; - } - } - if let Some(loc) = event.location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.block_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - } - if let Some(world) = loc.world.and_then(|w| w.uuid) { - if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { - self.world_uuid = uuid; - } - } - } - if !event.instrument.is_empty() { - if let Some(instrument) = instrument_from_bukkit(&event.instrument) { - self.instrument = instrument; - } - } - self.note = event.note.clamp(0, 24) as u8; - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::sign_change::SignChangeEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let world_uuid = self.player.world().uuid; - let location = build_location( - world_uuid, - &Vector3::new( - f64::from(self.block_pos.0.x), - f64::from(self.block_pos.0.y), - f64::from(self.block_pos.0.z), - ), - 0.0, - 0.0, - ); - - JvmEventPayload { - event: Event { - data: Some(Data::SignChange(SignChangeEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - block_key: block_to_key(self.block), - location: Some(location), - lines: self.lines.clone(), - is_front_text: self.is_front_text, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { - match data { - Data::SignChange(event) => { - if let Some(uuid) = event.player_uuid { - if let Ok(uuid) = uuid::Uuid::from_str(&uuid.value) { - if let Some(player) = server.get_player_by_uuid(uuid) { - self.player = player; - } - } - } - if !event.block_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_key) { - self.block = block; - } - } - if let Some(loc) = event.location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.block_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - } - } - if !event.lines.is_empty() { - self.lines = event.lines; - } - self.is_front_text = event.is_front_text; - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::tnt_prime::TNTPrimeEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let location = build_location( - self.world_uuid, - &Vector3::new( - f64::from(self.block_pos.0.x), - f64::from(self.block_pos.0.y), - f64::from(self.block_pos.0.z), - ), - 0.0, - 0.0, - ); - let player_uuid = self.player.as_ref().map(|player| Uuid { - value: player.gameprofile.id.to_string(), - }); - - JvmEventPayload { - event: Event { - data: Some(Data::TntPrime(TntPrimeEvent { - player_uuid, - block_key: block_to_key(self.block), - location: Some(location), - cause: self.cause.clone(), - })), - }, - context: EventContext { - server, - player: self.player.clone(), - }, - } - } - - fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { - match data { - Data::TntPrime(event) => { - if let Some(uuid) = event.player_uuid { - if let Ok(uuid) = uuid::Uuid::from_str(&uuid.value) { - self.player = server.get_player_by_uuid(uuid); - } - } else { - self.player = None; - } - if !event.block_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_key) { - self.block = block; - } - } - if let Some(loc) = event.location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.block_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - } - if let Some(world) = loc.world.and_then(|w| w.uuid) { - if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { - self.world_uuid = uuid; - } - } - } - if !event.cause.is_empty() { - self.cause = event.cause; - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::moisture_change::MoistureChangeEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let location = build_location( - self.world_uuid, - &Vector3::new( - f64::from(self.block_pos.0.x), - f64::from(self.block_pos.0.y), - f64::from(self.block_pos.0.z), - ), - 0.0, - 0.0, - ); - let new_block_key = Block::from_state_id(self.new_state_id) - .map(block_to_key) - .unwrap_or_default(); - - JvmEventPayload { - event: Event { - data: Some(Data::MoistureChange(MoistureChangeEvent { - block_key: block_to_key(self.block), - location: Some(location), - new_block_key, - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::MoistureChange(event) => { - if !event.block_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_key) { - self.block = block; - } - } - if let Some(loc) = event.location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.block_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - } - if let Some(world) = loc.world.and_then(|w| w.uuid) { - if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { - self.world_uuid = uuid; - } - } - } - if !event.new_block_key.is_empty() { - if let Some(block) = Block::from_name(&event.new_block_key) { - self.new_state_id = block.default_state.id; - } - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::sponge_absorb::SpongeAbsorbEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let location = build_location( - self.world_uuid, - &Vector3::new( - f64::from(self.block_pos.0.x), - f64::from(self.block_pos.0.y), - f64::from(self.block_pos.0.z), - ), - 0.0, - 0.0, - ); - let blocks = self - .blocks - .iter() - .map(|pos| { - let loc = build_location( - self.world_uuid, - &Vector3::new(f64::from(pos.0.x), f64::from(pos.0.y), f64::from(pos.0.z)), - 0.0, - 0.0, - ); - SpongeAbsorbBlockEntry { - block_key: block_to_key(&Block::WATER), - location: Some(loc), - } - }) - .collect(); - - JvmEventPayload { - event: Event { - data: Some(Data::SpongeAbsorb(SpongeAbsorbEvent { - block_key: block_to_key(self.block), - location: Some(location), - blocks, - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::SpongeAbsorb(event) => { - if !event.block_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_key) { - self.block = block; - } - } - if let Some(loc) = event.location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.block_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - } - if let Some(world) = loc.world.and_then(|w| w.uuid) { - if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { - self.world_uuid = uuid; - } - } - } - if !event.blocks.is_empty() { - let mut blocks = Vec::with_capacity(event.blocks.len()); - for entry in event.blocks { - if let Some(loc) = entry.location.and_then(location_to_vec3) { - blocks.push(pumpkin_util::math::position::BlockPos::new( - loc.x.floor() as i32, - loc.y.floor() as i32, - loc.z.floor() as i32, - )); - } - } - self.blocks = blocks; - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::fluid_level_change::FluidLevelChangeEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let location = build_location( - self.world_uuid, - &Vector3::new( - f64::from(self.block_pos.0.x), - f64::from(self.block_pos.0.y), - f64::from(self.block_pos.0.z), - ), - 0.0, - 0.0, - ); - let new_block_key = Block::from_state_id(self.new_state_id) - .map(block_to_key) - .unwrap_or_default(); - - JvmEventPayload { - event: Event { - data: Some(Data::FluidLevelChange(FluidLevelChangeEvent { - block_key: block_to_key(self.block), - location: Some(location), - new_block_key, - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::FluidLevelChange(event) => { - if !event.block_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_key) { - self.block = block; - } - } - if let Some(loc) = event.location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.block_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - } - if let Some(world) = loc.world.and_then(|w| w.uuid) { - if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { - self.world_uuid = uuid; - } - } - } - if !event.new_block_key.is_empty() { - if let Some(block) = Block::from_name(&event.new_block_key) { - self.new_state_id = block.default_state.id; - } - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::world::spawn_change::SpawnChangeEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let world_uuid = self.world.uuid; - let previous_location = build_location( - world_uuid, - &Vector3::new( - f64::from(self.previous_position.0.x), - f64::from(self.previous_position.0.y), - f64::from(self.previous_position.0.z), - ), - 0.0, - 0.0, - ); - let location = build_location( - world_uuid, - &Vector3::new( - f64::from(self.new_position.0.x), - f64::from(self.new_position.0.y), - f64::from(self.new_position.0.z), - ), - 0.0, - 0.0, - ); - - JvmEventPayload { - event: Event { - data: Some(Data::SpawnChange(SpawnChangeEvent { - previous_location: Some(previous_location), - location: Some(location), - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::SpawnChange(event) => { - if let Some(loc) = event.location.and_then(location_to_vec3) { - self.new_position = pumpkin_util::math::position::BlockPos::new( - loc.x.floor() as i32, - loc.y.floor() as i32, - loc.z.floor() as i32, - ); - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::server::server_list_ping::ServerListPingEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::ServerListPing(ServerListPingEvent { - motd: self.motd.clone(), - max_players: self.max_players as i32, - online_players: self.num_players as i32, - favicon: self.favicon.clone().unwrap_or_default(), - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::ServerListPing(event) => { - if !event.motd.is_empty() { - self.motd = event.motd; - } - if event.max_players >= 0 { - self.max_players = event.max_players as u32; - } - if event.online_players >= 0 { - self.num_players = event.online_players as u32; - } - if !event.favicon.is_empty() { - self.favicon = Some(event.favicon); - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::server::plugin_enable::PluginEnableEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PluginEnable(PluginEnableEvent { - plugin_name: self.plugin_name.clone(), - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PluginEnable(event) => { - if !event.plugin_name.is_empty() { - self.plugin_name = event.plugin_name; - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::server::plugin_disable::PluginDisableEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PluginDisable(PluginDisableEvent { - plugin_name: self.plugin_name.clone(), - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PluginDisable(event) => { - if !event.plugin_name.is_empty() { - self.plugin_name = event.plugin_name; - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::server::service_register::ServiceRegisterEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::ServiceRegister(ServiceRegisterEvent { - plugin_name: self.plugin_name.clone(), - service_name: self.service_name.clone(), - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::ServiceRegister(event) => { - if !event.plugin_name.is_empty() { - self.plugin_name = event.plugin_name; - } - if !event.service_name.is_empty() { - self.service_name = event.service_name; - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::server::service_unregister::ServiceUnregisterEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::ServiceUnregister(ServiceUnregisterEvent { - plugin_name: self.plugin_name.clone(), - service_name: self.service_name.clone(), - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::ServiceUnregister(event) => { - if !event.plugin_name.is_empty() { - self.plugin_name = event.plugin_name; - } - if !event.service_name.is_empty() { - self.service_name = event.service_name; - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_place::BlockPlaceEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let player_uuid = self.player.gameprofile.id.to_string(); - let world_uuid = self.player.world().uuid; - let location = build_location( - world_uuid, - &Vector3::new( - f64::from(self.position.0.x), - f64::from(self.position.0.y), - f64::from(self.position.0.z), - ), - 0.0, - 0.0, - ); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockPlace(BlockPlaceEvent { - player_uuid: Some(Uuid { value: player_uuid }), - block_key: block_to_key(self.block_placed), - block_against_key: block_to_key(self.block_placed_against), - location: Some(location), - can_build: self.can_build, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockPlace(event) => { - self.can_build = event.can_build; - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_can_build::BlockCanBuildEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let player_uuid = self.player.gameprofile.id.to_string(); - let world_uuid = self.player.world().uuid; - let location = build_location( - world_uuid, - &Vector3::new( - f64::from(self.block_pos.0.x), - f64::from(self.block_pos.0.y), - f64::from(self.block_pos.0.z), - ), - 0.0, - 0.0, - ); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockCanBuild(BlockCanBuildEvent { - player_uuid: Some(Uuid { value: player_uuid }), - block_key: block_to_key(self.block_to_build), - block_against_key: block_to_key(self.block), - location: Some(location), - can_build: self.buildable, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockCanBuild(event) => { - self.buildable = event.can_build; - if let Some(loc) = event.location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.block_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - } - } - if !event.block_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_key) { - self.block_to_build = block; - } - } - if !event.block_against_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_against_key) { - self.block = block; - } - } - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_burn::BlockBurnEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let location = build_location( - self.world_uuid, - &Vector3::new( - f64::from(self.block_pos.0.x), - f64::from(self.block_pos.0.y), - f64::from(self.block_pos.0.z), - ), - 0.0, - 0.0, - ); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockBurn(BlockBurnEvent { - block_key: block_to_key(self.block), - igniting_block_key: block_to_key(self.igniting_block), - location: Some(location), - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, _data: Data) -> Option<()> { - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_ignite::BlockIgniteEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let location = build_location( - self.world_uuid, - &Vector3::new( - f64::from(self.block_pos.0.x), - f64::from(self.block_pos.0.y), - f64::from(self.block_pos.0.z), - ), - 0.0, - 0.0, - ); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockIgnite(BlockIgniteEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - block_key: block_to_key(self.block), - igniting_block_key: block_to_key(self.igniting_block), - location: Some(location), - cause: self.cause.clone(), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockIgnite(event) => { - if !event.block_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_key) { - self.block = block; - } - } - if !event.igniting_block_key.is_empty() { - if let Some(block) = Block::from_name(&event.igniting_block_key) { - self.igniting_block = block; - } - } - if let Some(loc) = event.location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.block_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - } - if let Some(world) = loc.world.and_then(|w| w.uuid) { - if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { - self.world_uuid = uuid; - } - } - } - if !event.cause.is_empty() { - self.cause = event.cause; - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_spread::BlockSpreadEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let source_location = build_location( - self.world_uuid, - &Vector3::new( - f64::from(self.source_pos.0.x), - f64::from(self.source_pos.0.y), - f64::from(self.source_pos.0.z), - ), - 0.0, - 0.0, - ); - let location = build_location( - self.world_uuid, - &Vector3::new( - f64::from(self.block_pos.0.x), - f64::from(self.block_pos.0.y), - f64::from(self.block_pos.0.z), - ), - 0.0, - 0.0, - ); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockSpread(BlockSpreadEvent { - source_block_key: block_to_key(self.source_block), - source_location: Some(source_location), - block_key: block_to_key(self.block), - location: Some(location), - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockSpread(event) => { - if !event.source_block_key.is_empty() { - if let Some(block) = Block::from_name(&event.source_block_key) { - self.source_block = block; - } - } - if !event.block_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_key) { - self.block = block; - } - } - if let Some(loc) = event.source_location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.source_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - } - if let Some(world) = loc.world.and_then(|w| w.uuid) { - if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { - self.world_uuid = uuid; - } - } - } - if let Some(loc) = event.location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.block_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - } - if let Some(world) = loc.world.and_then(|w| w.uuid) { - if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { - self.world_uuid = uuid; - } - } - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::entity::entity_spawn::EntitySpawnEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::EntitySpawn(EntitySpawnEvent { - entity_uuid: Some(Uuid { - value: self.entity_uuid.to_string(), - }), - entity_type: self.entity_type.id.to_string(), - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, _data: Data) -> Option<()> { - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::entity::entity_damage::EntityDamageEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::EntityDamage(EntityDamageEvent { - entity_uuid: Some(Uuid { - value: self.entity_uuid.to_string(), - }), - damage: self.damage, - damage_type: self.damage_type.message_id.to_string(), - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::EntityDamage(event) => { - self.damage = event.damage; - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::entity::entity_death::EntityDeathEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::EntityDeath(EntityDeathEvent { - entity_uuid: Some(Uuid { - value: self.entity_uuid.to_string(), - }), - damage_type: self.damage_type.message_id.to_string(), - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, _data: Data) -> Option<()> { - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::server::server_command::ServerCommandEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::ServerCommand(ServerCommandEvent { - command: self.command.clone(), - })), - }, - context: EventContext { - server, - player: None, - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::ServerCommand(event) => { - self.command = event.command; - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::server::server_broadcast::ServerBroadcastEvent { +impl PatchBukkitEvent for pumpkin::plugin::api::events::server::server_broadcast::ServerBroadcastEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { JvmEventPayload { event: Event { @@ -4191,33 +661,27 @@ impl PatchBukkitEvent for pumpkin::plugin::server::server_broadcast::ServerBroad sender: serde_json::to_string(&self.sender).unwrap(), })), }, - context: EventContext { - server, - player: None, - }, + context: EventContext { server, player: None }, } } fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { match data { Data::ServerBroadcast(event) => { - self.message = serde_json::from_str(&event.message).unwrap_or_else(|_| { - TextComponent::from_legacy_string(&event.message) - }); - self.sender = serde_json::from_str(&event.sender).unwrap_or_else(|_| { - TextComponent::from_legacy_string(&event.sender) - }); + self.message = serde_json::from_str(&event.message) + .unwrap_or_else(|_| TextComponent::from_legacy_string(&event.message)); + self.sender = serde_json::from_str(&event.sender) + .unwrap_or_else(|_| TextComponent::from_legacy_string(&event.sender)); } _ => {} } - Some(()) } } fn build_location(world_uuid: uuid::Uuid, position: &Vector3, yaw: f32, pitch: f32) -> Location { Location { - world: Some(World { + world: Some(ProtoWorld { uuid: Some(Uuid { value: world_uuid.to_string(), }), @@ -4241,58 +705,17 @@ fn block_to_key(block: &Block) -> String { format!("minecraft:{}", block.name) } -fn item_to_key(item: &Item) -> String { +fn item_to_key(item: &pumpkin_data::item::Item) -> String { format!("minecraft:{}", item.registry_key) } -fn item_stack_from_key(key: &str, amount: u8) -> ItemStack { - let trimmed = key.strip_prefix("minecraft:").unwrap_or(key); - let item = Item::from_registry_key(trimmed).unwrap_or(&Item::AIR); - ItemStack::new(amount, item) -} - -fn equipment_slot_to_bukkit(slot: &EquipmentSlot) -> String { - match slot { - EquipmentSlot::MainHand(_) => "HAND".to_string(), - EquipmentSlot::OffHand(_) => "OFF_HAND".to_string(), - EquipmentSlot::Feet(_) => "FEET".to_string(), - EquipmentSlot::Legs(_) => "LEGS".to_string(), - EquipmentSlot::Chest(_) => "CHEST".to_string(), - EquipmentSlot::Head(_) => "HEAD".to_string(), - EquipmentSlot::Body(_) => "BODY".to_string(), - EquipmentSlot::Saddle(_) => "SADDLE".to_string(), - } -} - -fn equipment_slot_from_bukkit(slot: &str) -> Option { - match slot { - "HAND" => Some(EquipmentSlot::MAIN_HAND), - "OFF_HAND" => Some(EquipmentSlot::OFF_HAND), - "FEET" => Some(EquipmentSlot::FEET), - "LEGS" => Some(EquipmentSlot::LEGS), - "CHEST" => Some(EquipmentSlot::CHEST), - "HEAD" => Some(EquipmentSlot::HEAD), - "BODY" => Some(EquipmentSlot::BODY), - "SADDLE" => Some(EquipmentSlot::SADDLE), - _ => None, - } -} - -fn interact_action_to_bukkit(action: &pumpkin::plugin::player::player_interact_event::InteractAction) -> String { - match action { - pumpkin::plugin::player::player_interact_event::InteractAction::LeftClickBlock => { - "LEFT_CLICK_BLOCK".to_string() - } - pumpkin::plugin::player::player_interact_event::InteractAction::LeftClickAir => { - "LEFT_CLICK_AIR".to_string() - } - pumpkin::plugin::player::player_interact_event::InteractAction::RightClickAir => { - "RIGHT_CLICK_AIR".to_string() - } - pumpkin::plugin::player::player_interact_event::InteractAction::RightClickBlock => { - "RIGHT_CLICK_BLOCK".to_string() - } - } +fn find_world_by_uuid(server: &Arc, world_uuid: uuid::Uuid) -> Option> { + server + .worlds + .load() + .iter() + .find(|world| world.uuid == world_uuid) + .cloned() } fn gamemode_to_bukkit(mode: pumpkin_util::GameMode) -> String { @@ -4314,90 +737,41 @@ fn gamemode_from_bukkit(mode: &str) -> Option { } } -fn block_face_to_bukkit(face: Option) -> String { - match face { - Some(BlockDirection::Up) => "UP".to_string(), - Some(BlockDirection::Down) => "DOWN".to_string(), - Some(BlockDirection::North) => "NORTH".to_string(), - Some(BlockDirection::South) => "SOUTH".to_string(), - Some(BlockDirection::West) => "WEST".to_string(), - Some(BlockDirection::East) => "EAST".to_string(), - None => String::new(), - } -} - -fn bukkit_block_face_from_string(face: &str) -> Option { - match face { - "UP" => Some(BlockDirection::Up), - "DOWN" => Some(BlockDirection::Down), - "NORTH" => Some(BlockDirection::North), - "SOUTH" => Some(BlockDirection::South), - "WEST" => Some(BlockDirection::West), - "EAST" => Some(BlockDirection::East), - _ => None, - } -} - -fn bukkit_main_hand(hand: Hand) -> String { - match hand { - Hand::Left => "LEFT".to_string(), - Hand::Right => "RIGHT".to_string(), - } -} - -fn instrument_to_bukkit(instrument: Instrument) -> String { - match instrument { - Instrument::Harp => "PIANO".to_string(), - Instrument::Basedrum => "BASS_DRUM".to_string(), - Instrument::Snare => "SNARE_DRUM".to_string(), - Instrument::Hat => "STICKS".to_string(), - Instrument::Bass => "BASS_GUITAR".to_string(), - Instrument::Flute => "FLUTE".to_string(), - Instrument::Bell => "BELL".to_string(), - Instrument::Guitar => "GUITAR".to_string(), - Instrument::Chime => "CHIME".to_string(), - Instrument::Xylophone => "XYLOPHONE".to_string(), - Instrument::IronXylophone => "IRON_XYLOPHONE".to_string(), - Instrument::CowBell => "COW_BELL".to_string(), - Instrument::Didgeridoo => "DIDGERIDOO".to_string(), - Instrument::Bit => "BIT".to_string(), - Instrument::Banjo => "BANJO".to_string(), - Instrument::Pling => "PLING".to_string(), - Instrument::Zombie => "ZOMBIE".to_string(), - Instrument::Skeleton => "SKELETON".to_string(), - Instrument::Creeper => "CREEPER".to_string(), - Instrument::Dragon => "DRAGON".to_string(), - Instrument::WitherSkeleton => "WITHER_SKELETON".to_string(), - Instrument::Piglin => "PIGLIN".to_string(), - Instrument::CustomHead => "CUSTOM_HEAD".to_string(), +fn interact_action_to_bukkit( + action: &pumpkin::plugin::api::events::player::player_interact_event::InteractAction, +) -> String { + match action { + pumpkin::plugin::api::events::player::player_interact_event::InteractAction::LeftClickBlock => { + "LEFT_CLICK_BLOCK".to_string() + } + pumpkin::plugin::api::events::player::player_interact_event::InteractAction::LeftClickAir => { + "LEFT_CLICK_AIR".to_string() + } + pumpkin::plugin::api::events::player::player_interact_event::InteractAction::RightClickAir => { + "RIGHT_CLICK_AIR".to_string() + } + pumpkin::plugin::api::events::player::player_interact_event::InteractAction::RightClickBlock => { + "RIGHT_CLICK_BLOCK".to_string() + } } } -fn instrument_from_bukkit(name: &str) -> Option { - match name { - "PIANO" => Some(Instrument::Harp), - "BASS_DRUM" => Some(Instrument::Basedrum), - "SNARE_DRUM" => Some(Instrument::Snare), - "STICKS" => Some(Instrument::Hat), - "BASS_GUITAR" => Some(Instrument::Bass), - "FLUTE" => Some(Instrument::Flute), - "BELL" => Some(Instrument::Bell), - "GUITAR" => Some(Instrument::Guitar), - "CHIME" => Some(Instrument::Chime), - "XYLOPHONE" => Some(Instrument::Xylophone), - "IRON_XYLOPHONE" => Some(Instrument::IronXylophone), - "COW_BELL" => Some(Instrument::CowBell), - "DIDGERIDOO" => Some(Instrument::Didgeridoo), - "BIT" => Some(Instrument::Bit), - "BANJO" => Some(Instrument::Banjo), - "PLING" => Some(Instrument::Pling), - "ZOMBIE" => Some(Instrument::Zombie), - "SKELETON" => Some(Instrument::Skeleton), - "CREEPER" => Some(Instrument::Creeper), - "DRAGON" => Some(Instrument::Dragon), - "WITHER_SKELETON" => Some(Instrument::WitherSkeleton), - "PIGLIN" => Some(Instrument::Piglin), - "CUSTOM_HEAD" => Some(Instrument::CustomHead), +fn interact_action_from_bukkit( + action: &str, +) -> Option { + match action { + "LEFT_CLICK_BLOCK" => Some( + pumpkin::plugin::api::events::player::player_interact_event::InteractAction::LeftClickBlock, + ), + "LEFT_CLICK_AIR" => Some( + pumpkin::plugin::api::events::player::player_interact_event::InteractAction::LeftClickAir, + ), + "RIGHT_CLICK_AIR" => Some( + pumpkin::plugin::api::events::player::player_interact_event::InteractAction::RightClickAir, + ), + "RIGHT_CLICK_BLOCK" => Some( + pumpkin::plugin::api::events::player::player_interact_event::InteractAction::RightClickBlock, + ), _ => None, } } @@ -4448,7 +822,9 @@ where match rx.await { Ok(response) => { event.set_cancelled(response.cancelled); - event.apply_modifications(server, response.data.unwrap().data.unwrap()); + if let Some(data) = response.data.and_then(|d| d.data) { + event.apply_modifications(server, data); + } } Err(_) => { log::warn!("JVM worker dropped response channel for event"); diff --git a/rust/src/events/handler_legacy.rs b/rust/src/events/handler_legacy.rs new file mode 100644 index 0000000..01babef --- /dev/null +++ b/rust/src/events/handler_legacy.rs @@ -0,0 +1,4459 @@ +use std::marker::PhantomData; +use std::str::FromStr; +use std::sync::Arc; + +use pumpkin::entity::player::Player; +use pumpkin::plugin::{BoxFuture, Cancellable, EventHandler, Payload}; +use pumpkin::server::Server; +use pumpkin_api_macros::with_runtime; +use pumpkin_data::data_component_impl::EquipmentSlot; +use pumpkin_data::{Block, BlockDirection}; +use pumpkin_data::block_properties::Instrument; +use pumpkin_data::item::Item; +use pumpkin_util::Hand; +use pumpkin_util::math::vector3::Vector3; +use pumpkin_util::text::TextComponent; +use pumpkin_world::item::ItemStack; +use tokio::sync::{mpsc, oneshot}; + +use crate::java::jvm::commands::JvmCommand; +use crate::proto::patchbukkit::common::{Location, Uuid, Vec3, World}; +use crate::proto::patchbukkit::events::event::Data; +use crate::proto::patchbukkit::events::{ + BlockBreakEvent, BlockDamageEvent, BlockDamageAbortEvent, BlockDispenseEvent, BlockDropItemEntry, BlockDropItemEvent, BlockExplodeBlockEntry, BlockExplodeEvent, BlockFadeEvent, BlockFertilizeBlockEntry, BlockFertilizeEvent, BlockFormEvent, BlockFromToEvent, BlockGrowEvent, BlockPistonBlockEntry, BlockPistonExtendEvent, BlockPistonRetractEvent, BlockRedstoneEvent, BlockMultiPlaceBlockEntry, BlockMultiPlaceEvent, BlockPhysicsEvent, BlockPlaceEvent, BlockCanBuildEvent, BlockBurnEvent, BlockIgniteEvent, BlockSpreadEvent, NotePlayEvent, SignChangeEvent, TntPrimeEvent, MoistureChangeEvent, SpongeAbsorbEvent, SpongeAbsorbBlockEntry, FluidLevelChangeEvent, SpawnChangeEvent, ServerListPingEvent, PluginEnableEvent, PluginDisableEvent, ServiceRegisterEvent, ServiceUnregisterEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, + PlayerLeaveEvent, PlayerMoveEvent, PlayerInteractEvent, ServerBroadcastEvent, ServerCommandEvent, + EntityDamageEvent, EntityDeathEvent, EntitySpawnEvent, + PlayerLoginEvent, PlayerTeleportEvent, PlayerChangeWorldEvent, PlayerGamemodeChangeEvent, + AsyncPlayerPreLoginEvent, PlayerAdvancementDoneEvent, PlayerAnimationEvent, + PlayerArmorStandManipulateEvent, + PlayerBedEnterEvent, PlayerBedLeaveEvent, + PlayerBucketEmptyEvent, PlayerBucketFillEvent, PlayerBucketEntityEvent, + PlayerChangedMainHandEvent, + PlayerRegisterChannelEvent, PlayerUnregisterChannelEvent, PlayerDropItemEvent, + PlayerEditBookEvent, PlayerEggThrowEvent, PlayerExpChangeEvent, PlayerFishEvent, + PlayerInteractEntityEvent, PlayerInteractAtEntityEvent, PlayerItemHeldEvent, + PlayerItemDamageEvent, PlayerItemBreakEvent, PlayerItemConsumeEvent, PlayerItemMendEvent, + PlayerLevelChangeEvent, PlayerKickEvent, + PlayerToggleSneakEvent, PlayerToggleSprintEvent, PlayerToggleFlightEvent, + PlayerSwapHandItemsEvent, PlayerResourcePackStatusEvent, PlayerRespawnEvent, + PlayerPickupArrowEvent, PlayerPortalEvent, PlayerRecipeDiscoverEvent, PlayerRiptideEvent, + PlayerShearEntityEvent, PlayerSpawnLocationEvent, PlayerStatisticIncrementEvent, + PlayerVelocityEvent, PlayerHarvestBlockEvent, +}; + +pub struct EventContext { + pub server: Arc, + pub player: Option>, +} + +pub struct JvmEventPayload { + pub event: Event, + pub context: EventContext, +} + +pub trait PatchBukkitEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload; + fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()>; +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_join::PlayerJoinEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerJoin(PlayerJoinEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + join_message: serde_json::to_string(&self.join_message).unwrap(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerJoin(event) => { + self.join_message = serde_json::from_str(&event.join_message).ok()?; + server.get_player_by_uuid(uuid::Uuid::from_str(&event.player_uuid?.value).ok()?)?; + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_login::PlayerLoginEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerLogin(PlayerLoginEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + kick_message: serde_json::to_string(&self.kick_message).unwrap(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerLogin(event) => { + self.kick_message = serde_json::from_str(&event.kick_message).ok()?; + server.get_player_by_uuid(uuid::Uuid::from_str(&event.player_uuid?.value).ok()?)?; + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_pre_login::PlayerPreLoginEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::AsyncPlayerPreLogin(AsyncPlayerPreLoginEvent { + name: self.name.clone(), + player_uuid: Some(Uuid { + value: self.player_uuid.to_string(), + }), + address: self.address.clone(), + result: self.result.clone(), + kick_message: self.kick_message.clone(), + })), + }, + context: EventContext { + server, + player: None, + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::AsyncPlayerPreLogin(event) => { + self.result = event.result; + self.kick_message = event.kick_message; + if let Some(uuid) = event.player_uuid { + self.player_uuid = uuid::Uuid::from_str(&uuid.value).ok()?; + } + if !event.name.is_empty() { + self.name = event.name; + } + if !event.address.is_empty() { + self.address = event.address; + } + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_leave::PlayerLeaveEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerLeave(PlayerLeaveEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + leave_message: serde_json::to_string(&self.leave_message).unwrap(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerLeave(event) => { + self.leave_message = serde_json::from_str(&event.leave_message).ok()?; + server.get_player_by_uuid(uuid::Uuid::from_str(&event.player_uuid?.value).ok()?)?; + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_advancement_done::PlayerAdvancementDoneEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerAdvancementDone(PlayerAdvancementDoneEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + advancement_key: self.advancement_key.clone(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, _data: Data) -> Option<()> { + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_animation::PlayerAnimationEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerAnimation(PlayerAnimationEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + animation_type: self.animation_type.clone(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, _data: Data) -> Option<()> { + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_armor_stand_manipulate::PlayerArmorStandManipulateEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerArmorStandManipulate( + PlayerArmorStandManipulateEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + armor_stand_uuid: Some(Uuid { + value: self.armor_stand_uuid.to_string(), + }), + item_key: self.item_key.clone(), + armor_stand_item_key: self.armor_stand_item_key.clone(), + slot: self.slot.clone(), + }, + )), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerArmorStandManipulate(event) => { + if !event.item_key.is_empty() { + self.item_key = event.item_key; + } + if !event.armor_stand_item_key.is_empty() { + self.armor_stand_item_key = event.armor_stand_item_key; + } + if !event.slot.is_empty() { + self.slot = event.slot; + } + if let Some(uuid) = event.armor_stand_uuid { + self.armor_stand_uuid = uuid::Uuid::from_str(&uuid.value).ok()?; + } + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_bed_enter::PlayerBedEnterEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let world_uuid = self.player.world().uuid; + + JvmEventPayload { + event: Event { + data: Some(Data::PlayerBedEnter(PlayerBedEnterEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + bed_location: Some(build_location(world_uuid, &self.bed_position, 0.0, 0.0)), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerBedEnter(event) => { + if let Some(location) = event.bed_location { + if let Some(pos) = location_to_vec3(location) { + self.bed_position = pos; + } + } + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_bed_leave::PlayerBedLeaveEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let world_uuid = self.player.world().uuid; + + JvmEventPayload { + event: Event { + data: Some(Data::PlayerBedLeave(PlayerBedLeaveEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + bed_location: Some(build_location(world_uuid, &self.bed_position, 0.0, 0.0)), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerBedLeave(event) => { + if let Some(location) = event.bed_location { + if let Some(pos) = location_to_vec3(location) { + self.bed_position = pos; + } + } + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_bucket_empty::PlayerBucketEmptyEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let world_uuid = self.player.world().uuid; + JvmEventPayload { + event: Event { + data: Some(Data::PlayerBucketEmpty(PlayerBucketEmptyEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + location: Some(build_location(world_uuid, &self.position, 0.0, 0.0)), + block_key: self.block_key.clone(), + block_face: block_face_to_bukkit(self.face), + bucket_item_key: self.bucket_item_key.clone(), + hand: self.hand.clone(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerBucketEmpty(event) => { + if let Some(location) = event.location { + if let Some(pos) = location_to_vec3(location) { + self.position = pos; + } + } + if !event.block_key.is_empty() { + self.block_key = event.block_key; + } + if !event.bucket_item_key.is_empty() { + self.bucket_item_key = event.bucket_item_key; + } + if !event.hand.is_empty() { + self.hand = event.hand; + } + self.face = bukkit_block_face_from_string(&event.block_face); + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_bucket_fill::PlayerBucketFillEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let world_uuid = self.player.world().uuid; + JvmEventPayload { + event: Event { + data: Some(Data::PlayerBucketFill(PlayerBucketFillEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + location: Some(build_location(world_uuid, &self.position, 0.0, 0.0)), + block_key: self.block_key.clone(), + block_face: block_face_to_bukkit(self.face), + bucket_item_key: self.bucket_item_key.clone(), + hand: self.hand.clone(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerBucketFill(event) => { + if let Some(location) = event.location { + if let Some(pos) = location_to_vec3(location) { + self.position = pos; + } + } + if !event.block_key.is_empty() { + self.block_key = event.block_key; + } + if !event.bucket_item_key.is_empty() { + self.bucket_item_key = event.bucket_item_key; + } + if !event.hand.is_empty() { + self.hand = event.hand; + } + self.face = bukkit_block_face_from_string(&event.block_face); + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_bucket_entity::PlayerBucketEntityEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerBucketEntity(PlayerBucketEntityEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + entity_uuid: Some(Uuid { + value: self.entity_uuid.to_string(), + }), + entity_type: self.entity_type.clone(), + original_bucket_key: self.original_bucket_key.clone(), + entity_bucket_key: self.entity_bucket_key.clone(), + hand: self.hand.clone(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerBucketEntity(event) => { + if let Some(uuid) = event.entity_uuid { + self.entity_uuid = uuid::Uuid::from_str(&uuid.value).ok()?; + } + if !event.entity_type.is_empty() { + self.entity_type = event.entity_type; + } + if !event.original_bucket_key.is_empty() { + self.original_bucket_key = event.original_bucket_key; + } + if !event.entity_bucket_key.is_empty() { + self.entity_bucket_key = event.entity_bucket_key; + } + if !event.hand.is_empty() { + self.hand = event.hand; + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_changed_main_hand::PlayerChangedMainHandEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerChangedMainHand(PlayerChangedMainHandEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + main_hand: bukkit_main_hand(self.main_hand), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerChangedMainHand(event) => { + if let Ok(uuid) = uuid::Uuid::from_str(&event.player_uuid?.value) { + server.get_player_by_uuid(uuid)?; + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_register_channel::PlayerRegisterChannelEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerRegisterChannel(PlayerRegisterChannelEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + channel: self.channel.clone(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerRegisterChannel(event) => { + if let Ok(uuid) = uuid::Uuid::from_str(&event.player_uuid?.value) { + server.get_player_by_uuid(uuid)?; + } + if !event.channel.is_empty() { + self.channel = event.channel; + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_unregister_channel::PlayerUnregisterChannelEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerUnregisterChannel(PlayerUnregisterChannelEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + channel: self.channel.clone(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerUnregisterChannel(event) => { + if let Ok(uuid) = uuid::Uuid::from_str(&event.player_uuid?.value) { + server.get_player_by_uuid(uuid)?; + } + if !event.channel.is_empty() { + self.channel = event.channel; + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_move::PlayerMoveEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let world_uuid = self.player.world().uuid; + let yaw = self.player.living_entity.entity.yaw.load(); + let pitch = self.player.living_entity.entity.pitch.load(); + + JvmEventPayload { + event: Event { + data: Some(Data::PlayerMove(PlayerMoveEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + from: Some(build_location(world_uuid, &self.from, yaw, pitch)), + to: Some(build_location(world_uuid, &self.to, yaw, pitch)), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerMove(event) => { + server.get_player_by_uuid(uuid::Uuid::from_str(&event.player_uuid?.value).ok()?)?; + if let Some(from) = event.from { + if let Some(from_vec) = location_to_vec3(from) { + self.from = from_vec; + } + } + if let Some(to) = event.to { + if let Some(to_vec) = location_to_vec3(to) { + self.to = to_vec; + } + } + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_teleport::PlayerTeleportEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let world_uuid = self.player.world().uuid; + let yaw = self.player.living_entity.entity.yaw.load(); + let pitch = self.player.living_entity.entity.pitch.load(); + + JvmEventPayload { + event: Event { + data: Some(Data::PlayerTeleport(PlayerTeleportEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + from: Some(build_location(world_uuid, &self.from, yaw, pitch)), + to: Some(build_location(world_uuid, &self.to, yaw, pitch)), + cause: String::new(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerTeleport(event) => { + server.get_player_by_uuid(uuid::Uuid::from_str(&event.player_uuid?.value).ok()?)?; + if let Some(from) = event.from { + if let Some(from_vec) = location_to_vec3(from) { + self.from = from_vec; + } + } + if let Some(to) = event.to { + if let Some(to_vec) = location_to_vec3(to) { + self.to = to_vec; + } + } + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_change_world::PlayerChangeWorldEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let location = build_location(self.new_world.uuid, &self.position, self.yaw, self.pitch); + + JvmEventPayload { + event: Event { + data: Some(Data::PlayerChangeWorld(PlayerChangeWorldEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + previous_world: Some(World { + uuid: Some(Uuid { + value: self.previous_world.uuid.to_string(), + }), + }), + new_world: Some(World { + uuid: Some(Uuid { + value: self.new_world.uuid.to_string(), + }), + }), + position: Some(location), + yaw: self.yaw, + pitch: self.pitch, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerChangeWorld(event) => { + if let Some(position) = event.position.and_then(location_to_vec3) { + self.position = position; + } + self.yaw = event.yaw; + self.pitch = event.pitch; + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_gamemode_change::PlayerGamemodeChangeEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerGamemodeChange(PlayerGamemodeChangeEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + previous_gamemode: gamemode_to_bukkit(self.previous_gamemode), + new_gamemode: gamemode_to_bukkit(self.new_gamemode), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerGamemodeChange(event) => { + if let Some(prev) = gamemode_from_bukkit(&event.previous_gamemode) { + self.previous_gamemode = prev; + } + if let Some(next) = gamemode_from_bukkit(&event.new_gamemode) { + self.new_gamemode = next; + } + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_chat::PlayerChatEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let recipients = self + .recipients + .iter() + .map(|player| Uuid { + value: player.gameprofile.id.to_string(), + }) + .collect(); + + JvmEventPayload { + event: Event { + data: Some(Data::PlayerChat(PlayerChatEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + message: self.message.clone(), + recipients, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerChat(event) => { + self.message = event.message; + if !event.recipients.is_empty() { + let mut recipients = Vec::new(); + for recipient in event.recipients { + let uuid = uuid::Uuid::from_str(&recipient.value).ok()?; + if let Some(player) = server.get_player_by_uuid(uuid) { + recipients.push(player); + } + } + self.recipients = recipients; + } + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_command_preprocess::PlayerCommandPreprocessEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerCommand(PlayerCommandEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + command: self.command.clone(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerCommand(event) => { + if !event.command.is_empty() { + self.command = event.command; + } + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_command_send::PlayerCommandSendEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerCommandSend(crate::proto::patchbukkit::events::PlayerCommandSendEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + commands: self.commands.clone(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerCommandSend(event) => { + self.commands = event.commands; + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_drop_item::PlayerDropItemEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerDropItem(PlayerDropItemEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + item_uuid: Some(Uuid { + value: self.item_uuid.to_string(), + }), + item_key: item_to_key(self.item_stack.item), + item_amount: i32::from(self.item_stack.item_count), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerDropItem(event) => { + if let Some(uuid) = event.item_uuid { + if let Ok(item_uuid) = uuid::Uuid::from_str(&uuid.value) { + self.item_uuid = item_uuid; + } + } + let mut key = if event.item_key.is_empty() { + None + } else { + Some(event.item_key) + }; + let mut amount = if event.item_amount > 0 { + Some(event.item_amount as u8) + } else { + None + }; + + if key.is_some() || amount.is_some() { + let fallback_key = item_to_key(self.item_stack.item); + let key = key.take().unwrap_or(fallback_key); + let count = amount.take().unwrap_or(self.item_stack.item_count); + self.item_stack = item_stack_from_key(&key, count); + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_edit_book::PlayerEditBookEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerEditBook(PlayerEditBookEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + slot: self.slot, + pages: self.pages.clone(), + title: self.title.clone().unwrap_or_default(), + is_signing: self.is_signing, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerEditBook(event) => { + self.slot = event.slot; + self.pages = event.pages; + self.is_signing = event.is_signing; + self.title = if event.title.is_empty() { + None + } else { + Some(event.title) + }; + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_egg_throw::PlayerEggThrowEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerEggThrow(PlayerEggThrowEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + egg_uuid: Some(Uuid { + value: self.egg_uuid.to_string(), + }), + hatching: self.hatching, + num_hatches: i32::from(self.num_hatches), + hatching_type: self.hatching_type.clone(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerEggThrow(event) => { + if let Some(uuid) = event.egg_uuid { + if let Ok(egg_uuid) = uuid::Uuid::from_str(&uuid.value) { + self.egg_uuid = egg_uuid; + } + } + self.hatching = event.hatching; + if event.num_hatches >= 0 { + self.num_hatches = event.num_hatches.min(u8::MAX as i32) as u8; + } + if !event.hatching_type.is_empty() { + self.hatching_type = event.hatching_type; + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_exp_change::PlayerExpChangeEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerExpChange(PlayerExpChangeEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + amount: self.amount, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerExpChange(event) => { + self.amount = event.amount; + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_fish::PlayerFishEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerFish(PlayerFishEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + caught_uuid: self.caught_uuid.map(|uuid| Uuid { + value: uuid.to_string(), + }), + caught_type: self.caught_type.clone(), + hook_uuid: Some(Uuid { + value: self.hook_uuid.to_string(), + }), + state: self.state.clone(), + hand: self.hand.clone(), + exp_to_drop: self.exp_to_drop, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerFish(event) => { + self.caught_uuid = event + .caught_uuid + .and_then(|uuid| uuid::Uuid::from_str(&uuid.value).ok()); + if !event.caught_type.is_empty() { + self.caught_type = event.caught_type; + } + if let Some(uuid) = event.hook_uuid { + if let Ok(hook_uuid) = uuid::Uuid::from_str(&uuid.value) { + self.hook_uuid = hook_uuid; + } + } + if !event.state.is_empty() { + self.state = event.state; + } + if !event.hand.is_empty() { + self.hand = event.hand; + } + self.exp_to_drop = event.exp_to_drop; + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_interact_entity::PlayerInteractEntityEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerInteractEntity(PlayerInteractEntityEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + entity_uuid: Some(Uuid { + value: self.entity_uuid.to_string(), + }), + entity_type: self.entity_type.clone(), + hand: self.hand.clone(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerInteractEntity(event) => { + if let Some(uuid) = event.entity_uuid { + if let Ok(entity_uuid) = uuid::Uuid::from_str(&uuid.value) { + self.entity_uuid = entity_uuid; + } + } + if !event.entity_type.is_empty() { + self.entity_type = event.entity_type; + } + if !event.hand.is_empty() { + self.hand = event.hand; + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_interact_at_entity::PlayerInteractAtEntityEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerInteractAtEntity(PlayerInteractAtEntityEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + entity_uuid: Some(Uuid { + value: self.entity_uuid.to_string(), + }), + entity_type: self.entity_type.clone(), + hand: self.hand.clone(), + clicked_position: Some(Vec3 { + x: f64::from(self.clicked_position.x), + y: f64::from(self.clicked_position.y), + z: f64::from(self.clicked_position.z), + }), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerInteractAtEntity(event) => { + if let Some(uuid) = event.entity_uuid { + if let Ok(entity_uuid) = uuid::Uuid::from_str(&uuid.value) { + self.entity_uuid = entity_uuid; + } + } + if !event.entity_type.is_empty() { + self.entity_type = event.entity_type; + } + if !event.hand.is_empty() { + self.hand = event.hand; + } + if let Some(pos) = event.clicked_position { + self.clicked_position = Vector3::new(pos.x as f32, pos.y as f32, pos.z as f32); + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_item_held::PlayerItemHeldEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerItemHeld(PlayerItemHeldEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + previous_slot: self.previous_slot, + new_slot: self.new_slot, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerItemHeld(event) => { + self.previous_slot = event.previous_slot; + self.new_slot = event.new_slot; + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_item_damage::PlayerItemDamageEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerItemDamage(PlayerItemDamageEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + item_key: item_to_key(self.item_stack.item), + item_amount: i32::from(self.item_stack.item_count), + damage: self.damage, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerItemDamage(event) => { + self.damage = event.damage; + let mut key = if event.item_key.is_empty() { + None + } else { + Some(event.item_key) + }; + let mut amount = if event.item_amount > 0 { + Some(event.item_amount as u8) + } else { + None + }; + + if key.is_some() || amount.is_some() { + let fallback_key = item_to_key(self.item_stack.item); + let key = key.take().unwrap_or(fallback_key); + let count = amount.take().unwrap_or(self.item_stack.item_count); + self.item_stack = item_stack_from_key(&key, count); + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_item_break::PlayerItemBreakEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerItemBreak(PlayerItemBreakEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + item_key: item_to_key(self.item_stack.item), + item_amount: i32::from(self.item_stack.item_count), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerItemBreak(event) => { + let mut key = if event.item_key.is_empty() { + None + } else { + Some(event.item_key) + }; + let mut amount = if event.item_amount > 0 { + Some(event.item_amount as u8) + } else { + None + }; + + if key.is_some() || amount.is_some() { + let fallback_key = item_to_key(self.item_stack.item); + let key = key.take().unwrap_or(fallback_key); + let count = amount.take().unwrap_or(self.item_stack.item_count); + self.item_stack = item_stack_from_key(&key, count); + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_item_consume::PlayerItemConsumeEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let hand = match self.hand { + Hand::Left => "OFF_HAND", + Hand::Right => "HAND", + }; + JvmEventPayload { + event: Event { + data: Some(Data::PlayerItemConsume(PlayerItemConsumeEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + item_key: item_to_key(self.item_stack.item), + item_amount: i32::from(self.item_stack.item_count), + hand: hand.to_string(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerItemConsume(event) => { + if !event.hand.is_empty() { + self.hand = if event.hand == "OFF_HAND" { + Hand::Left + } else { + Hand::Right + }; + } + + let mut key = if event.item_key.is_empty() { + None + } else { + Some(event.item_key) + }; + let mut amount = if event.item_amount > 0 { + Some(event.item_amount as u8) + } else { + None + }; + + if key.is_some() || amount.is_some() { + let fallback_key = item_to_key(self.item_stack.item); + let key = key.take().unwrap_or(fallback_key); + let count = amount.take().unwrap_or(self.item_stack.item_count); + self.item_stack = item_stack_from_key(&key, count); + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_item_mend::PlayerItemMendEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerItemMend(PlayerItemMendEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + item_key: item_to_key(self.item_stack.item), + item_amount: i32::from(self.item_stack.item_count), + slot: equipment_slot_to_bukkit(&self.slot), + repair_amount: self.repair_amount, + orb_uuid: self.orb_uuid.map(|id| Uuid { value: id.to_string() }), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerItemMend(event) => { + self.repair_amount = event.repair_amount; + if !event.slot.is_empty() { + if let Some(slot) = equipment_slot_from_bukkit(&event.slot) { + self.slot = slot; + } + } + if let Some(uuid) = event.orb_uuid { + if let Ok(orb_uuid) = uuid::Uuid::from_str(&uuid.value) { + self.orb_uuid = Some(orb_uuid); + } + } + let mut key = if event.item_key.is_empty() { + None + } else { + Some(event.item_key) + }; + let mut amount = if event.item_amount > 0 { + Some(event.item_amount as u8) + } else { + None + }; + + if key.is_some() || amount.is_some() { + let fallback_key = item_to_key(self.item_stack.item); + let key = key.take().unwrap_or(fallback_key); + let count = amount.take().unwrap_or(self.item_stack.item_count); + self.item_stack = item_stack_from_key(&key, count); + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_level_change::PlayerLevelChangeEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerLevelChange(PlayerLevelChangeEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + old_level: self.old_level, + new_level: self.new_level, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerLevelChange(event) => { + self.old_level = event.old_level; + self.new_level = event.new_level; + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_kick::PlayerKickEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerKick(PlayerKickEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + reason: serde_json::to_string(&self.reason).unwrap_or_default(), + leave_message: serde_json::to_string(&self.leave_message).unwrap_or_default(), + cause: self.cause.clone(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerKick(event) => { + if !event.reason.is_empty() { + if let Ok(reason) = serde_json::from_str(&event.reason) { + self.reason = reason; + } + } + if !event.leave_message.is_empty() { + if let Ok(msg) = serde_json::from_str(&event.leave_message) { + self.leave_message = msg; + } + } + if !event.cause.is_empty() { + self.cause = event.cause; + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_toggle_sneak::PlayerToggleSneakEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerToggleSneak(PlayerToggleSneakEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + is_sneaking: self.is_sneaking, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerToggleSneak(event) => { + self.is_sneaking = event.is_sneaking; + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_toggle_sprint::PlayerToggleSprintEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerToggleSprint(PlayerToggleSprintEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + is_sprinting: self.is_sprinting, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerToggleSprint(event) => { + self.is_sprinting = event.is_sprinting; + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_toggle_flight::PlayerToggleFlightEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerToggleFlight(PlayerToggleFlightEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + is_flying: self.is_flying, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerToggleFlight(event) => { + self.is_flying = event.is_flying; + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_swap_hand_items::PlayerSwapHandItemsEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerSwapHandItems(PlayerSwapHandItemsEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + main_hand_item_key: item_to_key(self.main_hand_item.item), + main_hand_item_amount: i32::from(self.main_hand_item.item_count), + off_hand_item_key: item_to_key(self.off_hand_item.item), + off_hand_item_amount: i32::from(self.off_hand_item.item_count), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerSwapHandItems(event) => { + if !event.main_hand_item_key.is_empty() || event.main_hand_item_amount > 0 { + let key = if event.main_hand_item_key.is_empty() { + item_to_key(self.main_hand_item.item) + } else { + event.main_hand_item_key + }; + let count = if event.main_hand_item_amount > 0 { + event.main_hand_item_amount as u8 + } else { + self.main_hand_item.item_count + }; + self.main_hand_item = item_stack_from_key(&key, count); + } + if !event.off_hand_item_key.is_empty() || event.off_hand_item_amount > 0 { + let key = if event.off_hand_item_key.is_empty() { + item_to_key(self.off_hand_item.item) + } else { + event.off_hand_item_key + }; + let count = if event.off_hand_item_amount > 0 { + event.off_hand_item_amount as u8 + } else { + self.off_hand_item.item_count + }; + self.off_hand_item = item_stack_from_key(&key, count); + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_resource_pack_status::PlayerResourcePackStatusEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerResourcePackStatus(PlayerResourcePackStatusEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + pack_uuid: Some(Uuid { + value: self.pack_uuid.to_string(), + }), + status: self.status.clone(), + hash: self.pack_hash.clone(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerResourcePackStatus(event) => { + if let Some(uuid) = event.pack_uuid { + if let Ok(pack_uuid) = uuid::Uuid::from_str(&uuid.value) { + self.pack_uuid = pack_uuid; + } + } + if !event.status.is_empty() { + self.status = event.status; + } + if !event.hash.is_empty() { + self.pack_hash = event.hash; + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_respawn::PlayerRespawnEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let yaw = self.player.living_entity.entity.yaw.load(); + let pitch = self.player.living_entity.entity.pitch.load(); + JvmEventPayload { + event: Event { + data: Some(Data::PlayerRespawn(PlayerRespawnEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + respawn_location: Some(build_location( + self.world_uuid, + &Vector3::new( + self.respawn_position.x, + self.respawn_position.y, + self.respawn_position.z, + ), + yaw, + pitch, + )), + is_bed_spawn: self.is_bed_spawn, + is_anchor_spawn: self.is_anchor_spawn, + is_missing_respawn_block: self.is_missing_respawn_block, + respawn_reason: self.reason.clone(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerRespawn(event) => { + if let Some(loc) = event.respawn_location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.respawn_position = pos; + } + if let Some(world) = loc.world.and_then(|w| w.uuid) { + if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { + self.world_uuid = uuid; + } + } + } + self.is_bed_spawn = event.is_bed_spawn; + self.is_anchor_spawn = event.is_anchor_spawn; + self.is_missing_respawn_block = event.is_missing_respawn_block; + if !event.respawn_reason.is_empty() { + self.reason = event.respawn_reason; + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_pickup_arrow::PlayerPickupArrowEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerPickupArrow(PlayerPickupArrowEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + arrow_uuid: Some(Uuid { + value: self.arrow_uuid.to_string(), + }), + item_uuid: Some(Uuid { + value: self.item_uuid.to_string(), + }), + item_key: item_to_key(self.item_stack.item), + item_amount: self.item_stack.item_count as i32, + remaining: self.remaining, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerPickupArrow(event) => { + if let Some(uuid) = event.arrow_uuid { + if let Ok(arrow_uuid) = uuid::Uuid::from_str(&uuid.value) { + self.arrow_uuid = arrow_uuid; + } + } + if let Some(uuid) = event.item_uuid { + if let Ok(item_uuid) = uuid::Uuid::from_str(&uuid.value) { + self.item_uuid = item_uuid; + } + } + if !event.item_key.is_empty() || event.item_amount > 0 { + let key = if event.item_key.is_empty() { + item_to_key(self.item_stack.item) + } else { + event.item_key + }; + let count = if event.item_amount > 0 { + event.item_amount as u8 + } else { + self.item_stack.item_count + }; + self.item_stack = item_stack_from_key(&key, count); + } + self.remaining = event.remaining; + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_portal::PlayerPortalEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let yaw = self.player.living_entity.entity.yaw.load(); + let pitch = self.player.living_entity.entity.pitch.load(); + JvmEventPayload { + event: Event { + data: Some(Data::PlayerPortal(PlayerPortalEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + from: Some(build_location( + self.from_world_uuid, + &self.from_position, + yaw, + pitch, + )), + to: Some(build_location( + self.to_world_uuid, + &self.to_position, + yaw, + pitch, + )), + cause: self.cause.clone(), + search_radius: self.search_radius, + can_create_portal: self.can_create_portal, + creation_radius: self.creation_radius, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerPortal(event) => { + if let Some(from) = event.from { + if let Some(pos) = location_to_vec3(from.clone()) { + self.from_position = pos; + } + if let Some(world) = from.world.and_then(|w| w.uuid) { + if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { + self.from_world_uuid = uuid; + } + } + } + if let Some(to) = event.to { + if let Some(pos) = location_to_vec3(to.clone()) { + self.to_position = pos; + } + if let Some(world) = to.world.and_then(|w| w.uuid) { + if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { + self.to_world_uuid = uuid; + } + } + } + if !event.cause.is_empty() { + self.cause = event.cause; + } + self.search_radius = event.search_radius; + self.can_create_portal = event.can_create_portal; + self.creation_radius = event.creation_radius; + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_recipe_discover::PlayerRecipeDiscoverEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerRecipeDiscover(PlayerRecipeDiscoverEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + recipe_key: self.recipe_key.clone(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerRecipeDiscover(event) => { + if !event.recipe_key.is_empty() { + self.recipe_key = event.recipe_key; + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_riptide::PlayerRiptideEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerRiptide(PlayerRiptideEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + item_key: item_to_key(self.item_stack.item), + item_amount: self.item_stack.item_count as i32, + velocity: Some(Vec3 { + x: self.velocity.x, + y: self.velocity.y, + z: self.velocity.z, + }), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerRiptide(event) => { + if !event.item_key.is_empty() || event.item_amount > 0 { + let key = if event.item_key.is_empty() { + item_to_key(self.item_stack.item) + } else { + event.item_key + }; + let count = if event.item_amount > 0 { + event.item_amount as u8 + } else { + self.item_stack.item_count + }; + self.item_stack = item_stack_from_key(&key, count); + } + if let Some(velocity) = event.velocity { + self.velocity = Vector3::new(velocity.x, velocity.y, velocity.z); + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_shear_entity::PlayerShearEntityEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerShearEntity(PlayerShearEntityEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + entity_uuid: Some(Uuid { + value: self.entity_uuid.to_string(), + }), + entity_type: self.entity_type.clone(), + item_key: item_to_key(self.item_stack.item), + item_amount: self.item_stack.item_count as i32, + hand: self.hand.clone(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerShearEntity(event) => { + if let Some(uuid) = event.entity_uuid { + if let Ok(entity_uuid) = uuid::Uuid::from_str(&uuid.value) { + self.entity_uuid = entity_uuid; + } + } + if !event.entity_type.is_empty() { + self.entity_type = event.entity_type; + } + if !event.item_key.is_empty() || event.item_amount > 0 { + let key = if event.item_key.is_empty() { + item_to_key(self.item_stack.item) + } else { + event.item_key + }; + let count = if event.item_amount > 0 { + event.item_amount as u8 + } else { + self.item_stack.item_count + }; + self.item_stack = item_stack_from_key(&key, count); + } + if !event.hand.is_empty() { + self.hand = event.hand; + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_spawn_location::PlayerSpawnLocationEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let yaw = self.player.living_entity.entity.yaw.load(); + let pitch = self.player.living_entity.entity.pitch.load(); + JvmEventPayload { + event: Event { + data: Some(Data::PlayerSpawnLocation(PlayerSpawnLocationEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + spawn_location: Some(build_location( + self.world_uuid, + &self.spawn_position, + yaw, + pitch, + )), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerSpawnLocation(event) => { + if let Some(loc) = event.spawn_location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.spawn_position = pos; + } + if let Some(world) = loc.world.and_then(|w| w.uuid) { + if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { + self.world_uuid = uuid; + } + } + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_statistic_increment::PlayerStatisticIncrementEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerStatisticIncrement(PlayerStatisticIncrementEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + statistic: self.statistic.clone(), + initial_value: self.initial_value, + new_value: self.new_value, + entity_type: self.entity_type.clone(), + material_key: self.material_key.clone(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerStatisticIncrement(event) => { + if !event.statistic.is_empty() { + self.statistic = event.statistic; + } + self.initial_value = event.initial_value; + self.new_value = event.new_value; + if !event.entity_type.is_empty() { + self.entity_type = event.entity_type; + } + if !event.material_key.is_empty() { + self.material_key = event.material_key; + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_velocity::PlayerVelocityEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerVelocity(PlayerVelocityEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + velocity: Some(Vec3 { + x: self.velocity.x, + y: self.velocity.y, + z: self.velocity.z, + }), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerVelocity(event) => { + if let Some(velocity) = event.velocity { + self.velocity = Vector3::new(velocity.x, velocity.y, velocity.z); + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_harvest_block::PlayerHarvestBlockEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let yaw = self.player.living_entity.entity.yaw.load(); + let pitch = self.player.living_entity.entity.pitch.load(); + JvmEventPayload { + event: Event { + data: Some(Data::PlayerHarvestBlock(PlayerHarvestBlockEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + block_location: Some(build_location( + self.player.world().uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + yaw, + pitch, + )), + block_key: self.block_key.clone(), + item_key: item_to_key(self.item_stack.item), + item_amount: self.item_stack.item_count as i32, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerHarvestBlock(event) => { + if let Some(loc) = event.block_location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + if let Some(world) = loc.world.and_then(|w| w.uuid) { + if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { + if uuid != self.player.world().uuid { + // World changes are not supported for harvest event. + } + } + } + } + if !event.block_key.is_empty() { + self.block_key = event.block_key; + } + if !event.item_key.is_empty() || event.item_amount > 0 { + let key = if event.item_key.is_empty() { + item_to_key(self.item_stack.item) + } else { + event.item_key + }; + let count = if event.item_amount > 0 { + event.item_amount as u8 + } else { + self.item_stack.item_count + }; + self.item_stack = item_stack_from_key(&key, count); + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::player::player_interact_event::PlayerInteractEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let world_uuid = self.player.world().uuid; + let yaw = self.player.living_entity.entity.yaw.load(); + let pitch = self.player.living_entity.entity.pitch.load(); + + let clicked = self.clicked_pos.map(|pos| { + build_location( + world_uuid, + &Vector3::new( + f64::from(pos.0.x), + f64::from(pos.0.y), + f64::from(pos.0.z), + ), + yaw, + pitch, + ) + }); + + JvmEventPayload { + event: Event { + data: Some(Data::PlayerInteract(PlayerInteractEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + action: interact_action_to_bukkit(&self.action), + block_key: block_to_key(self.block), + clicked, + item_key: self.item_key.clone(), + block_face: block_face_to_bukkit(self.face), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, _data: Data) -> Option<()> { + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::block::block_break::BlockBreakEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let (player_uuid, world_uuid) = if let Some(player) = &self.player { + (player.gameprofile.id.to_string(), Some(player.world().uuid)) + } else { + ("00000000-0000-0000-0000-000000000000".to_string(), None) + }; + + let location = world_uuid.map(|world_uuid| { + build_location( + world_uuid, + &Vector3::new( + f64::from(self.block_position.0.x), + f64::from(self.block_position.0.y), + f64::from(self.block_position.0.z), + ), + 0.0, + 0.0, + ) + }); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockBreak(BlockBreakEvent { + player_uuid: Some(Uuid { value: player_uuid }), + block_key: block_to_key(self.block), + location, + exp: self.exp, + drop: self.drop, + })), + }, + context: EventContext { + server, + player: self.player.clone(), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::BlockBreak(event) => { + self.exp = event.exp; + self.drop = event.drop; + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::block::block_damage::BlockDamageEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let player_uuid = self.player.gameprofile.id.to_string(); + let world_uuid = self.player.world().uuid; + let location = build_location( + world_uuid, + &Vector3::new( + f64::from(self.block_position.0.x), + f64::from(self.block_position.0.y), + f64::from(self.block_position.0.z), + ), + 0.0, + 0.0, + ); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockDamage(BlockDamageEvent { + player_uuid: Some(Uuid { value: player_uuid }), + block_key: block_to_key(self.block), + location: Some(location), + item_key: item_to_key(self.item_stack.item), + insta_break: self.insta_break, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::BlockDamage(event) => { + self.insta_break = event.insta_break; + if !event.item_key.is_empty() { + let count = self.item_stack.item_count; + self.item_stack = item_stack_from_key(&event.item_key, count); + } + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::block::block_damage_abort::BlockDamageAbortEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let player_uuid = self.player.gameprofile.id.to_string(); + let world_uuid = self.player.world().uuid; + let location = build_location( + world_uuid, + &Vector3::new( + f64::from(self.block_position.0.x), + f64::from(self.block_position.0.y), + f64::from(self.block_position.0.z), + ), + 0.0, + 0.0, + ); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockDamageAbort(BlockDamageAbortEvent { + player_uuid: Some(Uuid { value: player_uuid }), + block_key: block_to_key(self.block), + location: Some(location), + item_key: item_to_key(self.item_stack.item), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::BlockDamageAbort(event) => { + if !event.item_key.is_empty() { + let count = self.item_stack.item_count; + self.item_stack = item_stack_from_key(&event.item_key, count); + } + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::block::block_dispense::BlockDispenseEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let world_uuid = server + .worlds + .load() + .first() + .map(|world| world.uuid) + .unwrap_or_default(); + let location = build_location( + world_uuid, + &Vector3::new( + f64::from(self.block_position.0.x), + f64::from(self.block_position.0.y), + f64::from(self.block_position.0.z), + ), + 0.0, + 0.0, + ); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockDispense(BlockDispenseEvent { + block_key: block_to_key(self.block), + location: Some(location), + item_key: item_to_key(self.item_stack.item), + item_amount: i32::from(self.item_stack.item_count), + velocity: Some(Vec3 { + x: self.velocity.x, + y: self.velocity.y, + z: self.velocity.z, + }), + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::BlockDispense(event) => { + if !event.item_key.is_empty() || event.item_amount > 0 { + let key = if event.item_key.is_empty() { + item_to_key(self.item_stack.item) + } else { + event.item_key + }; + let count = if event.item_amount > 0 { + event.item_amount as u8 + } else { + self.item_stack.item_count + }; + self.item_stack = item_stack_from_key(&key, count); + } + if let Some(vel) = event.velocity { + self.velocity = Vector3::new(vel.x, vel.y, vel.z); + } + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::block::block_drop_item::BlockDropItemEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let world_uuid = self.player.world().uuid; + let location = build_location( + world_uuid, + &Vector3::new( + f64::from(self.block_position.0.x), + f64::from(self.block_position.0.y), + f64::from(self.block_position.0.z), + ), + 0.0, + 0.0, + ); + let items = self + .items + .iter() + .map(|item| BlockDropItemEntry { + item_key: item_to_key(item.item), + item_amount: i32::from(item.item_count), + }) + .collect(); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockDropItem(BlockDropItemEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + block_key: block_to_key(self.block), + location: Some(location), + items, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::BlockDropItem(event) => { + if !event.items.is_empty() { + let mut items = Vec::with_capacity(event.items.len()); + for entry in event.items { + if entry.item_key.is_empty() && entry.item_amount <= 0 { + continue; + } + let key = if entry.item_key.is_empty() { + "minecraft:air" + } else { + entry.item_key.as_str() + }; + let stack = item_stack_from_key(key, entry.item_amount.clamp(0, u8::MAX as i32) as u8); + if !stack.is_empty() { + items.push(stack); + } + } + self.items = items; + } + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::block::block_explode::BlockExplodeEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.block_position.0.x), + f64::from(self.block_position.0.y), + f64::from(self.block_position.0.z), + ), + 0.0, + 0.0, + ); + let blocks = self + .blocks + .iter() + .map(|pos| { + let loc = build_location( + self.world_uuid, + &Vector3::new(f64::from(pos.0.x), f64::from(pos.0.y), f64::from(pos.0.z)), + 0.0, + 0.0, + ); + BlockExplodeBlockEntry { + block_key: String::new(), + location: Some(loc), + } + }) + .collect(); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockExplode(BlockExplodeEvent { + block_key: block_to_key(self.block), + location: Some(location), + yield_: self.yield_rate, + blocks, + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::BlockExplode(event) => { + self.yield_rate = event.yield_; + if !event.blocks.is_empty() { + let mut blocks = Vec::with_capacity(event.blocks.len()); + for entry in event.blocks { + if let Some(loc) = entry.location + && let Some(pos) = location_to_vec3(loc.clone()) + { + blocks.push(pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + )); + } + } + self.blocks = blocks; + } + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::block::block_fade::BlockFadeEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockFade(BlockFadeEvent { + block_key: block_to_key(self.block), + new_block_key: block_to_key(self.new_block), + location: Some(location), + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::BlockFade(event) => { + if !event.new_block_key.is_empty() { + if let Some(block) = Block::from_name(&event.new_block_key) { + self.new_block = block; + } + } + if let Some(loc) = event.location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + } + if !event.block_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_key) { + self.block = block; + } + } + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::block::block_fertilize::BlockFertilizeEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let world_uuid = self.player.world().uuid; + let location = build_location( + world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + let blocks = self + .blocks + .iter() + .map(|pos| { + let loc = build_location( + world_uuid, + &Vector3::new(f64::from(pos.0.x), f64::from(pos.0.y), f64::from(pos.0.z)), + 0.0, + 0.0, + ); + BlockFertilizeBlockEntry { + block_key: block_to_key(self.block), + location: Some(loc), + } + }) + .collect(); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockFertilize(BlockFertilizeEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + block_key: block_to_key(self.block), + location: Some(location), + blocks, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::BlockFertilize(event) => { + if !event.blocks.is_empty() { + let mut blocks = Vec::with_capacity(event.blocks.len()); + for entry in event.blocks { + if let Some(loc) = entry.location + && let Some(pos) = location_to_vec3(loc.clone()) + { + blocks.push(pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + )); + } + } + self.blocks = blocks; + } + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::block::block_form::BlockFormEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockForm(BlockFormEvent { + block_key: block_to_key(self.old_block), + new_block_key: block_to_key(self.new_block), + location: Some(location), + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::BlockForm(event) => { + if !event.new_block_key.is_empty() { + if let Some(block) = Block::from_name(&event.new_block_key) { + self.new_block = block; + } + } + if let Some(loc) = event.location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + } + if !event.block_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_key) { + self.old_block = block; + } + } + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::block::block_from_to::BlockFromToEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + let to_location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.to_pos.0.x), + f64::from(self.to_pos.0.y), + f64::from(self.to_pos.0.z), + ), + 0.0, + 0.0, + ); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockFromTo(BlockFromToEvent { + block_key: block_to_key(self.block), + location: Some(location), + to_block_key: block_to_key(self.to_block), + to_location: Some(to_location), + face: block_face_to_bukkit(Some(self.face)), + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::BlockFromTo(event) => { + if !event.to_block_key.is_empty() { + if let Some(block) = Block::from_name(&event.to_block_key) { + self.to_block = block; + } + } + if let Some(loc) = event.to_location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.to_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + } + if let Some(face) = bukkit_block_face_from_string(&event.face) { + self.face = face; + } + if !event.block_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_key) { + self.block = block; + } + } + if let Some(loc) = event.location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + } + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::block::block_grow::BlockGrowEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockGrow(BlockGrowEvent { + block_key: block_to_key(self.block), + new_block_key: block_to_key(self.new_block), + location: Some(location), + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::BlockGrow(event) => { + if !event.new_block_key.is_empty() { + if let Some(block) = Block::from_name(&event.new_block_key) { + self.new_block = block; + } + } + if let Some(loc) = event.location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + } + if !event.block_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_key) { + self.block = block; + } + } + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::block::block_piston_extend::BlockPistonExtendEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + let blocks = self + .blocks + .iter() + .map(|pos| { + let loc = build_location( + self.world_uuid, + &Vector3::new(f64::from(pos.0.x), f64::from(pos.0.y), f64::from(pos.0.z)), + 0.0, + 0.0, + ); + BlockPistonBlockEntry { + block_key: String::new(), + location: Some(loc), + } + }) + .collect(); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockPistonExtend(BlockPistonExtendEvent { + block_key: block_to_key(self.block), + location: Some(location), + direction: block_face_to_bukkit(Some(self.direction)), + length: self.length, + blocks, + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::BlockPistonExtend(event) => { + self.length = event.length; + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::block::block_piston_retract::BlockPistonRetractEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + let blocks = self + .blocks + .iter() + .map(|pos| { + let loc = build_location( + self.world_uuid, + &Vector3::new(f64::from(pos.0.x), f64::from(pos.0.y), f64::from(pos.0.z)), + 0.0, + 0.0, + ); + BlockPistonBlockEntry { + block_key: String::new(), + location: Some(loc), + } + }) + .collect(); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockPistonRetract(BlockPistonRetractEvent { + block_key: block_to_key(self.block), + location: Some(location), + direction: block_face_to_bukkit(Some(self.direction)), + length: self.length, + blocks, + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::BlockPistonRetract(event) => { + self.length = event.length; + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::block::block_redstone::BlockRedstoneEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let world_uuid = server + .worlds + .load() + .first() + .map(|world| world.uuid) + .unwrap_or_default(); + let location = build_location( + world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockRedstone(BlockRedstoneEvent { + block_key: block_to_key(self.block), + location: Some(location), + old_current: self.old_current, + new_current: self.new_current, + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::BlockRedstone(event) => { + self.new_current = event.new_current; + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::block::block_multi_place::BlockMultiPlaceEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let world_uuid = self.player.world().uuid; + let origin = self + .positions + .first() + .copied() + .unwrap_or_else(|| self.player.position().to_block_pos()); + let location = build_location( + world_uuid, + &Vector3::new( + f64::from(origin.0.x), + f64::from(origin.0.y), + f64::from(origin.0.z), + ), + 0.0, + 0.0, + ); + let blocks = self + .positions + .iter() + .map(|pos| { + let loc = build_location( + world_uuid, + &Vector3::new(f64::from(pos.0.x), f64::from(pos.0.y), f64::from(pos.0.z)), + 0.0, + 0.0, + ); + BlockMultiPlaceBlockEntry { + block_key: block_to_key(self.block_placed), + location: Some(loc), + } + }) + .collect(); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockMultiPlace(BlockMultiPlaceEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + block_key: block_to_key(self.block_placed), + location: Some(location), + blocks, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, _data: Data) -> Option<()> { + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::block::block_physics::BlockPhysicsEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + let source_location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.source_pos.0.x), + f64::from(self.source_pos.0.y), + f64::from(self.source_pos.0.z), + ), + 0.0, + 0.0, + ); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockPhysics(BlockPhysicsEvent { + block_key: block_to_key(self.block), + location: Some(location), + source_block_key: block_to_key(self.source_block), + source_location: Some(source_location), + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, _data: Data) -> Option<()> { + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::block::note_play::NotePlayEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + + JvmEventPayload { + event: Event { + data: Some(Data::NotePlay(NotePlayEvent { + block_key: block_to_key(self.block), + location: Some(location), + instrument: instrument_to_bukkit(self.instrument), + note: i32::from(self.note), + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::NotePlay(event) => { + if !event.block_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_key) { + self.block = block; + } + } + if let Some(loc) = event.location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + if let Some(world) = loc.world.and_then(|w| w.uuid) { + if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { + self.world_uuid = uuid; + } + } + } + if !event.instrument.is_empty() { + if let Some(instrument) = instrument_from_bukkit(&event.instrument) { + self.instrument = instrument; + } + } + self.note = event.note.clamp(0, 24) as u8; + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::block::sign_change::SignChangeEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let world_uuid = self.player.world().uuid; + let location = build_location( + world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + + JvmEventPayload { + event: Event { + data: Some(Data::SignChange(SignChangeEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + block_key: block_to_key(self.block), + location: Some(location), + lines: self.lines.clone(), + is_front_text: self.is_front_text, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { + match data { + Data::SignChange(event) => { + if let Some(uuid) = event.player_uuid { + if let Ok(uuid) = uuid::Uuid::from_str(&uuid.value) { + if let Some(player) = server.get_player_by_uuid(uuid) { + self.player = player; + } + } + } + if !event.block_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_key) { + self.block = block; + } + } + if let Some(loc) = event.location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + } + if !event.lines.is_empty() { + self.lines = event.lines; + } + self.is_front_text = event.is_front_text; + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::block::tnt_prime::TNTPrimeEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + let player_uuid = self.player.as_ref().map(|player| Uuid { + value: player.gameprofile.id.to_string(), + }); + + JvmEventPayload { + event: Event { + data: Some(Data::TntPrime(TntPrimeEvent { + player_uuid, + block_key: block_to_key(self.block), + location: Some(location), + cause: self.cause.clone(), + })), + }, + context: EventContext { + server, + player: self.player.clone(), + }, + } + } + + fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { + match data { + Data::TntPrime(event) => { + if let Some(uuid) = event.player_uuid { + if let Ok(uuid) = uuid::Uuid::from_str(&uuid.value) { + self.player = server.get_player_by_uuid(uuid); + } + } else { + self.player = None; + } + if !event.block_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_key) { + self.block = block; + } + } + if let Some(loc) = event.location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + if let Some(world) = loc.world.and_then(|w| w.uuid) { + if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { + self.world_uuid = uuid; + } + } + } + if !event.cause.is_empty() { + self.cause = event.cause; + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::block::moisture_change::MoistureChangeEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + let new_block_key = Block::from_state_id(self.new_state_id) + .map(block_to_key) + .unwrap_or_default(); + + JvmEventPayload { + event: Event { + data: Some(Data::MoistureChange(MoistureChangeEvent { + block_key: block_to_key(self.block), + location: Some(location), + new_block_key, + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::MoistureChange(event) => { + if !event.block_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_key) { + self.block = block; + } + } + if let Some(loc) = event.location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + if let Some(world) = loc.world.and_then(|w| w.uuid) { + if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { + self.world_uuid = uuid; + } + } + } + if !event.new_block_key.is_empty() { + if let Some(block) = Block::from_name(&event.new_block_key) { + self.new_state_id = block.default_state.id; + } + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::block::sponge_absorb::SpongeAbsorbEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + let blocks = self + .blocks + .iter() + .map(|pos| { + let loc = build_location( + self.world_uuid, + &Vector3::new(f64::from(pos.0.x), f64::from(pos.0.y), f64::from(pos.0.z)), + 0.0, + 0.0, + ); + SpongeAbsorbBlockEntry { + block_key: block_to_key(&Block::WATER), + location: Some(loc), + } + }) + .collect(); + + JvmEventPayload { + event: Event { + data: Some(Data::SpongeAbsorb(SpongeAbsorbEvent { + block_key: block_to_key(self.block), + location: Some(location), + blocks, + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::SpongeAbsorb(event) => { + if !event.block_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_key) { + self.block = block; + } + } + if let Some(loc) = event.location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + if let Some(world) = loc.world.and_then(|w| w.uuid) { + if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { + self.world_uuid = uuid; + } + } + } + if !event.blocks.is_empty() { + let mut blocks = Vec::with_capacity(event.blocks.len()); + for entry in event.blocks { + if let Some(loc) = entry.location.and_then(location_to_vec3) { + blocks.push(pumpkin_util::math::position::BlockPos::new( + loc.x.floor() as i32, + loc.y.floor() as i32, + loc.z.floor() as i32, + )); + } + } + self.blocks = blocks; + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::block::fluid_level_change::FluidLevelChangeEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + let new_block_key = Block::from_state_id(self.new_state_id) + .map(block_to_key) + .unwrap_or_default(); + + JvmEventPayload { + event: Event { + data: Some(Data::FluidLevelChange(FluidLevelChangeEvent { + block_key: block_to_key(self.block), + location: Some(location), + new_block_key, + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::FluidLevelChange(event) => { + if !event.block_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_key) { + self.block = block; + } + } + if let Some(loc) = event.location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + if let Some(world) = loc.world.and_then(|w| w.uuid) { + if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { + self.world_uuid = uuid; + } + } + } + if !event.new_block_key.is_empty() { + if let Some(block) = Block::from_name(&event.new_block_key) { + self.new_state_id = block.default_state.id; + } + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::world::spawn_change::SpawnChangeEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let world_uuid = self.world.uuid; + let previous_location = build_location( + world_uuid, + &Vector3::new( + f64::from(self.previous_position.0.x), + f64::from(self.previous_position.0.y), + f64::from(self.previous_position.0.z), + ), + 0.0, + 0.0, + ); + let location = build_location( + world_uuid, + &Vector3::new( + f64::from(self.new_position.0.x), + f64::from(self.new_position.0.y), + f64::from(self.new_position.0.z), + ), + 0.0, + 0.0, + ); + + JvmEventPayload { + event: Event { + data: Some(Data::SpawnChange(SpawnChangeEvent { + previous_location: Some(previous_location), + location: Some(location), + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::SpawnChange(event) => { + if let Some(loc) = event.location.and_then(location_to_vec3) { + self.new_position = pumpkin_util::math::position::BlockPos::new( + loc.x.floor() as i32, + loc.y.floor() as i32, + loc.z.floor() as i32, + ); + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::server::server_list_ping::ServerListPingEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::ServerListPing(ServerListPingEvent { + motd: self.motd.clone(), + max_players: self.max_players as i32, + online_players: self.num_players as i32, + favicon: self.favicon.clone().unwrap_or_default(), + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::ServerListPing(event) => { + if !event.motd.is_empty() { + self.motd = event.motd; + } + if event.max_players >= 0 { + self.max_players = event.max_players as u32; + } + if event.online_players >= 0 { + self.num_players = event.online_players as u32; + } + if !event.favicon.is_empty() { + self.favicon = Some(event.favicon); + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::server::plugin_enable::PluginEnableEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PluginEnable(PluginEnableEvent { + plugin_name: self.plugin_name.clone(), + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PluginEnable(event) => { + if !event.plugin_name.is_empty() { + self.plugin_name = event.plugin_name; + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::server::plugin_disable::PluginDisableEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PluginDisable(PluginDisableEvent { + plugin_name: self.plugin_name.clone(), + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PluginDisable(event) => { + if !event.plugin_name.is_empty() { + self.plugin_name = event.plugin_name; + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::server::service_register::ServiceRegisterEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::ServiceRegister(ServiceRegisterEvent { + plugin_name: self.plugin_name.clone(), + service_name: self.service_name.clone(), + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::ServiceRegister(event) => { + if !event.plugin_name.is_empty() { + self.plugin_name = event.plugin_name; + } + if !event.service_name.is_empty() { + self.service_name = event.service_name; + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::server::service_unregister::ServiceUnregisterEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::ServiceUnregister(ServiceUnregisterEvent { + plugin_name: self.plugin_name.clone(), + service_name: self.service_name.clone(), + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::ServiceUnregister(event) => { + if !event.plugin_name.is_empty() { + self.plugin_name = event.plugin_name; + } + if !event.service_name.is_empty() { + self.service_name = event.service_name; + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::block::block_place::BlockPlaceEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let player_uuid = self.player.gameprofile.id.to_string(); + let world_uuid = self.player.world().uuid; + let location = build_location( + world_uuid, + &Vector3::new( + f64::from(self.position.0.x), + f64::from(self.position.0.y), + f64::from(self.position.0.z), + ), + 0.0, + 0.0, + ); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockPlace(BlockPlaceEvent { + player_uuid: Some(Uuid { value: player_uuid }), + block_key: block_to_key(self.block_placed), + block_against_key: block_to_key(self.block_placed_against), + location: Some(location), + can_build: self.can_build, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::BlockPlace(event) => { + self.can_build = event.can_build; + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::block::block_can_build::BlockCanBuildEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let player_uuid = self.player.gameprofile.id.to_string(); + let world_uuid = self.player.world().uuid; + let location = build_location( + world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockCanBuild(BlockCanBuildEvent { + player_uuid: Some(Uuid { value: player_uuid }), + block_key: block_to_key(self.block_to_build), + block_against_key: block_to_key(self.block), + location: Some(location), + can_build: self.buildable, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::BlockCanBuild(event) => { + self.buildable = event.can_build; + if let Some(loc) = event.location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + } + if !event.block_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_key) { + self.block_to_build = block; + } + } + if !event.block_against_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_against_key) { + self.block = block; + } + } + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::block::block_burn::BlockBurnEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockBurn(BlockBurnEvent { + block_key: block_to_key(self.block), + igniting_block_key: block_to_key(self.igniting_block), + location: Some(location), + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, _data: Data) -> Option<()> { + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::block::block_ignite::BlockIgniteEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockIgnite(BlockIgniteEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + block_key: block_to_key(self.block), + igniting_block_key: block_to_key(self.igniting_block), + location: Some(location), + cause: self.cause.clone(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::BlockIgnite(event) => { + if !event.block_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_key) { + self.block = block; + } + } + if !event.igniting_block_key.is_empty() { + if let Some(block) = Block::from_name(&event.igniting_block_key) { + self.igniting_block = block; + } + } + if let Some(loc) = event.location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + if let Some(world) = loc.world.and_then(|w| w.uuid) { + if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { + self.world_uuid = uuid; + } + } + } + if !event.cause.is_empty() { + self.cause = event.cause; + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::block::block_spread::BlockSpreadEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let source_location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.source_pos.0.x), + f64::from(self.source_pos.0.y), + f64::from(self.source_pos.0.z), + ), + 0.0, + 0.0, + ); + let location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockSpread(BlockSpreadEvent { + source_block_key: block_to_key(self.source_block), + source_location: Some(source_location), + block_key: block_to_key(self.block), + location: Some(location), + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::BlockSpread(event) => { + if !event.source_block_key.is_empty() { + if let Some(block) = Block::from_name(&event.source_block_key) { + self.source_block = block; + } + } + if !event.block_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_key) { + self.block = block; + } + } + if let Some(loc) = event.source_location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.source_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + if let Some(world) = loc.world.and_then(|w| w.uuid) { + if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { + self.world_uuid = uuid; + } + } + } + if let Some(loc) = event.location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + if let Some(world) = loc.world.and_then(|w| w.uuid) { + if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { + self.world_uuid = uuid; + } + } + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::entity::entity_spawn::EntitySpawnEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::EntitySpawn(EntitySpawnEvent { + entity_uuid: Some(Uuid { + value: self.entity_uuid.to_string(), + }), + entity_type: self.entity_type.id.to_string(), + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, _data: Data) -> Option<()> { + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::entity::entity_damage::EntityDamageEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::EntityDamage(EntityDamageEvent { + entity_uuid: Some(Uuid { + value: self.entity_uuid.to_string(), + }), + damage: self.damage, + damage_type: self.damage_type.message_id.to_string(), + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::EntityDamage(event) => { + self.damage = event.damage; + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::entity::entity_death::EntityDeathEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::EntityDeath(EntityDeathEvent { + entity_uuid: Some(Uuid { + value: self.entity_uuid.to_string(), + }), + damage_type: self.damage_type.message_id.to_string(), + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, _data: Data) -> Option<()> { + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::server::server_command::ServerCommandEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::ServerCommand(ServerCommandEvent { + command: self.command.clone(), + })), + }, + context: EventContext { + server, + player: None, + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::ServerCommand(event) => { + self.command = event.command; + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::server::server_broadcast::ServerBroadcastEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::ServerBroadcast(ServerBroadcastEvent { + message: serde_json::to_string(&self.message).unwrap(), + sender: serde_json::to_string(&self.sender).unwrap(), + })), + }, + context: EventContext { + server, + player: None, + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::ServerBroadcast(event) => { + self.message = serde_json::from_str(&event.message).unwrap_or_else(|_| { + TextComponent::from_legacy_string(&event.message) + }); + self.sender = serde_json::from_str(&event.sender).unwrap_or_else(|_| { + TextComponent::from_legacy_string(&event.sender) + }); + } + _ => {} + } + + Some(()) + } +} + +fn build_location(world_uuid: uuid::Uuid, position: &Vector3, yaw: f32, pitch: f32) -> Location { + Location { + world: Some(World { + uuid: Some(Uuid { + value: world_uuid.to_string(), + }), + }), + position: Some(Vec3 { + x: position.x, + y: position.y, + z: position.z, + }), + yaw, + pitch, + } +} + +fn location_to_vec3(location: Location) -> Option> { + let pos = location.position?; + Some(Vector3::new(pos.x, pos.y, pos.z)) +} + +fn block_to_key(block: &Block) -> String { + format!("minecraft:{}", block.name) +} + +fn item_to_key(item: &Item) -> String { + format!("minecraft:{}", item.registry_key) +} + +fn item_stack_from_key(key: &str, amount: u8) -> ItemStack { + let trimmed = key.strip_prefix("minecraft:").unwrap_or(key); + let item = Item::from_registry_key(trimmed).unwrap_or(&Item::AIR); + ItemStack::new(amount, item) +} + +fn equipment_slot_to_bukkit(slot: &EquipmentSlot) -> String { + match slot { + EquipmentSlot::MainHand(_) => "HAND".to_string(), + EquipmentSlot::OffHand(_) => "OFF_HAND".to_string(), + EquipmentSlot::Feet(_) => "FEET".to_string(), + EquipmentSlot::Legs(_) => "LEGS".to_string(), + EquipmentSlot::Chest(_) => "CHEST".to_string(), + EquipmentSlot::Head(_) => "HEAD".to_string(), + EquipmentSlot::Body(_) => "BODY".to_string(), + EquipmentSlot::Saddle(_) => "SADDLE".to_string(), + } +} + +fn equipment_slot_from_bukkit(slot: &str) -> Option { + match slot { + "HAND" => Some(EquipmentSlot::MAIN_HAND), + "OFF_HAND" => Some(EquipmentSlot::OFF_HAND), + "FEET" => Some(EquipmentSlot::FEET), + "LEGS" => Some(EquipmentSlot::LEGS), + "CHEST" => Some(EquipmentSlot::CHEST), + "HEAD" => Some(EquipmentSlot::HEAD), + "BODY" => Some(EquipmentSlot::BODY), + "SADDLE" => Some(EquipmentSlot::SADDLE), + _ => None, + } +} + +fn interact_action_to_bukkit(action: &pumpkin::plugin::player::player_interact_event::InteractAction) -> String { + match action { + pumpkin::plugin::player::player_interact_event::InteractAction::LeftClickBlock => { + "LEFT_CLICK_BLOCK".to_string() + } + pumpkin::plugin::player::player_interact_event::InteractAction::LeftClickAir => { + "LEFT_CLICK_AIR".to_string() + } + pumpkin::plugin::player::player_interact_event::InteractAction::RightClickAir => { + "RIGHT_CLICK_AIR".to_string() + } + pumpkin::plugin::player::player_interact_event::InteractAction::RightClickBlock => { + "RIGHT_CLICK_BLOCK".to_string() + } + } +} + +fn gamemode_to_bukkit(mode: pumpkin_util::GameMode) -> String { + match mode { + pumpkin_util::GameMode::Survival => "SURVIVAL".to_string(), + pumpkin_util::GameMode::Creative => "CREATIVE".to_string(), + pumpkin_util::GameMode::Adventure => "ADVENTURE".to_string(), + pumpkin_util::GameMode::Spectator => "SPECTATOR".to_string(), + } +} + +fn gamemode_from_bukkit(mode: &str) -> Option { + match mode { + "SURVIVAL" => Some(pumpkin_util::GameMode::Survival), + "CREATIVE" => Some(pumpkin_util::GameMode::Creative), + "ADVENTURE" => Some(pumpkin_util::GameMode::Adventure), + "SPECTATOR" => Some(pumpkin_util::GameMode::Spectator), + _ => None, + } +} + +fn block_face_to_bukkit(face: Option) -> String { + match face { + Some(BlockDirection::Up) => "UP".to_string(), + Some(BlockDirection::Down) => "DOWN".to_string(), + Some(BlockDirection::North) => "NORTH".to_string(), + Some(BlockDirection::South) => "SOUTH".to_string(), + Some(BlockDirection::West) => "WEST".to_string(), + Some(BlockDirection::East) => "EAST".to_string(), + None => String::new(), + } +} + +fn bukkit_block_face_from_string(face: &str) -> Option { + match face { + "UP" => Some(BlockDirection::Up), + "DOWN" => Some(BlockDirection::Down), + "NORTH" => Some(BlockDirection::North), + "SOUTH" => Some(BlockDirection::South), + "WEST" => Some(BlockDirection::West), + "EAST" => Some(BlockDirection::East), + _ => None, + } +} + +fn bukkit_main_hand(hand: Hand) -> String { + match hand { + Hand::Left => "LEFT".to_string(), + Hand::Right => "RIGHT".to_string(), + } +} + +fn instrument_to_bukkit(instrument: Instrument) -> String { + match instrument { + Instrument::Harp => "PIANO".to_string(), + Instrument::Basedrum => "BASS_DRUM".to_string(), + Instrument::Snare => "SNARE_DRUM".to_string(), + Instrument::Hat => "STICKS".to_string(), + Instrument::Bass => "BASS_GUITAR".to_string(), + Instrument::Flute => "FLUTE".to_string(), + Instrument::Bell => "BELL".to_string(), + Instrument::Guitar => "GUITAR".to_string(), + Instrument::Chime => "CHIME".to_string(), + Instrument::Xylophone => "XYLOPHONE".to_string(), + Instrument::IronXylophone => "IRON_XYLOPHONE".to_string(), + Instrument::CowBell => "COW_BELL".to_string(), + Instrument::Didgeridoo => "DIDGERIDOO".to_string(), + Instrument::Bit => "BIT".to_string(), + Instrument::Banjo => "BANJO".to_string(), + Instrument::Pling => "PLING".to_string(), + Instrument::Zombie => "ZOMBIE".to_string(), + Instrument::Skeleton => "SKELETON".to_string(), + Instrument::Creeper => "CREEPER".to_string(), + Instrument::Dragon => "DRAGON".to_string(), + Instrument::WitherSkeleton => "WITHER_SKELETON".to_string(), + Instrument::Piglin => "PIGLIN".to_string(), + Instrument::CustomHead => "CUSTOM_HEAD".to_string(), + } +} + +fn instrument_from_bukkit(name: &str) -> Option { + match name { + "PIANO" => Some(Instrument::Harp), + "BASS_DRUM" => Some(Instrument::Basedrum), + "SNARE_DRUM" => Some(Instrument::Snare), + "STICKS" => Some(Instrument::Hat), + "BASS_GUITAR" => Some(Instrument::Bass), + "FLUTE" => Some(Instrument::Flute), + "BELL" => Some(Instrument::Bell), + "GUITAR" => Some(Instrument::Guitar), + "CHIME" => Some(Instrument::Chime), + "XYLOPHONE" => Some(Instrument::Xylophone), + "IRON_XYLOPHONE" => Some(Instrument::IronXylophone), + "COW_BELL" => Some(Instrument::CowBell), + "DIDGERIDOO" => Some(Instrument::Didgeridoo), + "BIT" => Some(Instrument::Bit), + "BANJO" => Some(Instrument::Banjo), + "PLING" => Some(Instrument::Pling), + "ZOMBIE" => Some(Instrument::Zombie), + "SKELETON" => Some(Instrument::Skeleton), + "CREEPER" => Some(Instrument::Creeper), + "DRAGON" => Some(Instrument::Dragon), + "WITHER_SKELETON" => Some(Instrument::WitherSkeleton), + "PIGLIN" => Some(Instrument::Piglin), + "CUSTOM_HEAD" => Some(Instrument::CustomHead), + _ => None, + } +} + +pub struct PatchBukkitEventHandler { + plugin_name: String, + command_tx: mpsc::Sender, + _phantom: PhantomData, +} + +impl PatchBukkitEventHandler { + #[must_use] + pub const fn new(plugin_name: String, command_tx: mpsc::Sender) -> Self { + Self { + plugin_name, + command_tx, + _phantom: PhantomData, + } + } +} + +#[with_runtime(global)] +impl EventHandler for PatchBukkitEventHandler +where + E: PatchBukkitEvent + Payload + Cancellable + 'static, +{ + fn handle_blocking<'a>( + &'a self, + server: &'a Arc, + event: &'a mut E, + ) -> BoxFuture<'a, ()> { + let command_tx = self.command_tx.clone(); + + Box::pin(async move { + let (tx, rx) = oneshot::channel(); + if let Err(e) = command_tx + .send(JvmCommand::FireEvent { + payload: event.to_payload(server.clone()), + respond_to: tx, + plugin: self.plugin_name.clone(), + }) + .await + { + log::error!("Failed to send event to JVM worker: {e}"); + return; + } + + match rx.await { + Ok(response) => { + event.set_cancelled(response.cancelled); + event.apply_modifications(server, response.data.unwrap().data.unwrap()); + } + Err(_) => { + log::warn!("JVM worker dropped response channel for event"); + } + } + }) + } +} diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index 48f0963..86e3847 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -1,97 +1,17 @@ -use std::sync::Arc; +use std::sync::Arc; use pumpkin::plugin::EventPriority; -use pumpkin::plugin::block::block_break::BlockBreakEvent; -use pumpkin::plugin::block::block_damage::BlockDamageEvent; -use pumpkin::plugin::block::block_damage_abort::BlockDamageAbortEvent; -use pumpkin::plugin::block::block_dispense::BlockDispenseEvent; -use pumpkin::plugin::block::block_drop_item::BlockDropItemEvent; -use pumpkin::plugin::block::block_explode::BlockExplodeEvent; -use pumpkin::plugin::block::block_fade::BlockFadeEvent; -use pumpkin::plugin::block::block_fertilize::BlockFertilizeEvent; -use pumpkin::plugin::block::block_form::BlockFormEvent; -use pumpkin::plugin::block::block_from_to::BlockFromToEvent; -use pumpkin::plugin::block::block_grow::BlockGrowEvent; -use pumpkin::plugin::block::block_piston_extend::BlockPistonExtendEvent; -use pumpkin::plugin::block::block_piston_retract::BlockPistonRetractEvent; -use pumpkin::plugin::block::block_redstone::BlockRedstoneEvent; -use pumpkin::plugin::block::block_multi_place::BlockMultiPlaceEvent; -use pumpkin::plugin::block::block_physics::BlockPhysicsEvent; -use pumpkin::plugin::block::block_place::BlockPlaceEvent; -use pumpkin::plugin::block::block_can_build::BlockCanBuildEvent; -use pumpkin::plugin::block::block_burn::BlockBurnEvent; -use pumpkin::plugin::block::block_ignite::BlockIgniteEvent; -use pumpkin::plugin::block::block_spread::BlockSpreadEvent; -use pumpkin::plugin::player::player_chat::PlayerChatEvent; -use pumpkin::plugin::player::player_command_preprocess::PlayerCommandPreprocessEvent; -use pumpkin::plugin::player::player_command_send::PlayerCommandSendEvent; -use pumpkin::plugin::player::player_drop_item::PlayerDropItemEvent; -use pumpkin::plugin::player::player_edit_book::PlayerEditBookEvent; -use pumpkin::plugin::player::player_egg_throw::PlayerEggThrowEvent; -use pumpkin::plugin::player::player_exp_change::PlayerExpChangeEvent; -use pumpkin::plugin::player::player_fish::PlayerFishEvent; -use pumpkin::plugin::player::player_interact_entity::PlayerInteractEntityEvent; -use pumpkin::plugin::player::player_interact_at_entity::PlayerInteractAtEntityEvent; -use pumpkin::plugin::player::player_item_held::PlayerItemHeldEvent; -use pumpkin::plugin::player::player_item_damage::PlayerItemDamageEvent; -use pumpkin::plugin::player::player_item_break::PlayerItemBreakEvent; -use pumpkin::plugin::player::player_item_consume::PlayerItemConsumeEvent; -use pumpkin::plugin::player::player_item_mend::PlayerItemMendEvent; -use pumpkin::plugin::player::player_level_change::PlayerLevelChangeEvent; -use pumpkin::plugin::player::player_kick::PlayerKickEvent; -use pumpkin::plugin::player::player_toggle_sneak::PlayerToggleSneakEvent; -use pumpkin::plugin::player::player_toggle_sprint::PlayerToggleSprintEvent; -use pumpkin::plugin::player::player_toggle_flight::PlayerToggleFlightEvent; -use pumpkin::plugin::player::player_swap_hand_items::PlayerSwapHandItemsEvent; -use pumpkin::plugin::player::player_resource_pack_status::PlayerResourcePackStatusEvent; -use pumpkin::plugin::player::player_respawn::PlayerRespawnEvent; -use pumpkin::plugin::player::player_pickup_arrow::PlayerPickupArrowEvent; -use pumpkin::plugin::player::player_portal::PlayerPortalEvent; -use pumpkin::plugin::player::player_recipe_discover::PlayerRecipeDiscoverEvent; -use pumpkin::plugin::player::player_riptide::PlayerRiptideEvent; -use pumpkin::plugin::player::player_shear_entity::PlayerShearEntityEvent; -use pumpkin::plugin::player::player_spawn_location::PlayerSpawnLocationEvent; -use pumpkin::plugin::player::player_statistic_increment::PlayerStatisticIncrementEvent; -use pumpkin::plugin::player::player_velocity::PlayerVelocityEvent; -use pumpkin::plugin::player::player_harvest_block::PlayerHarvestBlockEvent; -use pumpkin::plugin::player::player_interact_event::{InteractAction, PlayerInteractEvent}; -use pumpkin::plugin::player::player_join::PlayerJoinEvent; -use pumpkin::plugin::player::player_login::PlayerLoginEvent; -use pumpkin::plugin::player::player_pre_login::PlayerPreLoginEvent; -use pumpkin::plugin::player::player_advancement_done::PlayerAdvancementDoneEvent; -use pumpkin::plugin::player::player_animation::PlayerAnimationEvent; -use pumpkin::plugin::player::player_armor_stand_manipulate::PlayerArmorStandManipulateEvent; -use pumpkin::plugin::player::player_bed_enter::PlayerBedEnterEvent; -use pumpkin::plugin::player::player_bed_leave::PlayerBedLeaveEvent; -use pumpkin::plugin::player::player_bucket_empty::PlayerBucketEmptyEvent; -use pumpkin::plugin::player::player_bucket_fill::PlayerBucketFillEvent; -use pumpkin::plugin::player::player_bucket_entity::PlayerBucketEntityEvent; -use pumpkin::plugin::player::player_changed_main_hand::PlayerChangedMainHandEvent; -use pumpkin::plugin::player::player_register_channel::PlayerRegisterChannelEvent; -use pumpkin::plugin::player::player_unregister_channel::PlayerUnregisterChannelEvent; -use pumpkin::plugin::player::player_leave::PlayerLeaveEvent; -use pumpkin::plugin::player::player_move::PlayerMoveEvent; -use pumpkin::plugin::player::player_teleport::PlayerTeleportEvent; -use pumpkin::plugin::player::player_change_world::PlayerChangeWorldEvent; -use pumpkin::plugin::player::player_gamemode_change::PlayerGamemodeChangeEvent; -use pumpkin::plugin::server::server_broadcast::ServerBroadcastEvent; -use pumpkin::plugin::server::server_command::ServerCommandEvent; use pumpkin_data::Block; -use pumpkin_data::BlockDirection; -use pumpkin_data::data_component_impl::EquipmentSlot; use pumpkin_data::item::Item; use pumpkin_world::item::ItemStack; use pumpkin_util::math::vector3::Vector3; use pumpkin_util::text::TextComponent; -use pumpkin_util::Hand; use tokio::sync::Mutex; use crate::events::handler::PatchBukkitEventHandler; use crate::java::native_callbacks::CALLBACK_CONTEXT; use crate::proto::patchbukkit::events::event::Data; -use crate::proto::patchbukkit::events::{ - CallEventRequest, CallEventResponse, RegisterEventRequest, -}; +use crate::proto::patchbukkit::events::{CallEventRequest, CallEventResponse, RegisterEventRequest}; pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> Option<()> { let ctx = CALLBACK_CONTEXT.get()?; @@ -120,84 +40,9 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O "org.bukkit.event.player.PlayerJoinEvent" => { context .register_event::< - pumpkin::plugin::player::player_join::PlayerJoinEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerLoginEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_login::PlayerLoginEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.AsyncPlayerPreLoginEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_pre_login::PlayerPreLoginEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerQuitEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_leave::PlayerLeaveEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerMoveEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_move::PlayerMoveEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerAdvancementDoneEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_advancement_done::PlayerAdvancementDoneEvent, + pumpkin::plugin::api::events::player::player_join::PlayerJoinEvent, PatchBukkitEventHandler< - pumpkin::plugin::player::player_advancement_done::PlayerAdvancementDoneEvent, + pumpkin::plugin::api::events::player::player_join::PlayerJoinEvent, >, >( Arc::new(PatchBukkitEventHandler::new( @@ -209,12 +54,12 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } - "org.bukkit.event.player.PlayerAnimationEvent" => { + "org.bukkit.event.player.PlayerLoginEvent" => { context .register_event::< - pumpkin::plugin::player::player_animation::PlayerAnimationEvent, + pumpkin::plugin::api::events::player::player_login::PlayerLoginEvent, PatchBukkitEventHandler< - pumpkin::plugin::player::player_animation::PlayerAnimationEvent, + pumpkin::plugin::api::events::player::player_login::PlayerLoginEvent, >, >( Arc::new(PatchBukkitEventHandler::new( @@ -226,12 +71,12 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } - "org.bukkit.event.player.PlayerArmorStandManipulateEvent" => { + "org.bukkit.event.player.PlayerQuitEvent" => { context .register_event::< - pumpkin::plugin::player::player_armor_stand_manipulate::PlayerArmorStandManipulateEvent, + pumpkin::plugin::api::events::player::player_leave::PlayerLeaveEvent, PatchBukkitEventHandler< - pumpkin::plugin::player::player_armor_stand_manipulate::PlayerArmorStandManipulateEvent, + pumpkin::plugin::api::events::player::player_leave::PlayerLeaveEvent, >, >( Arc::new(PatchBukkitEventHandler::new( @@ -243,12 +88,12 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } - "org.bukkit.event.player.PlayerBedEnterEvent" => { + "org.bukkit.event.player.PlayerMoveEvent" => { context .register_event::< - pumpkin::plugin::player::player_bed_enter::PlayerBedEnterEvent, + pumpkin::plugin::api::events::player::player_move::PlayerMoveEvent, PatchBukkitEventHandler< - pumpkin::plugin::player::player_bed_enter::PlayerBedEnterEvent, + pumpkin::plugin::api::events::player::player_move::PlayerMoveEvent, >, >( Arc::new(PatchBukkitEventHandler::new( @@ -260,12 +105,12 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } - "org.bukkit.event.player.PlayerBedLeaveEvent" => { + "org.bukkit.event.player.PlayerTeleportEvent" => { context .register_event::< - pumpkin::plugin::player::player_bed_leave::PlayerBedLeaveEvent, + pumpkin::plugin::api::events::player::player_teleport::PlayerTeleportEvent, PatchBukkitEventHandler< - pumpkin::plugin::player::player_bed_leave::PlayerBedLeaveEvent, + pumpkin::plugin::api::events::player::player_teleport::PlayerTeleportEvent, >, >( Arc::new(PatchBukkitEventHandler::new( @@ -277,12 +122,12 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } - "org.bukkit.event.player.PlayerBucketEmptyEvent" => { + "org.bukkit.event.player.PlayerChangedWorldEvent" => { context .register_event::< - pumpkin::plugin::player::player_bucket_empty::PlayerBucketEmptyEvent, + pumpkin::plugin::api::events::player::player_change_world::PlayerChangeWorldEvent, PatchBukkitEventHandler< - pumpkin::plugin::player::player_bucket_empty::PlayerBucketEmptyEvent, + pumpkin::plugin::api::events::player::player_change_world::PlayerChangeWorldEvent, >, >( Arc::new(PatchBukkitEventHandler::new( @@ -294,12 +139,12 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } - "org.bukkit.event.player.PlayerBucketFillEvent" => { + "org.bukkit.event.player.PlayerGameModeChangeEvent" => { context .register_event::< - pumpkin::plugin::player::player_bucket_fill::PlayerBucketFillEvent, + pumpkin::plugin::api::events::player::player_gamemode_change::PlayerGamemodeChangeEvent, PatchBukkitEventHandler< - pumpkin::plugin::player::player_bucket_fill::PlayerBucketFillEvent, + pumpkin::plugin::api::events::player::player_gamemode_change::PlayerGamemodeChangeEvent, >, >( Arc::new(PatchBukkitEventHandler::new( @@ -311,12 +156,13 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } - "org.bukkit.event.player.PlayerBucketEntityEvent" => { + "org.bukkit.event.player.AsyncPlayerChatEvent" + | "org.bukkit.event.player.PlayerChatEvent" => { context .register_event::< - pumpkin::plugin::player::player_bucket_entity::PlayerBucketEntityEvent, + pumpkin::plugin::api::events::player::player_chat::PlayerChatEvent, PatchBukkitEventHandler< - pumpkin::plugin::player::player_bucket_entity::PlayerBucketEntityEvent, + pumpkin::plugin::api::events::player::player_chat::PlayerChatEvent, >, >( Arc::new(PatchBukkitEventHandler::new( @@ -328,12 +174,12 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } - "org.bukkit.event.player.PlayerChangedMainHandEvent" => { + "org.bukkit.event.player.PlayerCommandSendEvent" => { context .register_event::< - pumpkin::plugin::player::player_changed_main_hand::PlayerChangedMainHandEvent, + pumpkin::plugin::api::events::player::player_command_send::PlayerCommandSendEvent, PatchBukkitEventHandler< - pumpkin::plugin::player::player_changed_main_hand::PlayerChangedMainHandEvent, + pumpkin::plugin::api::events::player::player_command_send::PlayerCommandSendEvent, >, >( Arc::new(PatchBukkitEventHandler::new( @@ -345,12 +191,12 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } - "org.bukkit.event.player.PlayerRegisterChannelEvent" => { + "org.bukkit.event.player.PlayerInteractEvent" => { context .register_event::< - pumpkin::plugin::player::player_register_channel::PlayerRegisterChannelEvent, + pumpkin::plugin::api::events::player::player_interact_event::PlayerInteractEvent, PatchBukkitEventHandler< - pumpkin::plugin::player::player_register_channel::PlayerRegisterChannelEvent, + pumpkin::plugin::api::events::player::player_interact_event::PlayerInteractEvent, >, >( Arc::new(PatchBukkitEventHandler::new( @@ -362,12 +208,12 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } - "org.bukkit.event.player.PlayerUnregisterChannelEvent" => { + "org.bukkit.event.block.BlockBreakEvent" => { context .register_event::< - pumpkin::plugin::player::player_unregister_channel::PlayerUnregisterChannelEvent, + pumpkin::plugin::api::events::block::block_break::BlockBreakEvent, PatchBukkitEventHandler< - pumpkin::plugin::player::player_unregister_channel::PlayerUnregisterChannelEvent, + pumpkin::plugin::api::events::block::block_break::BlockBreakEvent, >, >( Arc::new(PatchBukkitEventHandler::new( @@ -379,27 +225,12 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } - "org.bukkit.event.player.PlayerTeleportEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_teleport::PlayerTeleportEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerChangedWorldEvent" => { + "org.bukkit.event.block.BlockBurnEvent" => { context .register_event::< - pumpkin::plugin::player::player_change_world::PlayerChangeWorldEvent, + pumpkin::plugin::api::events::block::block_burn::BlockBurnEvent, PatchBukkitEventHandler< - pumpkin::plugin::player::player_change_world::PlayerChangeWorldEvent, + pumpkin::plugin::api::events::block::block_burn::BlockBurnEvent, >, >( Arc::new(PatchBukkitEventHandler::new( @@ -411,12 +242,12 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } - "org.bukkit.event.player.PlayerGameModeChangeEvent" => { + "org.bukkit.event.block.BlockCanBuildEvent" => { context .register_event::< - pumpkin::plugin::player::player_gamemode_change::PlayerGamemodeChangeEvent, + pumpkin::plugin::api::events::block::block_can_build::BlockCanBuildEvent, PatchBukkitEventHandler< - pumpkin::plugin::player::player_gamemode_change::PlayerGamemodeChangeEvent, + pumpkin::plugin::api::events::block::block_can_build::BlockCanBuildEvent, >, >( Arc::new(PatchBukkitEventHandler::new( @@ -428,27 +259,12 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } - "org.bukkit.event.player.AsyncPlayerChatEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_chat::PlayerChatEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerCommandPreprocessEvent" => { + "org.bukkit.event.block.BlockPlaceEvent" => { context .register_event::< - pumpkin::plugin::player::player_command_preprocess::PlayerCommandPreprocessEvent, + pumpkin::plugin::api::events::block::block_place::BlockPlaceEvent, PatchBukkitEventHandler< - pumpkin::plugin::player::player_command_preprocess::PlayerCommandPreprocessEvent, + pumpkin::plugin::api::events::block::block_place::BlockPlaceEvent, >, >( Arc::new(PatchBukkitEventHandler::new( @@ -460,12 +276,12 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } - "org.bukkit.event.player.PlayerCommandSendEvent" => { + "org.bukkit.event.server.ServerCommandEvent" => { context .register_event::< - pumpkin::plugin::player::player_command_send::PlayerCommandSendEvent, + pumpkin::plugin::api::events::server::server_command::ServerCommandEvent, PatchBukkitEventHandler< - pumpkin::plugin::player::player_command_send::PlayerCommandSendEvent, + pumpkin::plugin::api::events::server::server_command::ServerCommandEvent, >, >( Arc::new(PatchBukkitEventHandler::new( @@ -477,12 +293,12 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } - "org.bukkit.event.player.PlayerDropItemEvent" => { + "org.bukkit.event.server.BroadcastMessageEvent" => { context .register_event::< - pumpkin::plugin::player::player_drop_item::PlayerDropItemEvent, + pumpkin::plugin::api::events::server::server_broadcast::ServerBroadcastEvent, PatchBukkitEventHandler< - pumpkin::plugin::player::player_drop_item::PlayerDropItemEvent, + pumpkin::plugin::api::events::server::server_broadcast::ServerBroadcastEvent, >, >( Arc::new(PatchBukkitEventHandler::new( @@ -494,2264 +310,170 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } - "org.bukkit.event.player.PlayerEditBookEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_edit_book::PlayerEditBookEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_edit_book::PlayerEditBookEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + _ => { + log::warn!("Unsupported Bukkit event registration: {}", request.event_type); } - "org.bukkit.event.player.PlayerEggThrowEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_egg_throw::PlayerEggThrowEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_egg_throw::PlayerEggThrowEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + } + }) + }); + + Some(()) +} + +pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let ctx = CALLBACK_CONTEXT.get()?; + + let handled = tokio::task::block_in_place(|| { + ctx.runtime.block_on(async { + let Some(data) = request.event.and_then(|event| event.data) else { + return Some(false); + }; + + match data { + Data::PlayerChat(event) => { + let uuid = uuid::Uuid::parse_str(&event.player_uuid?.value).ok()?; + let player = ctx.plugin_context.server.get_player_by_uuid(uuid)?; + let mut recipients = Vec::new(); + for recipient in event.recipients { + let rid = uuid::Uuid::parse_str(&recipient.value).ok()?; + if let Some(recipient_player) = ctx.plugin_context.server.get_player_by_uuid(rid) { + recipients.push(recipient_player); + } + } + let pumpkin_event = + pumpkin::plugin::api::events::player::player_chat::PlayerChatEvent::new( + player, + event.message, + recipients, + ); + ctx.plugin_context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) } - "org.bukkit.event.player.PlayerExpChangeEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_exp_change::PlayerExpChangeEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_exp_change::PlayerExpChangeEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + Data::PlayerCommandSend(event) => { + let uuid = uuid::Uuid::parse_str(&event.player_uuid?.value).ok()?; + let player = ctx.plugin_context.server.get_player_by_uuid(uuid)?; + let command = event.commands.first().cloned().unwrap_or_default(); + let pumpkin_event = + pumpkin::plugin::api::events::player::player_command_send::PlayerCommandSendEvent::new( + player, + command, + ); + ctx.plugin_context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) } - "org.bukkit.event.player.PlayerFishEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_fish::PlayerFishEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_fish::PlayerFishEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + Data::PlayerInteract(event) => { + let uuid = uuid::Uuid::parse_str(&event.player_uuid?.value).ok()?; + let player = ctx.plugin_context.server.get_player_by_uuid(uuid)?; + let action = match event.action.as_str() { + "LEFT_CLICK_BLOCK" => pumpkin::plugin::api::events::player::player_interact_event::InteractAction::LeftClickBlock, + "LEFT_CLICK_AIR" => pumpkin::plugin::api::events::player::player_interact_event::InteractAction::LeftClickAir, + "RIGHT_CLICK_AIR" => pumpkin::plugin::api::events::player::player_interact_event::InteractAction::RightClickAir, + "RIGHT_CLICK_BLOCK" => pumpkin::plugin::api::events::player::player_interact_event::InteractAction::RightClickBlock, + _ => pumpkin::plugin::api::events::player::player_interact_event::InteractAction::RightClickAir, + }; + let block = block_from_key(&event.block_key); + let clicked_pos = event + .clicked + .and_then(location_to_vec3) + .map(|pos| pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + )); + let item = Arc::new(Mutex::new(item_stack_from_key(&event.item_key, 1))); + let pumpkin_event = + pumpkin::plugin::api::events::player::player_interact_event::PlayerInteractEvent::new( + &player, + action, + &item, + block, + clicked_pos, + ); + ctx.plugin_context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) } - "org.bukkit.event.player.PlayerInteractEntityEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_interact_entity::PlayerInteractEntityEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_interact_entity::PlayerInteractEntityEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + Data::PlayerMove(event) => { + let uuid = uuid::Uuid::parse_str(&event.player_uuid?.value).ok()?; + let player = ctx.plugin_context.server.get_player_by_uuid(uuid)?; + let from = event.from.and_then(location_to_vec3).unwrap_or_else(Vector3::default); + let to = event.to.and_then(location_to_vec3).unwrap_or_else(Vector3::default); + let pumpkin_event = + pumpkin::plugin::api::events::player::player_move::PlayerMoveEvent::new( + player, + from, + to, + ); + ctx.plugin_context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) } - "org.bukkit.event.player.PlayerInteractAtEntityEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_interact_at_entity::PlayerInteractAtEntityEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_interact_at_entity::PlayerInteractAtEntityEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + Data::PlayerTeleport(event) => { + let uuid = uuid::Uuid::parse_str(&event.player_uuid?.value).ok()?; + let player = ctx.plugin_context.server.get_player_by_uuid(uuid)?; + let from = event.from.and_then(location_to_vec3).unwrap_or_else(Vector3::default); + let to = event.to.and_then(location_to_vec3).unwrap_or_else(Vector3::default); + let pumpkin_event = + pumpkin::plugin::api::events::player::player_teleport::PlayerTeleportEvent::new( + player, + from, + to, + ); + ctx.plugin_context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) } - "org.bukkit.event.player.PlayerItemHeldEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_item_held::PlayerItemHeldEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_item_held::PlayerItemHeldEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + Data::PlayerChangeWorld(event) => { + let uuid = uuid::Uuid::parse_str(&event.player_uuid?.value).ok()?; + let player = ctx.plugin_context.server.get_player_by_uuid(uuid)?; + let previous_world = event + .previous_world + .and_then(|w| w.uuid) + .and_then(|id| uuid::Uuid::parse_str(&id.value).ok()) + .and_then(|id| find_world_by_uuid(&ctx.plugin_context.server, id)) + .unwrap_or_else(|| ctx.plugin_context.server.worlds.load()[0].clone()); + let new_world = event + .new_world + .and_then(|w| w.uuid) + .and_then(|id| uuid::Uuid::parse_str(&id.value).ok()) + .and_then(|id| find_world_by_uuid(&ctx.plugin_context.server, id)) + .unwrap_or_else(|| ctx.plugin_context.server.worlds.load()[0].clone()); + let position = event + .position + .and_then(location_to_vec3) + .unwrap_or_else(Vector3::default); + let pumpkin_event = + pumpkin::plugin::api::events::player::player_change_world::PlayerChangeWorldEvent::new( + player, + previous_world, + new_world, + position, + event.yaw, + event.pitch, + ); + ctx.plugin_context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) } - "org.bukkit.event.player.PlayerItemDamageEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_item_damage::PlayerItemDamageEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_item_damage::PlayerItemDamageEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + Data::PlayerGamemodeChange(event) => { + let uuid = uuid::Uuid::parse_str(&event.player_uuid?.value).ok()?; + let player = ctx.plugin_context.server.get_player_by_uuid(uuid)?; + let previous = gamemode_from_bukkit(&event.previous_gamemode) + .unwrap_or(pumpkin_util::GameMode::Survival); + let new_mode = gamemode_from_bukkit(&event.new_gamemode) + .unwrap_or(pumpkin_util::GameMode::Survival); + let pumpkin_event = + pumpkin::plugin::api::events::player::player_gamemode_change::PlayerGamemodeChangeEvent::new( + player, + previous, + new_mode, + ); + ctx.plugin_context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) } - "org.bukkit.event.player.PlayerItemBreakEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_item_break::PlayerItemBreakEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_item_break::PlayerItemBreakEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerItemConsumeEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_item_consume::PlayerItemConsumeEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_item_consume::PlayerItemConsumeEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerItemMendEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_item_mend::PlayerItemMendEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_item_mend::PlayerItemMendEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerLevelChangeEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_level_change::PlayerLevelChangeEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_level_change::PlayerLevelChangeEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerKickEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_kick::PlayerKickEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_kick::PlayerKickEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerToggleSneakEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_toggle_sneak::PlayerToggleSneakEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_toggle_sneak::PlayerToggleSneakEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerToggleSprintEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_toggle_sprint::PlayerToggleSprintEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_toggle_sprint::PlayerToggleSprintEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerToggleFlightEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_toggle_flight::PlayerToggleFlightEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_toggle_flight::PlayerToggleFlightEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerSwapHandItemsEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_swap_hand_items::PlayerSwapHandItemsEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_swap_hand_items::PlayerSwapHandItemsEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerResourcePackStatusEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_resource_pack_status::PlayerResourcePackStatusEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_resource_pack_status::PlayerResourcePackStatusEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerRespawnEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_respawn::PlayerRespawnEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_respawn::PlayerRespawnEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerPickupArrowEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_pickup_arrow::PlayerPickupArrowEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_pickup_arrow::PlayerPickupArrowEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerPortalEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_portal::PlayerPortalEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_portal::PlayerPortalEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerRecipeDiscoverEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_recipe_discover::PlayerRecipeDiscoverEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_recipe_discover::PlayerRecipeDiscoverEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerRiptideEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_riptide::PlayerRiptideEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_riptide::PlayerRiptideEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerShearEntityEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_shear_entity::PlayerShearEntityEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_shear_entity::PlayerShearEntityEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.spigotmc.event.player.PlayerSpawnLocationEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_spawn_location::PlayerSpawnLocationEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_spawn_location::PlayerSpawnLocationEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerStatisticIncrementEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_statistic_increment::PlayerStatisticIncrementEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_statistic_increment::PlayerStatisticIncrementEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerVelocityEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_velocity::PlayerVelocityEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_velocity::PlayerVelocityEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerHarvestBlockEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_harvest_block::PlayerHarvestBlockEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_harvest_block::PlayerHarvestBlockEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerInteractEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_interact_event::PlayerInteractEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_interact_event::PlayerInteractEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockBreakEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_break::BlockBreakEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockDamageEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_damage::BlockDamageEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockDamageAbortEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_damage_abort::BlockDamageAbortEvent, - PatchBukkitEventHandler< - pumpkin::plugin::block::block_damage_abort::BlockDamageAbortEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockDispenseEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_dispense::BlockDispenseEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockDropItemEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_drop_item::BlockDropItemEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockExplodeEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_explode::BlockExplodeEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockFadeEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_fade::BlockFadeEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockFertilizeEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_fertilize::BlockFertilizeEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockFormEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_form::BlockFormEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockFromToEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_from_to::BlockFromToEvent, - PatchBukkitEventHandler< - pumpkin::plugin::block::block_from_to::BlockFromToEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockGrowEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_grow::BlockGrowEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockPistonExtendEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_piston_extend::BlockPistonExtendEvent, - PatchBukkitEventHandler< - pumpkin::plugin::block::block_piston_extend::BlockPistonExtendEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockPistonRetractEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_piston_retract::BlockPistonRetractEvent, - PatchBukkitEventHandler< - pumpkin::plugin::block::block_piston_retract::BlockPistonRetractEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockRedstoneEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_redstone::BlockRedstoneEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockMultiPlaceEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_multi_place::BlockMultiPlaceEvent, - PatchBukkitEventHandler< - pumpkin::plugin::block::block_multi_place::BlockMultiPlaceEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockPhysicsEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_physics::BlockPhysicsEvent, - PatchBukkitEventHandler< - pumpkin::plugin::block::block_physics::BlockPhysicsEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.NotePlayEvent" => { - context - .register_event::< - pumpkin::plugin::block::note_play::NotePlayEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.SignChangeEvent" => { - context - .register_event::< - pumpkin::plugin::block::sign_change::SignChangeEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.TNTPrimeEvent" => { - context - .register_event::< - pumpkin::plugin::block::tnt_prime::TNTPrimeEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.MoistureChangeEvent" => { - context - .register_event::< - pumpkin::plugin::block::moisture_change::MoistureChangeEvent, - PatchBukkitEventHandler< - pumpkin::plugin::block::moisture_change::MoistureChangeEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.SpongeAbsorbEvent" => { - context - .register_event::< - pumpkin::plugin::block::sponge_absorb::SpongeAbsorbEvent, - PatchBukkitEventHandler< - pumpkin::plugin::block::sponge_absorb::SpongeAbsorbEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.FluidLevelChangeEvent" => { - context - .register_event::< - pumpkin::plugin::block::fluid_level_change::FluidLevelChangeEvent, - PatchBukkitEventHandler< - pumpkin::plugin::block::fluid_level_change::FluidLevelChangeEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.world.SpawnChangeEvent" => { - context - .register_event::< - pumpkin::plugin::world::spawn_change::SpawnChangeEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.server.ServerListPingEvent" => { - context - .register_event::< - pumpkin::plugin::server::server_list_ping::ServerListPingEvent, - PatchBukkitEventHandler< - pumpkin::plugin::server::server_list_ping::ServerListPingEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.server.PluginEnableEvent" => { - context - .register_event::< - pumpkin::plugin::server::plugin_enable::PluginEnableEvent, - PatchBukkitEventHandler< - pumpkin::plugin::server::plugin_enable::PluginEnableEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.server.PluginDisableEvent" => { - context - .register_event::< - pumpkin::plugin::server::plugin_disable::PluginDisableEvent, - PatchBukkitEventHandler< - pumpkin::plugin::server::plugin_disable::PluginDisableEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.server.ServiceRegisterEvent" => { - context - .register_event::< - pumpkin::plugin::server::service_register::ServiceRegisterEvent, - PatchBukkitEventHandler< - pumpkin::plugin::server::service_register::ServiceRegisterEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.server.ServiceUnregisterEvent" => { - context - .register_event::< - pumpkin::plugin::server::service_unregister::ServiceUnregisterEvent, - PatchBukkitEventHandler< - pumpkin::plugin::server::service_unregister::ServiceUnregisterEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockCanBuildEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_can_build::BlockCanBuildEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockBurnEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_burn::BlockBurnEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockIgniteEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_ignite::BlockIgniteEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockSpreadEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_spread::BlockSpreadEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockPlaceEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_place::BlockPlaceEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.entity.EntitySpawnEvent" => { - context - .register_event::< - pumpkin::plugin::entity::entity_spawn::EntitySpawnEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.entity.EntityDamageEvent" => { - context - .register_event::< - pumpkin::plugin::entity::entity_damage::EntityDamageEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.entity.EntityDeathEvent" => { - context - .register_event::< - pumpkin::plugin::entity::entity_death::EntityDeathEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.server.ServerCommandEvent" => { - context - .register_event::< - pumpkin::plugin::server::server_command::ServerCommandEvent, - PatchBukkitEventHandler< - pumpkin::plugin::server::server_command::ServerCommandEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.server.BroadcastMessageEvent" => { - context - .register_event::< - pumpkin::plugin::server::server_broadcast::ServerBroadcastEvent, - PatchBukkitEventHandler< - pumpkin::plugin::server::server_broadcast::ServerBroadcastEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - _ => { - log::warn!( - "Unsupported Bukkit event type '{}' from plugin '{}'", - request.event_type, request.plugin_name - ); - } - } - }); - }); - - Some(()) -} - -pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { - let ctx = CALLBACK_CONTEXT.get()?; - let event = request.event?; - log::debug!("Java calling event {:?}", event); - - let context = ctx.plugin_context.clone(); - - let handled = tokio::task::block_in_place(|| { - ctx.runtime.block_on(async { - match event.data? { - Data::PlayerJoin(player_join_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_join_event_data.player_uuid?.value).ok()?; - let 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; - Some(true) - } - Data::PlayerLogin(player_login_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_login_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let pumpkin_event = PlayerLoginEvent::new( - player, - TextComponent::from_legacy_string(&player_login_event_data.kick_message), - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::AsyncPlayerPreLogin(player_pre_login_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_pre_login_event_data.player_uuid?.value).ok()?; - let pumpkin_event = PlayerPreLoginEvent::new( - player_pre_login_event_data.name, - uuid, - player_pre_login_event_data.address, - player_pre_login_event_data.result, - player_pre_login_event_data.kick_message, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerLeave(player_leave_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_leave_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let pumpkin_event = PlayerLeaveEvent::new( - player, - TextComponent::from_legacy_string(&player_leave_event_data.leave_message), - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerMove(player_move_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_move_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let from = player_move_event_data.from?.position?; - let to = player_move_event_data.to?.position?; - let pumpkin_event = PlayerMoveEvent::new( - player, - Vector3::new(from.x, from.y, from.z), - Vector3::new(to.x, to.y, to.z), - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerAdvancementDone(player_advancement_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_advancement_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let pumpkin_event = PlayerAdvancementDoneEvent::new( - player, - player_advancement_event_data.advancement_key, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerAnimation(player_animation_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_animation_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let pumpkin_event = PlayerAnimationEvent::new( - player, - player_animation_event_data.animation_type, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerArmorStandManipulate(player_armor_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_armor_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let armor_uuid = uuid::Uuid::parse_str( - &player_armor_event_data.armor_stand_uuid?.value, - ) - .ok()?; - let pumpkin_event = PlayerArmorStandManipulateEvent::new( - player, - armor_uuid, - player_armor_event_data.item_key, - player_armor_event_data.armor_stand_item_key, - player_armor_event_data.slot, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerBedEnter(player_bed_enter_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_bed_enter_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let position = player_bed_enter_event_data - .bed_location - .and_then(|loc| loc.position) - .map(|pos| Vector3::new(pos.x, pos.y, pos.z)) - .unwrap_or_else(|| player.position()); - let pumpkin_event = PlayerBedEnterEvent::new(player, position); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerBedLeave(player_bed_leave_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_bed_leave_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let position = player_bed_leave_event_data - .bed_location - .and_then(|loc| loc.position) - .map(|pos| Vector3::new(pos.x, pos.y, pos.z)) - .unwrap_or_else(|| player.position()); - let pumpkin_event = PlayerBedLeaveEvent::new(player, position); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerBucketEmpty(player_bucket_empty_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_bucket_empty_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let position = player_bucket_empty_event_data - .location - .and_then(|loc| loc.position) - .map(|pos| Vector3::new(pos.x, pos.y, pos.z)) - .unwrap_or_else(|| player.position()); - let face = bukkit_block_face_to_direction( - &player_bucket_empty_event_data.block_face, - ); - let pumpkin_event = PlayerBucketEmptyEvent::new( - player, - position, - player_bucket_empty_event_data.block_key, - face, - player_bucket_empty_event_data.bucket_item_key, - player_bucket_empty_event_data.hand, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerBucketFill(player_bucket_fill_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_bucket_fill_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let position = player_bucket_fill_event_data - .location - .and_then(|loc| loc.position) - .map(|pos| Vector3::new(pos.x, pos.y, pos.z)) - .unwrap_or_else(|| player.position()); - let face = bukkit_block_face_to_direction( - &player_bucket_fill_event_data.block_face, - ); - let pumpkin_event = PlayerBucketFillEvent::new( - player, - position, - player_bucket_fill_event_data.block_key, - face, - player_bucket_fill_event_data.bucket_item_key, - player_bucket_fill_event_data.hand, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerBucketEntity(player_bucket_entity_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_bucket_entity_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let entity_uuid = - uuid::Uuid::parse_str(&player_bucket_entity_event_data.entity_uuid?.value).ok()?; - let pumpkin_event = PlayerBucketEntityEvent::new( - player, - entity_uuid, - player_bucket_entity_event_data.entity_type, - player_bucket_entity_event_data.original_bucket_key, - player_bucket_entity_event_data.entity_bucket_key, - player_bucket_entity_event_data.hand, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerChangedMainHand(player_changed_main_hand_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_changed_main_hand_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let main_hand = main_hand_from_bukkit( - &player_changed_main_hand_event_data.main_hand, - ) - .unwrap_or(Hand::Right); - let pumpkin_event = PlayerChangedMainHandEvent::new(player, main_hand); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerRegisterChannel(player_register_channel_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_register_channel_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let pumpkin_event = PlayerRegisterChannelEvent::new( - player, - player_register_channel_event_data.channel, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerUnregisterChannel(player_unregister_channel_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_unregister_channel_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let pumpkin_event = PlayerUnregisterChannelEvent::new( - player, - player_unregister_channel_event_data.channel, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerTeleport(player_teleport_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_teleport_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let from = player_teleport_event_data.from?.position?; - let to = player_teleport_event_data.to?.position?; - let pumpkin_event = PlayerTeleportEvent::new( - player, - Vector3::new(from.x, from.y, from.z), - Vector3::new(to.x, to.y, to.z), - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerChangeWorld(player_change_world_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_change_world_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let prev_uuid = uuid::Uuid::parse_str( - &player_change_world_event_data.previous_world?.uuid?.value, - ) - .ok()?; - let new_uuid = uuid::Uuid::parse_str( - &player_change_world_event_data.new_world?.uuid?.value, - ) - .ok()?; - let prev_world = context - .server - .worlds - .load() - .iter() - .find(|world| world.uuid == prev_uuid)? - .clone(); - let new_world = context - .server - .worlds - .load() - .iter() - .find(|world| world.uuid == new_uuid)? - .clone(); - let position = player_change_world_event_data - .position - .and_then(|loc| loc.position) - .map(|pos| Vector3::new(pos.x, pos.y, pos.z)) - .unwrap_or_else(|| player.position()); - let pumpkin_event = PlayerChangeWorldEvent::new( - player, - prev_world, - new_world, - position, - player_change_world_event_data.yaw, - player_change_world_event_data.pitch, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerGamemodeChange(player_gamemode_change_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_gamemode_change_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let prev = gamemode_from_bukkit(&player_gamemode_change_event_data.previous_gamemode) - .unwrap_or(player.gamemode.load()); - let next = gamemode_from_bukkit(&player_gamemode_change_event_data.new_gamemode) - .unwrap_or(player.gamemode.load()); - let pumpkin_event = PlayerGamemodeChangeEvent::new(player, prev, next); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerChat(player_chat_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_chat_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let mut recipients = Vec::new(); - if player_chat_event_data.recipients.is_empty() { - recipients = context.server.get_all_players(); - } else { - for recipient in player_chat_event_data.recipients { - if let Ok(uuid) = uuid::Uuid::parse_str(&recipient.value) { - if let Some(recipient_player) = - context.server.get_player_by_uuid(uuid) - { - recipients.push(recipient_player); - } - } - } - } - - let pumpkin_event = PlayerChatEvent::new( - player, - player_chat_event_data.message, - recipients, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerCommand(player_command_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_command_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let pumpkin_event = - PlayerCommandPreprocessEvent::new(player, player_command_event_data.command); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerCommandSend(player_command_send_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_command_send_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let pumpkin_event = - PlayerCommandSendEvent::new(player, player_command_send_event_data.commands); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerDropItem(player_drop_item_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_drop_item_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let item_uuid = - uuid::Uuid::parse_str(&player_drop_item_event_data.item_uuid?.value).ok()?; - let item_stack = item_stack_from_key( - &player_drop_item_event_data.item_key, - player_drop_item_event_data.item_amount, - ); - let pumpkin_event = - PlayerDropItemEvent::new(player, item_uuid, item_stack); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerEditBook(player_edit_book_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_edit_book_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let title = if player_edit_book_event_data.title.is_empty() { - None - } else { - Some(player_edit_book_event_data.title) - }; - let pumpkin_event = PlayerEditBookEvent::new( - player, - player_edit_book_event_data.slot, - player_edit_book_event_data.pages, - title, - player_edit_book_event_data.is_signing, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerEggThrow(player_egg_throw_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_egg_throw_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let egg_uuid = - uuid::Uuid::parse_str(&player_egg_throw_event_data.egg_uuid?.value).ok()?; - let pumpkin_event = PlayerEggThrowEvent::new( - player, - egg_uuid, - player_egg_throw_event_data.hatching, - player_egg_throw_event_data.num_hatches.min(u8::MAX as i32) as u8, - player_egg_throw_event_data.hatching_type, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerExpChange(player_exp_change_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_exp_change_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let pumpkin_event = - PlayerExpChangeEvent::new(player, player_exp_change_event_data.amount); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerFish(player_fish_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_fish_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let caught_uuid = player_fish_event_data - .caught_uuid - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()); - let hook_uuid = - uuid::Uuid::parse_str(&player_fish_event_data.hook_uuid?.value).ok()?; - let pumpkin_event = PlayerFishEvent::new( - player, - caught_uuid, - hook_uuid, - player_fish_event_data.caught_type, - player_fish_event_data.state, - player_fish_event_data.hand, - player_fish_event_data.exp_to_drop, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerInteractEntity(player_interact_entity_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_interact_entity_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let entity_uuid = - uuid::Uuid::parse_str(&player_interact_entity_event_data.entity_uuid?.value).ok()?; - let pumpkin_event = PlayerInteractEntityEvent::new( - player, - entity_uuid, - player_interact_entity_event_data.entity_type, - player_interact_entity_event_data.hand, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerInteractAtEntity(player_interact_at_entity_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_interact_at_entity_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let entity_uuid = - uuid::Uuid::parse_str(&player_interact_at_entity_event_data.entity_uuid?.value).ok()?; - let position = player_interact_at_entity_event_data - .clicked_position - .map(|pos| Vector3::new(pos.x as f32, pos.y as f32, pos.z as f32)) - .unwrap_or_else(|| Vector3::new(0.0, 0.0, 0.0)); - let pumpkin_event = PlayerInteractAtEntityEvent::new( - player, - entity_uuid, - player_interact_at_entity_event_data.entity_type, - player_interact_at_entity_event_data.hand, - position, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerItemHeld(player_item_held_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_item_held_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let pumpkin_event = PlayerItemHeldEvent::new( - player, - player_item_held_event_data.previous_slot, - player_item_held_event_data.new_slot, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerItemDamage(player_item_damage_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_item_damage_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let key = if player_item_damage_event_data.item_key.is_empty() { - "minecraft:air" - } else { - player_item_damage_event_data.item_key.as_str() - }; - let item = item_stack_from_key(key, player_item_damage_event_data.item_amount); - let pumpkin_event = PlayerItemDamageEvent::new( - player, - item, - player_item_damage_event_data.damage, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerItemBreak(player_item_break_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_item_break_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let key = if player_item_break_event_data.item_key.is_empty() { - "minecraft:air" - } else { - player_item_break_event_data.item_key.as_str() - }; - let item = item_stack_from_key(key, player_item_break_event_data.item_amount); - let pumpkin_event = PlayerItemBreakEvent::new(player, item); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerItemConsume(player_item_consume_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_item_consume_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let key = if player_item_consume_event_data.item_key.is_empty() { - "minecraft:air" - } else { - player_item_consume_event_data.item_key.as_str() - }; - let item = item_stack_from_key(key, player_item_consume_event_data.item_amount); - let hand = if player_item_consume_event_data.hand == "OFF_HAND" { - Hand::Left - } else { - Hand::Right - }; - let pumpkin_event = PlayerItemConsumeEvent::new(player, item, hand); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerItemMend(player_item_mend_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_item_mend_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let key = if player_item_mend_event_data.item_key.is_empty() { - "minecraft:air" - } else { - player_item_mend_event_data.item_key.as_str() - }; - let item = item_stack_from_key(key, player_item_mend_event_data.item_amount); - let slot = equipment_slot_from_bukkit(&player_item_mend_event_data.slot) - .unwrap_or(EquipmentSlot::MAIN_HAND); - let orb_uuid = player_item_mend_event_data - .orb_uuid - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()); - let pumpkin_event = PlayerItemMendEvent::new( - player, - item, - slot, - player_item_mend_event_data.repair_amount, - orb_uuid, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerLevelChange(player_level_change_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_level_change_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let pumpkin_event = PlayerLevelChangeEvent::new( - player, - player_level_change_event_data.old_level, - player_level_change_event_data.new_level, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerKick(player_kick_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_kick_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let reason = serde_json::from_str(&player_kick_event_data.reason) - .unwrap_or_else(|_| TextComponent::text(&player_kick_event_data.reason)); - let leave_message = serde_json::from_str(&player_kick_event_data.leave_message) - .unwrap_or_else(|_| TextComponent::text(&player_kick_event_data.leave_message)); - let cause = if player_kick_event_data.cause.is_empty() { - "UNKNOWN".to_string() - } else { - player_kick_event_data.cause - }; - let pumpkin_event = - PlayerKickEvent::new(player, reason, leave_message, cause); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerToggleSneak(player_toggle_sneak_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_toggle_sneak_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let pumpkin_event = PlayerToggleSneakEvent::new( - player, - player_toggle_sneak_event_data.is_sneaking, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerToggleSprint(player_toggle_sprint_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_toggle_sprint_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let pumpkin_event = PlayerToggleSprintEvent::new( - player, - player_toggle_sprint_event_data.is_sprinting, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerToggleFlight(player_toggle_flight_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_toggle_flight_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let pumpkin_event = PlayerToggleFlightEvent::new( - player, - player_toggle_flight_event_data.is_flying, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerSwapHandItems(player_swap_hand_items_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_swap_hand_items_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let main_key = if player_swap_hand_items_event_data.main_hand_item_key.is_empty() { - "minecraft:air" - } else { - player_swap_hand_items_event_data.main_hand_item_key.as_str() - }; - let off_key = if player_swap_hand_items_event_data.off_hand_item_key.is_empty() { - "minecraft:air" - } else { - player_swap_hand_items_event_data.off_hand_item_key.as_str() - }; - let main_item = item_stack_from_key( - main_key, - player_swap_hand_items_event_data.main_hand_item_amount, - ); - let off_item = item_stack_from_key( - off_key, - player_swap_hand_items_event_data.off_hand_item_amount, - ); - let pumpkin_event = PlayerSwapHandItemsEvent::new(player, main_item, off_item); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerResourcePackStatus(player_resource_pack_status_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_resource_pack_status_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let pack_uuid = player_resource_pack_status_event_data - .pack_uuid - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) - .unwrap_or_else(uuid::Uuid::new_v4); - let pumpkin_event = PlayerResourcePackStatusEvent::new( - player, - pack_uuid, - player_resource_pack_status_event_data.hash, - player_resource_pack_status_event_data.status, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerRespawn(player_respawn_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_respawn_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let (world_uuid, pos) = if let Some(loc) = player_respawn_event_data.respawn_location { - let world_uuid = loc - .world - .and_then(|w| w.uuid) - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) - .unwrap_or_else(|| player.world().uuid); - let pos = location_to_vec3(loc).unwrap_or_else(|| player.position()); - (world_uuid, pos) - } else { - (player.world().uuid, player.position()) - }; - let pumpkin_event = PlayerRespawnEvent::new( - player, - pos, - world_uuid, - player_respawn_event_data.is_bed_spawn, - player_respawn_event_data.is_anchor_spawn, - player_respawn_event_data.is_missing_respawn_block, - player_respawn_event_data.respawn_reason, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerPickupArrow(player_pickup_arrow_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_pickup_arrow_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let arrow_uuid = player_pickup_arrow_event_data - .arrow_uuid - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) - .unwrap_or_else(uuid::Uuid::new_v4); - let item_uuid = player_pickup_arrow_event_data - .item_uuid - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) - .unwrap_or_else(uuid::Uuid::new_v4); - let key = if player_pickup_arrow_event_data.item_key.is_empty() { - "minecraft:air" - } else { - player_pickup_arrow_event_data.item_key.as_str() - }; - let item = item_stack_from_key(key, player_pickup_arrow_event_data.item_amount); - let pumpkin_event = PlayerPickupArrowEvent::new( - player, - arrow_uuid, - item_uuid, - item, - player_pickup_arrow_event_data.remaining, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerPortal(player_portal_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_portal_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let (from_world_uuid, from_pos) = if let Some(loc) = player_portal_event_data.from { - let world_uuid = loc - .world - .and_then(|w| w.uuid) - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) - .unwrap_or_else(|| player.world().uuid); - let pos = location_to_vec3(loc).unwrap_or_else(|| player.position()); - (world_uuid, pos) - } else { - (player.world().uuid, player.position()) - }; - let (to_world_uuid, to_pos) = if let Some(loc) = player_portal_event_data.to { - let world_uuid = loc - .world - .and_then(|w| w.uuid) - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) - .unwrap_or_else(|| player.world().uuid); - let pos = location_to_vec3(loc).unwrap_or_else(|| player.position()); - (world_uuid, pos) - } else { - (player.world().uuid, player.position()) - }; - let cause = if player_portal_event_data.cause.is_empty() { - "UNKNOWN".to_string() - } else { - player_portal_event_data.cause - }; - let pumpkin_event = PlayerPortalEvent::new( - player, - from_pos, - from_world_uuid, - to_pos, - to_world_uuid, - cause, - player_portal_event_data.search_radius, - player_portal_event_data.can_create_portal, - player_portal_event_data.creation_radius, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerRecipeDiscover(player_recipe_discover_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_recipe_discover_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let pumpkin_event = PlayerRecipeDiscoverEvent::new( - player, - player_recipe_discover_event_data.recipe_key, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerRiptide(player_riptide_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_riptide_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let key = if player_riptide_event_data.item_key.is_empty() { - "minecraft:air" - } else { - player_riptide_event_data.item_key.as_str() - }; - let item = item_stack_from_key(key, player_riptide_event_data.item_amount); - let velocity = player_riptide_event_data - .velocity - .map(|v| Vector3::new(v.x, v.y, v.z)) - .unwrap_or_else(Vector3::default); - let pumpkin_event = PlayerRiptideEvent::new(player, item, velocity); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerShearEntity(player_shear_entity_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_shear_entity_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let entity_uuid = player_shear_entity_event_data - .entity_uuid - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) - .unwrap_or_else(uuid::Uuid::new_v4); - let key = if player_shear_entity_event_data.item_key.is_empty() { - "minecraft:air" - } else { - player_shear_entity_event_data.item_key.as_str() - }; - let item = item_stack_from_key(key, player_shear_entity_event_data.item_amount); - let hand = if player_shear_entity_event_data.hand.is_empty() { - "HAND".to_string() - } else { - player_shear_entity_event_data.hand - }; - let entity_type = player_shear_entity_event_data.entity_type; - let pumpkin_event = PlayerShearEntityEvent::new( - player, - entity_uuid, - entity_type, - item, - hand, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerSpawnLocation(player_spawn_location_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_spawn_location_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let (world_uuid, pos) = if let Some(loc) = player_spawn_location_event_data.spawn_location { - let world_uuid = loc - .world - .and_then(|w| w.uuid) - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) - .unwrap_or_else(|| player.world().uuid); - let pos = location_to_vec3(loc).unwrap_or_else(|| player.position()); - (world_uuid, pos) - } else { - (player.world().uuid, player.position()) - }; - let pumpkin_event = PlayerSpawnLocationEvent::new(player, pos, world_uuid); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerStatisticIncrement(player_statistic_increment_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_statistic_increment_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let pumpkin_event = PlayerStatisticIncrementEvent::new( - player, - player_statistic_increment_event_data.statistic, - player_statistic_increment_event_data.initial_value, - player_statistic_increment_event_data.new_value, - player_statistic_increment_event_data.entity_type, - player_statistic_increment_event_data.material_key, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerVelocity(player_velocity_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_velocity_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let velocity = player_velocity_event_data - .velocity - .map(|v| Vector3::new(v.x, v.y, v.z)) - .unwrap_or_else(Vector3::default); - let pumpkin_event = PlayerVelocityEvent::new(player, velocity); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerHarvestBlock(player_harvest_block_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_harvest_block_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let (world_uuid, pos) = - if let Some(loc) = player_harvest_block_event_data.block_location { - let world_uuid = loc - .world - .and_then(|w| w.uuid) - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) - .unwrap_or_else(|| player.world().uuid); - let pos = location_to_vec3(loc).unwrap_or_else(|| player.position()); - (world_uuid, pos) - } else { - (player.world().uuid, player.position()) - }; - let block_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - let key = if player_harvest_block_event_data.item_key.is_empty() { - "minecraft:air" - } else { - player_harvest_block_event_data.item_key.as_str() - }; - let item = item_stack_from_key( - key, - player_harvest_block_event_data.item_amount, - ); - let block_key = if player_harvest_block_event_data.block_key.is_empty() { - "minecraft:air".to_string() - } else { - player_harvest_block_event_data.block_key - }; - let pumpkin_event = PlayerHarvestBlockEvent::new( - player, - block_pos, - block_key, - item, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerInteract(player_interact_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_interact_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let action = match player_interact_event_data.action.as_str() { - "LEFT_CLICK_BLOCK" => InteractAction::LeftClickBlock, - "LEFT_CLICK_AIR" => InteractAction::LeftClickAir, - "RIGHT_CLICK_BLOCK" => InteractAction::RightClickBlock, - "RIGHT_CLICK_AIR" => InteractAction::RightClickAir, - _ => InteractAction::RightClickAir, - }; - - let clicked_pos = player_interact_event_data - .clicked - .and_then(|loc| loc.position) - .map(|pos| { - pumpkin_util::math::position::BlockPos::new( - pos.x as i32, - pos.y as i32, - pos.z as i32, - ) - }); - - let block = block_from_key(&player_interact_event_data.block_key); - let item = Arc::new(Mutex::new(item_from_key( - &player_interact_event_data.item_key, - ))); - let face = bukkit_block_face_to_direction( - &player_interact_event_data.block_face, - ); - - let pumpkin_event = PlayerInteractEvent::new( - &player, - action, - &item, - player_interact_event_data.item_key, - block, - clicked_pos, - face, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::BlockBreak(block_break_event_data) => { - let uuid = uuid::Uuid::parse_str(&block_break_event_data.player_uuid?.value) - .ok()?; - let player = context.server.get_player_by_uuid(uuid); - let block = block_from_key(&block_break_event_data.block_key); - let position = block_break_event_data - .location - .and_then(|loc| loc.position) - .map(|pos| { - pumpkin_util::math::position::BlockPos::new( - pos.x as i32, - pos.y as i32, - pos.z as i32, - ) - }) - .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); - - let pumpkin_event = BlockBreakEvent::new( - player, - block, - position, - block_break_event_data.exp, - block_break_event_data.drop, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::BlockDamage(block_damage_event_data) => { - let uuid = uuid::Uuid::parse_str(&block_damage_event_data.player_uuid?.value) - .ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let block = block_from_key(&block_damage_event_data.block_key); - let position = block_damage_event_data - .location - .and_then(|loc| loc.position) - .map(|pos| { - pumpkin_util::math::position::BlockPos::new( - pos.x as i32, - pos.y as i32, - pos.z as i32, - ) - }) - .unwrap_or_else(|| player.position().to_block_pos()); - let key = if block_damage_event_data.item_key.is_empty() { - "minecraft:air" - } else { - block_damage_event_data.item_key.as_str() - }; - let item_stack = item_stack_from_key(key, 1); - let pumpkin_event = BlockDamageEvent::new( - player, - block, - position, - item_stack, - block_damage_event_data.insta_break, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::BlockDamageAbort(block_damage_abort_event_data) => { - let uuid = uuid::Uuid::parse_str(&block_damage_abort_event_data.player_uuid?.value) - .ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let block = block_from_key(&block_damage_abort_event_data.block_key); - let position = block_damage_abort_event_data - .location - .and_then(|loc| loc.position) - .map(|pos| { - pumpkin_util::math::position::BlockPos::new( - pos.x as i32, - pos.y as i32, - pos.z as i32, - ) - }) - .unwrap_or_else(|| player.position().to_block_pos()); - let key = if block_damage_abort_event_data.item_key.is_empty() { - "minecraft:air" - } else { - block_damage_abort_event_data.item_key.as_str() - }; - let item_stack = item_stack_from_key(key, 1); - let pumpkin_event = - BlockDamageAbortEvent::new(player, block, position, item_stack); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::BlockDispense(block_dispense_event_data) => { - let block = block_from_key(&block_dispense_event_data.block_key); - let position = block_dispense_event_data - .location - .and_then(|loc| loc.position) - .map(|pos| { - pumpkin_util::math::position::BlockPos::new( - pos.x as i32, - pos.y as i32, - pos.z as i32, - ) - }) - .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); - let key = if block_dispense_event_data.item_key.is_empty() { - "minecraft:air" - } else { - block_dispense_event_data.item_key.as_str() - }; - let item_stack = - item_stack_from_key(key, block_dispense_event_data.item_amount); - let velocity = block_dispense_event_data - .velocity - .map(|v| Vector3::new(v.x, v.y, v.z)) - .unwrap_or_else(|| Vector3::new(0.0, 0.0, 0.0)); - let pumpkin_event = - BlockDispenseEvent::new(block, position, item_stack, velocity); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::BlockDropItem(block_drop_item_event_data) => { - let uuid = uuid::Uuid::parse_str(&block_drop_item_event_data.player_uuid?.value) - .ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let block = block_from_key(&block_drop_item_event_data.block_key); - let position = block_drop_item_event_data - .location - .and_then(|loc| loc.position) - .map(|pos| { - pumpkin_util::math::position::BlockPos::new( - pos.x as i32, - pos.y as i32, - pos.z as i32, - ) - }) - .unwrap_or_else(|| player.position().to_block_pos()); - let mut items = Vec::new(); - for entry in block_drop_item_event_data.items { - if entry.item_key.is_empty() && entry.item_amount <= 0 { - continue; - } - let key = if entry.item_key.is_empty() { - "minecraft:air" - } else { - entry.item_key.as_str() - }; - let stack = item_stack_from_key(key, entry.item_amount); - if !stack.is_empty() { - items.push(stack); - } - } - let pumpkin_event = BlockDropItemEvent::new(player, block, position, items); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::BlockExplode(block_explode_event_data) => { - let block = block_from_key(&block_explode_event_data.block_key); - let position = block_explode_event_data - .location - .and_then(|loc| loc.position) - .map(|pos| { - pumpkin_util::math::position::BlockPos::new( - pos.x as i32, - pos.y as i32, - pos.z as i32, - ) - }) - .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); - let world_uuid = block_explode_event_data - .location - .and_then(|loc| loc.world) - .and_then(|w| w.uuid) - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) - .unwrap_or_else(|| { - context - .server - .worlds - .load() - .first() - .map(|world| world.uuid) - .unwrap_or_default() - }); - let mut blocks = Vec::new(); - for entry in block_explode_event_data.blocks { - if let Some(loc) = entry.location - && let Some(pos) = location_to_vec3(loc.clone()) - { - blocks.push(pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - )); - } - } - let pumpkin_event = BlockExplodeEvent::new( - block, - position, - world_uuid, - blocks, - block_explode_event_data.yield_, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::BlockFade(block_fade_event_data) => { - let block = block_from_key(&block_fade_event_data.block_key); - let new_block = block_from_key(&block_fade_event_data.new_block_key); - let position = block_fade_event_data + Data::BlockBreak(event) => { + let player = event + .player_uuid + .and_then(|id| uuid::Uuid::parse_str(&id.value).ok()) + .and_then(|id| ctx.plugin_context.server.get_player_by_uuid(id)); + let block = block_from_key(&event.block_key); + let position = event .location .and_then(|loc| loc.position) .map(|pos| { @@ -2762,632 +484,83 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { - let uuid = uuid::Uuid::parse_str(&block_fertilize_event_data.player_uuid?.value) - .ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let block = block_from_key(&block_fertilize_event_data.block_key); - let position = block_fertilize_event_data - .location - .and_then(|loc| loc.position) - .map(|pos| { - pumpkin_util::math::position::BlockPos::new( - pos.x as i32, - pos.y as i32, - pos.z as i32, - ) - }) - .unwrap_or_else(|| player.position().to_block_pos()); - let mut blocks = Vec::new(); - for entry in block_fertilize_event_data.blocks { - if let Some(loc) = entry.location - && let Some(pos) = location_to_vec3(loc.clone()) - { - blocks.push(pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - )); - } - } let pumpkin_event = - BlockFertilizeEvent::new(player, block, position, blocks); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::BlockForm(block_form_event_data) => { - let old_block = block_from_key(&block_form_event_data.block_key); - let new_block = block_from_key(&block_form_event_data.new_block_key); - let position = block_form_event_data - .location - .and_then(|loc| loc.position) - .map(|pos| { - pumpkin_util::math::position::BlockPos::new( - pos.x as i32, - pos.y as i32, - pos.z as i32, - ) - }) - .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); - let world_uuid = block_form_event_data - .location - .and_then(|loc| loc.world) - .and_then(|w| w.uuid) - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) - .unwrap_or_else(|| { - context - .server - .worlds - .load() - .first() - .map(|world| world.uuid) - .unwrap_or_default() - }); - let pumpkin_event = BlockFormEvent::new(old_block, new_block, position, world_uuid); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::BlockFromTo(block_from_to_event_data) => { - let block = block_from_key(&block_from_to_event_data.block_key); - let to_block = block_from_key(&block_from_to_event_data.to_block_key); - let position = block_from_to_event_data - .location - .and_then(|loc| loc.position) - .map(|pos| { - pumpkin_util::math::position::BlockPos::new( - pos.x as i32, - pos.y as i32, - pos.z as i32, - ) - }) - .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); - let to_position = block_from_to_event_data - .to_location - .and_then(|loc| loc.position) - .map(|pos| { - pumpkin_util::math::position::BlockPos::new( - pos.x as i32, - pos.y as i32, - pos.z as i32, - ) - }) - .unwrap_or_else(|| position); - let world_uuid = block_from_to_event_data - .location - .and_then(|loc| loc.world) - .and_then(|w| w.uuid) - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) - .unwrap_or_else(|| { - context - .server - .worlds - .load() - .first() - .map(|world| world.uuid) - .unwrap_or_default() - }); - let face = - bukkit_block_face_to_direction(&block_from_to_event_data.face).unwrap_or( - BlockDirection::Down, + pumpkin::plugin::api::events::block::block_break::BlockBreakEvent::new( + player, + block, + position, + event.exp, + event.drop, ); - let pumpkin_event = BlockFromToEvent::new( - block, - position, - to_block, - to_position, - face, - world_uuid, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::BlockGrow(block_grow_event_data) => { - let block = block_from_key(&block_grow_event_data.block_key); - let new_block = block_from_key(&block_grow_event_data.new_block_key); - let position = block_grow_event_data - .location - .and_then(|loc| loc.position) - .map(|pos| { - pumpkin_util::math::position::BlockPos::new( - pos.x as i32, - pos.y as i32, - pos.z as i32, - ) - }) - .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); - let world_uuid = block_grow_event_data - .location - .and_then(|loc| loc.world) - .and_then(|w| w.uuid) - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) - .unwrap_or_else(|| { - context - .server - .worlds - .load() - .first() - .map(|world| world.uuid) - .unwrap_or_default() - }); - let pumpkin_event = BlockGrowEvent::new(block, new_block, position, world_uuid); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::BlockPistonExtend(block_piston_extend_event_data) => { - let block = block_from_key(&block_piston_extend_event_data.block_key); - let position = block_piston_extend_event_data - .location - .and_then(|loc| loc.position) - .map(|pos| { - pumpkin_util::math::position::BlockPos::new( - pos.x as i32, - pos.y as i32, - pos.z as i32, - ) - }) - .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); - let world_uuid = block_piston_extend_event_data - .location - .and_then(|loc| loc.world) - .and_then(|w| w.uuid) - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) - .unwrap_or_else(|| { - context - .server - .worlds - .load() - .first() - .map(|world| world.uuid) - .unwrap_or_default() - }); - let face = - bukkit_block_face_to_direction(&block_piston_extend_event_data.direction) - .unwrap_or(BlockDirection::Down); - let mut blocks = Vec::new(); - for entry in block_piston_extend_event_data.blocks { - if let Some(loc) = entry.location - && let Some(pos) = location_to_vec3(loc.clone()) - { - blocks.push(pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - )); - } - } - let pumpkin_event = BlockPistonExtendEvent::new( - block, - position, - face, - block_piston_extend_event_data.length, - blocks, - world_uuid, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::BlockPistonRetract(block_piston_retract_event_data) => { - let block = block_from_key(&block_piston_retract_event_data.block_key); - let position = block_piston_retract_event_data - .location - .and_then(|loc| loc.position) - .map(|pos| { - pumpkin_util::math::position::BlockPos::new( - pos.x as i32, - pos.y as i32, - pos.z as i32, - ) - }) - .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); - let world_uuid = block_piston_retract_event_data - .location - .and_then(|loc| loc.world) - .and_then(|w| w.uuid) - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) - .unwrap_or_else(|| { - context - .server - .worlds - .load() - .first() - .map(|world| world.uuid) - .unwrap_or_default() - }); - let face = - bukkit_block_face_to_direction(&block_piston_retract_event_data.direction) - .unwrap_or(BlockDirection::Down); - let mut blocks = Vec::new(); - for entry in block_piston_retract_event_data.blocks { - if let Some(loc) = entry.location - && let Some(pos) = location_to_vec3(loc.clone()) - { - blocks.push(pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - )); - } - } - let pumpkin_event = BlockPistonRetractEvent::new( - block, - position, - face, - block_piston_retract_event_data.length, - blocks, - world_uuid, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::BlockRedstone(block_redstone_event_data) => { - let block = block_from_key(&block_redstone_event_data.block_key); - let position = block_redstone_event_data - .location - .and_then(|loc| loc.position) - .map(|pos| { - pumpkin_util::math::position::BlockPos::new( - pos.x as i32, - pos.y as i32, - pos.z as i32, - ) - }) - .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); - let pumpkin_event = BlockRedstoneEvent::new( - block, - position, - block_redstone_event_data.old_current, - block_redstone_event_data.new_current, - ); - context.server.plugin_manager.fire(pumpkin_event).await; + ctx.plugin_context.server.plugin_manager.fire(pumpkin_event).await; Some(true) } - Data::BlockMultiPlace(block_multi_place_event_data) => { - let uuid = uuid::Uuid::parse_str(&block_multi_place_event_data.player_uuid?.value) - .ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let block = block_from_key(&block_multi_place_event_data.block_key); - let mut positions = Vec::new(); - for entry in block_multi_place_event_data.blocks { - if let Some(loc) = entry.location - && let Some(pos) = location_to_vec3(loc.clone()) - { - positions.push(pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - )); - } - } + Data::BlockBurn(event) => { + let block = block_from_key(&event.block_key); + let igniting_block = block_from_key(&event.igniting_block_key); let pumpkin_event = - BlockMultiPlaceEvent::new(player, block, positions); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::BlockPhysics(block_physics_event_data) => { - let block = block_from_key(&block_physics_event_data.block_key); - let source_block = block_from_key(&block_physics_event_data.source_block_key); - let position = block_physics_event_data - .location - .and_then(|loc| loc.position) - .map(|pos| { - pumpkin_util::math::position::BlockPos::new( - pos.x as i32, - pos.y as i32, - pos.z as i32, - ) - }) - .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); - let source_pos = block_physics_event_data - .source_location - .and_then(|loc| loc.position) - .map(|pos| { - pumpkin_util::math::position::BlockPos::new( - pos.x as i32, - pos.y as i32, - pos.z as i32, - ) - }) - .unwrap_or_else(|| position); - let world_uuid = block_physics_event_data - .location - .and_then(|loc| loc.world) - .and_then(|w| w.uuid) - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) - .unwrap_or_else(|| { - context - .server - .worlds - .load() - .first() - .map(|world| world.uuid) - .unwrap_or_default() - }); - let pumpkin_event = BlockPhysicsEvent::new( - block, - position, - source_block, - source_pos, - world_uuid, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::BlockPlace(block_place_event_data) => { - let uuid = uuid::Uuid::parse_str(&block_place_event_data.player_uuid?.value) - .ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let block = block_from_key(&block_place_event_data.block_key); - let against = block_from_key(&block_place_event_data.block_against_key); - let position = block_place_event_data - .location - .and_then(|loc| loc.position) - .map(|pos| { - pumpkin_util::math::position::BlockPos::new( - pos.x as i32, - pos.y as i32, - pos.z as i32, - ) - }) - .unwrap_or_else(|| player.position().to_block_pos()); - - let pumpkin_event = BlockPlaceEvent { - player, - block_placed: block, - block_placed_against: against, - position, - can_build: block_place_event_data.can_build, - cancelled: false, - }; - - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::BlockCanBuild(block_can_build_event_data) => { - let uuid = - uuid::Uuid::parse_str(&block_can_build_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let block_to_build = block_from_key(&block_can_build_event_data.block_key); - let block_against = block_from_key(&block_can_build_event_data.block_against_key); - let position = block_can_build_event_data - .location - .and_then(|loc| loc.position) - .map(|pos| { - pumpkin_util::math::position::BlockPos::new( - pos.x as i32, - pos.y as i32, - pos.z as i32, - ) - }) - .unwrap_or_else(|| player.position().to_block_pos()); - let pumpkin_event = BlockCanBuildEvent { - player, - block_to_build, - buildable: block_can_build_event_data.can_build, - block: block_against, - block_pos: position, - cancelled: false, - }; - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::BlockBurn(block_burn_event_data) => { - let block = block_from_key(&block_burn_event_data.block_key); - let igniting_block = - block_from_key(&block_burn_event_data.igniting_block_key); - let (world_uuid, pos) = if let Some(loc) = block_burn_event_data.location { - let world_uuid = loc - .world - .and_then(|w| w.uuid) - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) - .unwrap_or_else(|| { - context - .server - .worlds - .load() - .first() - .map(|w| w.uuid) - .unwrap_or_else(uuid::Uuid::new_v4) - }); - let pos = location_to_vec3(loc).unwrap_or_else(Vector3::default); - (world_uuid, pos) - } else { - ( - context - .server - .worlds - .load() - .first() - .map(|w| w.uuid) - .unwrap_or_else(uuid::Uuid::new_v4), - Vector3::default(), - ) - }; - let block_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - let pumpkin_event = BlockBurnEvent { - igniting_block, - block, - block_pos, - world_uuid, - cancelled: false, - }; - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::BlockIgnite(block_ignite_event_data) => { - let uuid = - uuid::Uuid::parse_str(&block_ignite_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let block = block_from_key(&block_ignite_event_data.block_key); - let igniting_block = - block_from_key(&block_ignite_event_data.igniting_block_key); - let (world_uuid, pos) = if let Some(loc) = block_ignite_event_data.location { - let world_uuid = loc - .world - .and_then(|w| w.uuid) - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) - .unwrap_or_else(|| player.world().uuid); - let pos = location_to_vec3(loc).unwrap_or_else(Vector3::default); - (world_uuid, pos) - } else { - (player.world().uuid, Vector3::default()) - }; - let block_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - let cause = if block_ignite_event_data.cause.is_empty() { - "UNKNOWN".to_string() - } else { - block_ignite_event_data.cause - }; - let pumpkin_event = BlockIgniteEvent { - player, - block, - igniting_block, - block_pos, - world_uuid, - cause, - cancelled: false, - }; - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::BlockSpread(block_spread_event_data) => { - let source_block = block_from_key(&block_spread_event_data.source_block_key); - let block = block_from_key(&block_spread_event_data.block_key); - let (world_uuid, source_pos) = - if let Some(loc) = block_spread_event_data.source_location { - let world_uuid = loc - .world - .and_then(|w| w.uuid) - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) - .unwrap_or_else(|| { - context - .server - .worlds - .load() - .first() - .map(|w| w.uuid) - .unwrap_or_else(uuid::Uuid::new_v4) - }); - let pos = location_to_vec3(loc).unwrap_or_else(Vector3::default); - ( - world_uuid, - pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ), - ) - } else { - ( - context - .server - .worlds - .load() - .first() - .map(|w| w.uuid) - .unwrap_or_else(uuid::Uuid::new_v4), - pumpkin_util::math::position::BlockPos::new(0, 0, 0), - ) + pumpkin::plugin::api::events::block::block_burn::BlockBurnEvent { + igniting_block, + block, + cancelled: false, }; - let block_pos = if let Some(loc) = block_spread_event_data.location { - let pos = location_to_vec3(loc).unwrap_or_else(Vector3::default); - pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ) - } else { - source_pos - }; - let pumpkin_event = BlockSpreadEvent { - source_block, - source_pos, - block, - block_pos, - world_uuid, - cancelled: false, - }; - context.server.plugin_manager.fire(pumpkin_event).await; + ctx.plugin_context.server.plugin_manager.fire(pumpkin_event).await; Some(true) } - Data::EntitySpawn(entity_spawn_event_data) => { - let uuid = uuid::Uuid::parse_str(&entity_spawn_event_data.entity_uuid?.value) - .ok()?; + Data::BlockCanBuild(event) => { + let uuid = uuid::Uuid::parse_str(&event.player_uuid?.value).ok()?; + let player = ctx.plugin_context.server.get_player_by_uuid(uuid)?; + let block_to_build = block_from_key(&event.block_key); + let block_against = block_from_key(&event.block_against_key); let pumpkin_event = - pumpkin::plugin::entity::entity_spawn::EntitySpawnEvent::new( - uuid, - &pumpkin_data::entity::EntityType::PLAYER, - ); - context.server.plugin_manager.fire(pumpkin_event).await; + pumpkin::plugin::api::events::block::block_can_build::BlockCanBuildEvent { + block_to_build, + buildable: event.can_build, + player, + block: block_against, + cancelled: false, + }; + ctx.plugin_context.server.plugin_manager.fire(pumpkin_event).await; Some(true) } - Data::EntityDamage(entity_damage_event_data) => { - let uuid = uuid::Uuid::parse_str(&entity_damage_event_data.entity_uuid?.value) - .ok()?; + Data::BlockPlace(event) => { + let uuid = uuid::Uuid::parse_str(&event.player_uuid?.value).ok()?; + let player = ctx.plugin_context.server.get_player_by_uuid(uuid)?; + let block = block_from_key(&event.block_key); + let against = block_from_key(&event.block_against_key); let pumpkin_event = - pumpkin::plugin::entity::entity_damage::EntityDamageEvent::new( - uuid, - entity_damage_event_data.damage, - pumpkin_data::damage::DamageType::GENERIC, - ); - context.server.plugin_manager.fire(pumpkin_event).await; + pumpkin::plugin::api::events::block::block_place::BlockPlaceEvent { + player, + block_placed: block, + block_placed_against: against, + can_build: event.can_build, + cancelled: false, + }; + ctx.plugin_context.server.plugin_manager.fire(pumpkin_event).await; Some(true) } - Data::EntityDeath(entity_death_event_data) => { - let uuid = uuid::Uuid::parse_str(&entity_death_event_data.entity_uuid?.value) - .ok()?; + Data::ServerCommand(event) => { let pumpkin_event = - pumpkin::plugin::entity::entity_death::EntityDeathEvent::new( - uuid, - pumpkin_data::damage::DamageType::GENERIC, + pumpkin::plugin::api::events::server::server_command::ServerCommandEvent::new( + event.command, ); - context.server.plugin_manager.fire(pumpkin_event).await; + ctx.plugin_context.server.plugin_manager.fire(pumpkin_event).await; Some(true) } - Data::ServerCommand(server_command_event_data) => { + Data::ServerBroadcast(event) => { + let message = serde_json::from_str(&event.message) + .unwrap_or_else(|_| TextComponent::from_legacy_string(&event.message)); + let sender = serde_json::from_str(&event.sender) + .unwrap_or_else(|_| TextComponent::from_legacy_string(&event.sender)); let pumpkin_event = - ServerCommandEvent::new(server_command_event_data.command); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::ServerBroadcast(server_broadcast_event_data) => { - let message = serde_json::from_str(&server_broadcast_event_data.message) - .unwrap_or_else(|_| { - TextComponent::from_legacy_string(&server_broadcast_event_data.message) - }); - let sender = serde_json::from_str(&server_broadcast_event_data.sender) - .unwrap_or_else(|_| { - TextComponent::from_legacy_string(&server_broadcast_event_data.sender) - }); - let pumpkin_event = ServerBroadcastEvent::new(message, sender); - context.server.plugin_manager.fire(pumpkin_event).await; + pumpkin::plugin::api::events::server::server_broadcast::ServerBroadcastEvent::new( + message, + sender, + ); + ctx.plugin_context.server.plugin_manager.fire(pumpkin_event).await; Some(true) } + _ => Some(false), } }) })?; @@ -3400,12 +573,6 @@ fn block_from_key(key: &str) -> &'static Block { Block::from_registry_key(trimmed).unwrap_or(&Block::AIR) } -fn item_from_key(key: &str) -> ItemStack { - let trimmed = key.strip_prefix("minecraft:").unwrap_or(key); - let item = Item::from_registry_key(trimmed).unwrap_or(&Item::AIR); - ItemStack::new(1, item) -} - fn item_stack_from_key(key: &str, amount: i32) -> ItemStack { let trimmed = key.strip_prefix("minecraft:").unwrap_or(key); let item = Item::from_registry_key(trimmed).unwrap_or(&Item::AIR); @@ -3413,30 +580,9 @@ fn item_stack_from_key(key: &str, amount: i32) -> ItemStack { ItemStack::new(count, item) } -fn equipment_slot_from_bukkit(slot: &str) -> Option { - match slot { - "HAND" => Some(EquipmentSlot::MAIN_HAND), - "OFF_HAND" => Some(EquipmentSlot::OFF_HAND), - "FEET" => Some(EquipmentSlot::FEET), - "LEGS" => Some(EquipmentSlot::LEGS), - "CHEST" => Some(EquipmentSlot::CHEST), - "HEAD" => Some(EquipmentSlot::HEAD), - "BODY" => Some(EquipmentSlot::BODY), - "SADDLE" => Some(EquipmentSlot::SADDLE), - _ => None, - } -} - -fn bukkit_block_face_to_direction(face: &str) -> Option { - match face { - "UP" => Some(BlockDirection::Up), - "DOWN" => Some(BlockDirection::Down), - "NORTH" => Some(BlockDirection::North), - "SOUTH" => Some(BlockDirection::South), - "WEST" => Some(BlockDirection::West), - "EAST" => Some(BlockDirection::East), - _ => None, - } +fn location_to_vec3(location: crate::proto::patchbukkit::common::Location) -> Option> { + let pos = location.position?; + Some(Vector3::new(pos.x, pos.y, pos.z)) } fn gamemode_from_bukkit(mode: &str) -> Option { @@ -3449,10 +595,15 @@ fn gamemode_from_bukkit(mode: &str) -> Option { } } -fn main_hand_from_bukkit(hand: &str) -> Option { - match hand { - "LEFT" => Some(Hand::Left), - "RIGHT" => Some(Hand::Right), - _ => None, - } +fn find_world_by_uuid( + server: &std::sync::Arc, + world_uuid: uuid::Uuid, +) -> Option> { + server + .worlds + .load() + .iter() + .find(|world| world.uuid == world_uuid) + .cloned() } + diff --git a/rust/src/java/native_callbacks/events_legacy.rs b/rust/src/java/native_callbacks/events_legacy.rs new file mode 100644 index 0000000..48f0963 --- /dev/null +++ b/rust/src/java/native_callbacks/events_legacy.rs @@ -0,0 +1,3458 @@ +use std::sync::Arc; + +use pumpkin::plugin::EventPriority; +use pumpkin::plugin::block::block_break::BlockBreakEvent; +use pumpkin::plugin::block::block_damage::BlockDamageEvent; +use pumpkin::plugin::block::block_damage_abort::BlockDamageAbortEvent; +use pumpkin::plugin::block::block_dispense::BlockDispenseEvent; +use pumpkin::plugin::block::block_drop_item::BlockDropItemEvent; +use pumpkin::plugin::block::block_explode::BlockExplodeEvent; +use pumpkin::plugin::block::block_fade::BlockFadeEvent; +use pumpkin::plugin::block::block_fertilize::BlockFertilizeEvent; +use pumpkin::plugin::block::block_form::BlockFormEvent; +use pumpkin::plugin::block::block_from_to::BlockFromToEvent; +use pumpkin::plugin::block::block_grow::BlockGrowEvent; +use pumpkin::plugin::block::block_piston_extend::BlockPistonExtendEvent; +use pumpkin::plugin::block::block_piston_retract::BlockPistonRetractEvent; +use pumpkin::plugin::block::block_redstone::BlockRedstoneEvent; +use pumpkin::plugin::block::block_multi_place::BlockMultiPlaceEvent; +use pumpkin::plugin::block::block_physics::BlockPhysicsEvent; +use pumpkin::plugin::block::block_place::BlockPlaceEvent; +use pumpkin::plugin::block::block_can_build::BlockCanBuildEvent; +use pumpkin::plugin::block::block_burn::BlockBurnEvent; +use pumpkin::plugin::block::block_ignite::BlockIgniteEvent; +use pumpkin::plugin::block::block_spread::BlockSpreadEvent; +use pumpkin::plugin::player::player_chat::PlayerChatEvent; +use pumpkin::plugin::player::player_command_preprocess::PlayerCommandPreprocessEvent; +use pumpkin::plugin::player::player_command_send::PlayerCommandSendEvent; +use pumpkin::plugin::player::player_drop_item::PlayerDropItemEvent; +use pumpkin::plugin::player::player_edit_book::PlayerEditBookEvent; +use pumpkin::plugin::player::player_egg_throw::PlayerEggThrowEvent; +use pumpkin::plugin::player::player_exp_change::PlayerExpChangeEvent; +use pumpkin::plugin::player::player_fish::PlayerFishEvent; +use pumpkin::plugin::player::player_interact_entity::PlayerInteractEntityEvent; +use pumpkin::plugin::player::player_interact_at_entity::PlayerInteractAtEntityEvent; +use pumpkin::plugin::player::player_item_held::PlayerItemHeldEvent; +use pumpkin::plugin::player::player_item_damage::PlayerItemDamageEvent; +use pumpkin::plugin::player::player_item_break::PlayerItemBreakEvent; +use pumpkin::plugin::player::player_item_consume::PlayerItemConsumeEvent; +use pumpkin::plugin::player::player_item_mend::PlayerItemMendEvent; +use pumpkin::plugin::player::player_level_change::PlayerLevelChangeEvent; +use pumpkin::plugin::player::player_kick::PlayerKickEvent; +use pumpkin::plugin::player::player_toggle_sneak::PlayerToggleSneakEvent; +use pumpkin::plugin::player::player_toggle_sprint::PlayerToggleSprintEvent; +use pumpkin::plugin::player::player_toggle_flight::PlayerToggleFlightEvent; +use pumpkin::plugin::player::player_swap_hand_items::PlayerSwapHandItemsEvent; +use pumpkin::plugin::player::player_resource_pack_status::PlayerResourcePackStatusEvent; +use pumpkin::plugin::player::player_respawn::PlayerRespawnEvent; +use pumpkin::plugin::player::player_pickup_arrow::PlayerPickupArrowEvent; +use pumpkin::plugin::player::player_portal::PlayerPortalEvent; +use pumpkin::plugin::player::player_recipe_discover::PlayerRecipeDiscoverEvent; +use pumpkin::plugin::player::player_riptide::PlayerRiptideEvent; +use pumpkin::plugin::player::player_shear_entity::PlayerShearEntityEvent; +use pumpkin::plugin::player::player_spawn_location::PlayerSpawnLocationEvent; +use pumpkin::plugin::player::player_statistic_increment::PlayerStatisticIncrementEvent; +use pumpkin::plugin::player::player_velocity::PlayerVelocityEvent; +use pumpkin::plugin::player::player_harvest_block::PlayerHarvestBlockEvent; +use pumpkin::plugin::player::player_interact_event::{InteractAction, PlayerInteractEvent}; +use pumpkin::plugin::player::player_join::PlayerJoinEvent; +use pumpkin::plugin::player::player_login::PlayerLoginEvent; +use pumpkin::plugin::player::player_pre_login::PlayerPreLoginEvent; +use pumpkin::plugin::player::player_advancement_done::PlayerAdvancementDoneEvent; +use pumpkin::plugin::player::player_animation::PlayerAnimationEvent; +use pumpkin::plugin::player::player_armor_stand_manipulate::PlayerArmorStandManipulateEvent; +use pumpkin::plugin::player::player_bed_enter::PlayerBedEnterEvent; +use pumpkin::plugin::player::player_bed_leave::PlayerBedLeaveEvent; +use pumpkin::plugin::player::player_bucket_empty::PlayerBucketEmptyEvent; +use pumpkin::plugin::player::player_bucket_fill::PlayerBucketFillEvent; +use pumpkin::plugin::player::player_bucket_entity::PlayerBucketEntityEvent; +use pumpkin::plugin::player::player_changed_main_hand::PlayerChangedMainHandEvent; +use pumpkin::plugin::player::player_register_channel::PlayerRegisterChannelEvent; +use pumpkin::plugin::player::player_unregister_channel::PlayerUnregisterChannelEvent; +use pumpkin::plugin::player::player_leave::PlayerLeaveEvent; +use pumpkin::plugin::player::player_move::PlayerMoveEvent; +use pumpkin::plugin::player::player_teleport::PlayerTeleportEvent; +use pumpkin::plugin::player::player_change_world::PlayerChangeWorldEvent; +use pumpkin::plugin::player::player_gamemode_change::PlayerGamemodeChangeEvent; +use pumpkin::plugin::server::server_broadcast::ServerBroadcastEvent; +use pumpkin::plugin::server::server_command::ServerCommandEvent; +use pumpkin_data::Block; +use pumpkin_data::BlockDirection; +use pumpkin_data::data_component_impl::EquipmentSlot; +use pumpkin_data::item::Item; +use pumpkin_world::item::ItemStack; +use pumpkin_util::math::vector3::Vector3; +use pumpkin_util::text::TextComponent; +use pumpkin_util::Hand; +use tokio::sync::Mutex; + +use crate::events::handler::PatchBukkitEventHandler; +use crate::java::native_callbacks::CALLBACK_CONTEXT; +use crate::proto::patchbukkit::events::event::Data; +use crate::proto::patchbukkit::events::{ + CallEventRequest, CallEventResponse, RegisterEventRequest, +}; + +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, + 3 => EventPriority::High, + _ => EventPriority::Highest, + }; + + log::info!( + "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(); + + tokio::task::block_in_place(|| { + ctx.runtime.block_on(async { + match request.event_type.as_str() { + "org.bukkit.event.player.PlayerJoinEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_join::PlayerJoinEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerLoginEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_login::PlayerLoginEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.AsyncPlayerPreLoginEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_pre_login::PlayerPreLoginEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerQuitEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_leave::PlayerLeaveEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerMoveEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_move::PlayerMoveEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerAdvancementDoneEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_advancement_done::PlayerAdvancementDoneEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_advancement_done::PlayerAdvancementDoneEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerAnimationEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_animation::PlayerAnimationEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_animation::PlayerAnimationEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerArmorStandManipulateEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_armor_stand_manipulate::PlayerArmorStandManipulateEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_armor_stand_manipulate::PlayerArmorStandManipulateEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerBedEnterEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_bed_enter::PlayerBedEnterEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_bed_enter::PlayerBedEnterEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerBedLeaveEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_bed_leave::PlayerBedLeaveEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_bed_leave::PlayerBedLeaveEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerBucketEmptyEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_bucket_empty::PlayerBucketEmptyEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_bucket_empty::PlayerBucketEmptyEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerBucketFillEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_bucket_fill::PlayerBucketFillEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_bucket_fill::PlayerBucketFillEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerBucketEntityEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_bucket_entity::PlayerBucketEntityEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_bucket_entity::PlayerBucketEntityEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerChangedMainHandEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_changed_main_hand::PlayerChangedMainHandEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_changed_main_hand::PlayerChangedMainHandEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerRegisterChannelEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_register_channel::PlayerRegisterChannelEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_register_channel::PlayerRegisterChannelEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerUnregisterChannelEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_unregister_channel::PlayerUnregisterChannelEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_unregister_channel::PlayerUnregisterChannelEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerTeleportEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_teleport::PlayerTeleportEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerChangedWorldEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_change_world::PlayerChangeWorldEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_change_world::PlayerChangeWorldEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerGameModeChangeEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_gamemode_change::PlayerGamemodeChangeEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_gamemode_change::PlayerGamemodeChangeEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.AsyncPlayerChatEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_chat::PlayerChatEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerCommandPreprocessEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_command_preprocess::PlayerCommandPreprocessEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_command_preprocess::PlayerCommandPreprocessEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerCommandSendEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_command_send::PlayerCommandSendEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_command_send::PlayerCommandSendEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerDropItemEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_drop_item::PlayerDropItemEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_drop_item::PlayerDropItemEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerEditBookEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_edit_book::PlayerEditBookEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_edit_book::PlayerEditBookEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerEggThrowEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_egg_throw::PlayerEggThrowEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_egg_throw::PlayerEggThrowEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerExpChangeEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_exp_change::PlayerExpChangeEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_exp_change::PlayerExpChangeEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerFishEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_fish::PlayerFishEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_fish::PlayerFishEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerInteractEntityEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_interact_entity::PlayerInteractEntityEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_interact_entity::PlayerInteractEntityEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerInteractAtEntityEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_interact_at_entity::PlayerInteractAtEntityEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_interact_at_entity::PlayerInteractAtEntityEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerItemHeldEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_item_held::PlayerItemHeldEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_item_held::PlayerItemHeldEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerItemDamageEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_item_damage::PlayerItemDamageEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_item_damage::PlayerItemDamageEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerItemBreakEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_item_break::PlayerItemBreakEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_item_break::PlayerItemBreakEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerItemConsumeEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_item_consume::PlayerItemConsumeEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_item_consume::PlayerItemConsumeEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerItemMendEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_item_mend::PlayerItemMendEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_item_mend::PlayerItemMendEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerLevelChangeEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_level_change::PlayerLevelChangeEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_level_change::PlayerLevelChangeEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerKickEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_kick::PlayerKickEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_kick::PlayerKickEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerToggleSneakEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_toggle_sneak::PlayerToggleSneakEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_toggle_sneak::PlayerToggleSneakEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerToggleSprintEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_toggle_sprint::PlayerToggleSprintEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_toggle_sprint::PlayerToggleSprintEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerToggleFlightEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_toggle_flight::PlayerToggleFlightEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_toggle_flight::PlayerToggleFlightEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerSwapHandItemsEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_swap_hand_items::PlayerSwapHandItemsEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_swap_hand_items::PlayerSwapHandItemsEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerResourcePackStatusEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_resource_pack_status::PlayerResourcePackStatusEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_resource_pack_status::PlayerResourcePackStatusEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerRespawnEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_respawn::PlayerRespawnEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_respawn::PlayerRespawnEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerPickupArrowEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_pickup_arrow::PlayerPickupArrowEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_pickup_arrow::PlayerPickupArrowEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerPortalEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_portal::PlayerPortalEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_portal::PlayerPortalEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerRecipeDiscoverEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_recipe_discover::PlayerRecipeDiscoverEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_recipe_discover::PlayerRecipeDiscoverEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerRiptideEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_riptide::PlayerRiptideEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_riptide::PlayerRiptideEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerShearEntityEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_shear_entity::PlayerShearEntityEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_shear_entity::PlayerShearEntityEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.spigotmc.event.player.PlayerSpawnLocationEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_spawn_location::PlayerSpawnLocationEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_spawn_location::PlayerSpawnLocationEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerStatisticIncrementEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_statistic_increment::PlayerStatisticIncrementEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_statistic_increment::PlayerStatisticIncrementEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerVelocityEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_velocity::PlayerVelocityEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_velocity::PlayerVelocityEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerHarvestBlockEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_harvest_block::PlayerHarvestBlockEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_harvest_block::PlayerHarvestBlockEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerInteractEvent" => { + context + .register_event::< + pumpkin::plugin::player::player_interact_event::PlayerInteractEvent, + PatchBukkitEventHandler< + pumpkin::plugin::player::player_interact_event::PlayerInteractEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.BlockBreakEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_break::BlockBreakEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.BlockDamageEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_damage::BlockDamageEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.BlockDamageAbortEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_damage_abort::BlockDamageAbortEvent, + PatchBukkitEventHandler< + pumpkin::plugin::block::block_damage_abort::BlockDamageAbortEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.BlockDispenseEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_dispense::BlockDispenseEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.BlockDropItemEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_drop_item::BlockDropItemEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.BlockExplodeEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_explode::BlockExplodeEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.BlockFadeEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_fade::BlockFadeEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.BlockFertilizeEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_fertilize::BlockFertilizeEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.BlockFormEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_form::BlockFormEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.BlockFromToEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_from_to::BlockFromToEvent, + PatchBukkitEventHandler< + pumpkin::plugin::block::block_from_to::BlockFromToEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.BlockGrowEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_grow::BlockGrowEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.BlockPistonExtendEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_piston_extend::BlockPistonExtendEvent, + PatchBukkitEventHandler< + pumpkin::plugin::block::block_piston_extend::BlockPistonExtendEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.BlockPistonRetractEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_piston_retract::BlockPistonRetractEvent, + PatchBukkitEventHandler< + pumpkin::plugin::block::block_piston_retract::BlockPistonRetractEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.BlockRedstoneEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_redstone::BlockRedstoneEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.BlockMultiPlaceEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_multi_place::BlockMultiPlaceEvent, + PatchBukkitEventHandler< + pumpkin::plugin::block::block_multi_place::BlockMultiPlaceEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.BlockPhysicsEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_physics::BlockPhysicsEvent, + PatchBukkitEventHandler< + pumpkin::plugin::block::block_physics::BlockPhysicsEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.NotePlayEvent" => { + context + .register_event::< + pumpkin::plugin::block::note_play::NotePlayEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.SignChangeEvent" => { + context + .register_event::< + pumpkin::plugin::block::sign_change::SignChangeEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.TNTPrimeEvent" => { + context + .register_event::< + pumpkin::plugin::block::tnt_prime::TNTPrimeEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.MoistureChangeEvent" => { + context + .register_event::< + pumpkin::plugin::block::moisture_change::MoistureChangeEvent, + PatchBukkitEventHandler< + pumpkin::plugin::block::moisture_change::MoistureChangeEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.SpongeAbsorbEvent" => { + context + .register_event::< + pumpkin::plugin::block::sponge_absorb::SpongeAbsorbEvent, + PatchBukkitEventHandler< + pumpkin::plugin::block::sponge_absorb::SpongeAbsorbEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.FluidLevelChangeEvent" => { + context + .register_event::< + pumpkin::plugin::block::fluid_level_change::FluidLevelChangeEvent, + PatchBukkitEventHandler< + pumpkin::plugin::block::fluid_level_change::FluidLevelChangeEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.world.SpawnChangeEvent" => { + context + .register_event::< + pumpkin::plugin::world::spawn_change::SpawnChangeEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.server.ServerListPingEvent" => { + context + .register_event::< + pumpkin::plugin::server::server_list_ping::ServerListPingEvent, + PatchBukkitEventHandler< + pumpkin::plugin::server::server_list_ping::ServerListPingEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.server.PluginEnableEvent" => { + context + .register_event::< + pumpkin::plugin::server::plugin_enable::PluginEnableEvent, + PatchBukkitEventHandler< + pumpkin::plugin::server::plugin_enable::PluginEnableEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.server.PluginDisableEvent" => { + context + .register_event::< + pumpkin::plugin::server::plugin_disable::PluginDisableEvent, + PatchBukkitEventHandler< + pumpkin::plugin::server::plugin_disable::PluginDisableEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.server.ServiceRegisterEvent" => { + context + .register_event::< + pumpkin::plugin::server::service_register::ServiceRegisterEvent, + PatchBukkitEventHandler< + pumpkin::plugin::server::service_register::ServiceRegisterEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.server.ServiceUnregisterEvent" => { + context + .register_event::< + pumpkin::plugin::server::service_unregister::ServiceUnregisterEvent, + PatchBukkitEventHandler< + pumpkin::plugin::server::service_unregister::ServiceUnregisterEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.BlockCanBuildEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_can_build::BlockCanBuildEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.BlockBurnEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_burn::BlockBurnEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.BlockIgniteEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_ignite::BlockIgniteEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.BlockSpreadEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_spread::BlockSpreadEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.BlockPlaceEvent" => { + context + .register_event::< + pumpkin::plugin::block::block_place::BlockPlaceEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.entity.EntitySpawnEvent" => { + context + .register_event::< + pumpkin::plugin::entity::entity_spawn::EntitySpawnEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.entity.EntityDamageEvent" => { + context + .register_event::< + pumpkin::plugin::entity::entity_damage::EntityDamageEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.entity.EntityDeathEvent" => { + context + .register_event::< + pumpkin::plugin::entity::entity_death::EntityDeathEvent, + PatchBukkitEventHandler, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.server.ServerCommandEvent" => { + context + .register_event::< + pumpkin::plugin::server::server_command::ServerCommandEvent, + PatchBukkitEventHandler< + pumpkin::plugin::server::server_command::ServerCommandEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.server.BroadcastMessageEvent" => { + context + .register_event::< + pumpkin::plugin::server::server_broadcast::ServerBroadcastEvent, + PatchBukkitEventHandler< + pumpkin::plugin::server::server_broadcast::ServerBroadcastEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + _ => { + log::warn!( + "Unsupported Bukkit event type '{}' from plugin '{}'", + request.event_type, request.plugin_name + ); + } + } + }); + }); + + Some(()) +} + +pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { + let ctx = CALLBACK_CONTEXT.get()?; + let event = request.event?; + log::debug!("Java calling event {:?}", event); + + let context = ctx.plugin_context.clone(); + + let handled = tokio::task::block_in_place(|| { + ctx.runtime.block_on(async { + match event.data? { + Data::PlayerJoin(player_join_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_join_event_data.player_uuid?.value).ok()?; + let 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; + Some(true) + } + Data::PlayerLogin(player_login_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_login_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let pumpkin_event = PlayerLoginEvent::new( + player, + TextComponent::from_legacy_string(&player_login_event_data.kick_message), + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::AsyncPlayerPreLogin(player_pre_login_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_pre_login_event_data.player_uuid?.value).ok()?; + let pumpkin_event = PlayerPreLoginEvent::new( + player_pre_login_event_data.name, + uuid, + player_pre_login_event_data.address, + player_pre_login_event_data.result, + player_pre_login_event_data.kick_message, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerLeave(player_leave_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_leave_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let pumpkin_event = PlayerLeaveEvent::new( + player, + TextComponent::from_legacy_string(&player_leave_event_data.leave_message), + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerMove(player_move_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_move_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let from = player_move_event_data.from?.position?; + let to = player_move_event_data.to?.position?; + let pumpkin_event = PlayerMoveEvent::new( + player, + Vector3::new(from.x, from.y, from.z), + Vector3::new(to.x, to.y, to.z), + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerAdvancementDone(player_advancement_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_advancement_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let pumpkin_event = PlayerAdvancementDoneEvent::new( + player, + player_advancement_event_data.advancement_key, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerAnimation(player_animation_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_animation_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let pumpkin_event = PlayerAnimationEvent::new( + player, + player_animation_event_data.animation_type, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerArmorStandManipulate(player_armor_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_armor_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let armor_uuid = uuid::Uuid::parse_str( + &player_armor_event_data.armor_stand_uuid?.value, + ) + .ok()?; + let pumpkin_event = PlayerArmorStandManipulateEvent::new( + player, + armor_uuid, + player_armor_event_data.item_key, + player_armor_event_data.armor_stand_item_key, + player_armor_event_data.slot, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerBedEnter(player_bed_enter_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_bed_enter_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let position = player_bed_enter_event_data + .bed_location + .and_then(|loc| loc.position) + .map(|pos| Vector3::new(pos.x, pos.y, pos.z)) + .unwrap_or_else(|| player.position()); + let pumpkin_event = PlayerBedEnterEvent::new(player, position); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerBedLeave(player_bed_leave_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_bed_leave_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let position = player_bed_leave_event_data + .bed_location + .and_then(|loc| loc.position) + .map(|pos| Vector3::new(pos.x, pos.y, pos.z)) + .unwrap_or_else(|| player.position()); + let pumpkin_event = PlayerBedLeaveEvent::new(player, position); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerBucketEmpty(player_bucket_empty_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_bucket_empty_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let position = player_bucket_empty_event_data + .location + .and_then(|loc| loc.position) + .map(|pos| Vector3::new(pos.x, pos.y, pos.z)) + .unwrap_or_else(|| player.position()); + let face = bukkit_block_face_to_direction( + &player_bucket_empty_event_data.block_face, + ); + let pumpkin_event = PlayerBucketEmptyEvent::new( + player, + position, + player_bucket_empty_event_data.block_key, + face, + player_bucket_empty_event_data.bucket_item_key, + player_bucket_empty_event_data.hand, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerBucketFill(player_bucket_fill_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_bucket_fill_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let position = player_bucket_fill_event_data + .location + .and_then(|loc| loc.position) + .map(|pos| Vector3::new(pos.x, pos.y, pos.z)) + .unwrap_or_else(|| player.position()); + let face = bukkit_block_face_to_direction( + &player_bucket_fill_event_data.block_face, + ); + let pumpkin_event = PlayerBucketFillEvent::new( + player, + position, + player_bucket_fill_event_data.block_key, + face, + player_bucket_fill_event_data.bucket_item_key, + player_bucket_fill_event_data.hand, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerBucketEntity(player_bucket_entity_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_bucket_entity_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let entity_uuid = + uuid::Uuid::parse_str(&player_bucket_entity_event_data.entity_uuid?.value).ok()?; + let pumpkin_event = PlayerBucketEntityEvent::new( + player, + entity_uuid, + player_bucket_entity_event_data.entity_type, + player_bucket_entity_event_data.original_bucket_key, + player_bucket_entity_event_data.entity_bucket_key, + player_bucket_entity_event_data.hand, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerChangedMainHand(player_changed_main_hand_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_changed_main_hand_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let main_hand = main_hand_from_bukkit( + &player_changed_main_hand_event_data.main_hand, + ) + .unwrap_or(Hand::Right); + let pumpkin_event = PlayerChangedMainHandEvent::new(player, main_hand); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerRegisterChannel(player_register_channel_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_register_channel_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let pumpkin_event = PlayerRegisterChannelEvent::new( + player, + player_register_channel_event_data.channel, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerUnregisterChannel(player_unregister_channel_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_unregister_channel_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let pumpkin_event = PlayerUnregisterChannelEvent::new( + player, + player_unregister_channel_event_data.channel, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerTeleport(player_teleport_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_teleport_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let from = player_teleport_event_data.from?.position?; + let to = player_teleport_event_data.to?.position?; + let pumpkin_event = PlayerTeleportEvent::new( + player, + Vector3::new(from.x, from.y, from.z), + Vector3::new(to.x, to.y, to.z), + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerChangeWorld(player_change_world_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_change_world_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let prev_uuid = uuid::Uuid::parse_str( + &player_change_world_event_data.previous_world?.uuid?.value, + ) + .ok()?; + let new_uuid = uuid::Uuid::parse_str( + &player_change_world_event_data.new_world?.uuid?.value, + ) + .ok()?; + let prev_world = context + .server + .worlds + .load() + .iter() + .find(|world| world.uuid == prev_uuid)? + .clone(); + let new_world = context + .server + .worlds + .load() + .iter() + .find(|world| world.uuid == new_uuid)? + .clone(); + let position = player_change_world_event_data + .position + .and_then(|loc| loc.position) + .map(|pos| Vector3::new(pos.x, pos.y, pos.z)) + .unwrap_or_else(|| player.position()); + let pumpkin_event = PlayerChangeWorldEvent::new( + player, + prev_world, + new_world, + position, + player_change_world_event_data.yaw, + player_change_world_event_data.pitch, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerGamemodeChange(player_gamemode_change_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_gamemode_change_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let prev = gamemode_from_bukkit(&player_gamemode_change_event_data.previous_gamemode) + .unwrap_or(player.gamemode.load()); + let next = gamemode_from_bukkit(&player_gamemode_change_event_data.new_gamemode) + .unwrap_or(player.gamemode.load()); + let pumpkin_event = PlayerGamemodeChangeEvent::new(player, prev, next); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerChat(player_chat_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_chat_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let mut recipients = Vec::new(); + if player_chat_event_data.recipients.is_empty() { + recipients = context.server.get_all_players(); + } else { + for recipient in player_chat_event_data.recipients { + if let Ok(uuid) = uuid::Uuid::parse_str(&recipient.value) { + if let Some(recipient_player) = + context.server.get_player_by_uuid(uuid) + { + recipients.push(recipient_player); + } + } + } + } + + let pumpkin_event = PlayerChatEvent::new( + player, + player_chat_event_data.message, + recipients, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerCommand(player_command_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_command_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let pumpkin_event = + PlayerCommandPreprocessEvent::new(player, player_command_event_data.command); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerCommandSend(player_command_send_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_command_send_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let pumpkin_event = + PlayerCommandSendEvent::new(player, player_command_send_event_data.commands); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerDropItem(player_drop_item_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_drop_item_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let item_uuid = + uuid::Uuid::parse_str(&player_drop_item_event_data.item_uuid?.value).ok()?; + let item_stack = item_stack_from_key( + &player_drop_item_event_data.item_key, + player_drop_item_event_data.item_amount, + ); + let pumpkin_event = + PlayerDropItemEvent::new(player, item_uuid, item_stack); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerEditBook(player_edit_book_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_edit_book_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let title = if player_edit_book_event_data.title.is_empty() { + None + } else { + Some(player_edit_book_event_data.title) + }; + let pumpkin_event = PlayerEditBookEvent::new( + player, + player_edit_book_event_data.slot, + player_edit_book_event_data.pages, + title, + player_edit_book_event_data.is_signing, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerEggThrow(player_egg_throw_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_egg_throw_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let egg_uuid = + uuid::Uuid::parse_str(&player_egg_throw_event_data.egg_uuid?.value).ok()?; + let pumpkin_event = PlayerEggThrowEvent::new( + player, + egg_uuid, + player_egg_throw_event_data.hatching, + player_egg_throw_event_data.num_hatches.min(u8::MAX as i32) as u8, + player_egg_throw_event_data.hatching_type, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerExpChange(player_exp_change_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_exp_change_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let pumpkin_event = + PlayerExpChangeEvent::new(player, player_exp_change_event_data.amount); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerFish(player_fish_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_fish_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let caught_uuid = player_fish_event_data + .caught_uuid + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()); + let hook_uuid = + uuid::Uuid::parse_str(&player_fish_event_data.hook_uuid?.value).ok()?; + let pumpkin_event = PlayerFishEvent::new( + player, + caught_uuid, + hook_uuid, + player_fish_event_data.caught_type, + player_fish_event_data.state, + player_fish_event_data.hand, + player_fish_event_data.exp_to_drop, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerInteractEntity(player_interact_entity_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_interact_entity_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let entity_uuid = + uuid::Uuid::parse_str(&player_interact_entity_event_data.entity_uuid?.value).ok()?; + let pumpkin_event = PlayerInteractEntityEvent::new( + player, + entity_uuid, + player_interact_entity_event_data.entity_type, + player_interact_entity_event_data.hand, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerInteractAtEntity(player_interact_at_entity_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_interact_at_entity_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let entity_uuid = + uuid::Uuid::parse_str(&player_interact_at_entity_event_data.entity_uuid?.value).ok()?; + let position = player_interact_at_entity_event_data + .clicked_position + .map(|pos| Vector3::new(pos.x as f32, pos.y as f32, pos.z as f32)) + .unwrap_or_else(|| Vector3::new(0.0, 0.0, 0.0)); + let pumpkin_event = PlayerInteractAtEntityEvent::new( + player, + entity_uuid, + player_interact_at_entity_event_data.entity_type, + player_interact_at_entity_event_data.hand, + position, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerItemHeld(player_item_held_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_item_held_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let pumpkin_event = PlayerItemHeldEvent::new( + player, + player_item_held_event_data.previous_slot, + player_item_held_event_data.new_slot, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerItemDamage(player_item_damage_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_item_damage_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let key = if player_item_damage_event_data.item_key.is_empty() { + "minecraft:air" + } else { + player_item_damage_event_data.item_key.as_str() + }; + let item = item_stack_from_key(key, player_item_damage_event_data.item_amount); + let pumpkin_event = PlayerItemDamageEvent::new( + player, + item, + player_item_damage_event_data.damage, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerItemBreak(player_item_break_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_item_break_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let key = if player_item_break_event_data.item_key.is_empty() { + "minecraft:air" + } else { + player_item_break_event_data.item_key.as_str() + }; + let item = item_stack_from_key(key, player_item_break_event_data.item_amount); + let pumpkin_event = PlayerItemBreakEvent::new(player, item); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerItemConsume(player_item_consume_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_item_consume_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let key = if player_item_consume_event_data.item_key.is_empty() { + "minecraft:air" + } else { + player_item_consume_event_data.item_key.as_str() + }; + let item = item_stack_from_key(key, player_item_consume_event_data.item_amount); + let hand = if player_item_consume_event_data.hand == "OFF_HAND" { + Hand::Left + } else { + Hand::Right + }; + let pumpkin_event = PlayerItemConsumeEvent::new(player, item, hand); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerItemMend(player_item_mend_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_item_mend_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let key = if player_item_mend_event_data.item_key.is_empty() { + "minecraft:air" + } else { + player_item_mend_event_data.item_key.as_str() + }; + let item = item_stack_from_key(key, player_item_mend_event_data.item_amount); + let slot = equipment_slot_from_bukkit(&player_item_mend_event_data.slot) + .unwrap_or(EquipmentSlot::MAIN_HAND); + let orb_uuid = player_item_mend_event_data + .orb_uuid + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()); + let pumpkin_event = PlayerItemMendEvent::new( + player, + item, + slot, + player_item_mend_event_data.repair_amount, + orb_uuid, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerLevelChange(player_level_change_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_level_change_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let pumpkin_event = PlayerLevelChangeEvent::new( + player, + player_level_change_event_data.old_level, + player_level_change_event_data.new_level, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerKick(player_kick_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_kick_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let reason = serde_json::from_str(&player_kick_event_data.reason) + .unwrap_or_else(|_| TextComponent::text(&player_kick_event_data.reason)); + let leave_message = serde_json::from_str(&player_kick_event_data.leave_message) + .unwrap_or_else(|_| TextComponent::text(&player_kick_event_data.leave_message)); + let cause = if player_kick_event_data.cause.is_empty() { + "UNKNOWN".to_string() + } else { + player_kick_event_data.cause + }; + let pumpkin_event = + PlayerKickEvent::new(player, reason, leave_message, cause); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerToggleSneak(player_toggle_sneak_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_toggle_sneak_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let pumpkin_event = PlayerToggleSneakEvent::new( + player, + player_toggle_sneak_event_data.is_sneaking, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerToggleSprint(player_toggle_sprint_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_toggle_sprint_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let pumpkin_event = PlayerToggleSprintEvent::new( + player, + player_toggle_sprint_event_data.is_sprinting, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerToggleFlight(player_toggle_flight_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_toggle_flight_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let pumpkin_event = PlayerToggleFlightEvent::new( + player, + player_toggle_flight_event_data.is_flying, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerSwapHandItems(player_swap_hand_items_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_swap_hand_items_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let main_key = if player_swap_hand_items_event_data.main_hand_item_key.is_empty() { + "minecraft:air" + } else { + player_swap_hand_items_event_data.main_hand_item_key.as_str() + }; + let off_key = if player_swap_hand_items_event_data.off_hand_item_key.is_empty() { + "minecraft:air" + } else { + player_swap_hand_items_event_data.off_hand_item_key.as_str() + }; + let main_item = item_stack_from_key( + main_key, + player_swap_hand_items_event_data.main_hand_item_amount, + ); + let off_item = item_stack_from_key( + off_key, + player_swap_hand_items_event_data.off_hand_item_amount, + ); + let pumpkin_event = PlayerSwapHandItemsEvent::new(player, main_item, off_item); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerResourcePackStatus(player_resource_pack_status_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_resource_pack_status_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let pack_uuid = player_resource_pack_status_event_data + .pack_uuid + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) + .unwrap_or_else(uuid::Uuid::new_v4); + let pumpkin_event = PlayerResourcePackStatusEvent::new( + player, + pack_uuid, + player_resource_pack_status_event_data.hash, + player_resource_pack_status_event_data.status, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerRespawn(player_respawn_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_respawn_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let (world_uuid, pos) = if let Some(loc) = player_respawn_event_data.respawn_location { + let world_uuid = loc + .world + .and_then(|w| w.uuid) + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) + .unwrap_or_else(|| player.world().uuid); + let pos = location_to_vec3(loc).unwrap_or_else(|| player.position()); + (world_uuid, pos) + } else { + (player.world().uuid, player.position()) + }; + let pumpkin_event = PlayerRespawnEvent::new( + player, + pos, + world_uuid, + player_respawn_event_data.is_bed_spawn, + player_respawn_event_data.is_anchor_spawn, + player_respawn_event_data.is_missing_respawn_block, + player_respawn_event_data.respawn_reason, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerPickupArrow(player_pickup_arrow_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_pickup_arrow_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let arrow_uuid = player_pickup_arrow_event_data + .arrow_uuid + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) + .unwrap_or_else(uuid::Uuid::new_v4); + let item_uuid = player_pickup_arrow_event_data + .item_uuid + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) + .unwrap_or_else(uuid::Uuid::new_v4); + let key = if player_pickup_arrow_event_data.item_key.is_empty() { + "minecraft:air" + } else { + player_pickup_arrow_event_data.item_key.as_str() + }; + let item = item_stack_from_key(key, player_pickup_arrow_event_data.item_amount); + let pumpkin_event = PlayerPickupArrowEvent::new( + player, + arrow_uuid, + item_uuid, + item, + player_pickup_arrow_event_data.remaining, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerPortal(player_portal_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_portal_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let (from_world_uuid, from_pos) = if let Some(loc) = player_portal_event_data.from { + let world_uuid = loc + .world + .and_then(|w| w.uuid) + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) + .unwrap_or_else(|| player.world().uuid); + let pos = location_to_vec3(loc).unwrap_or_else(|| player.position()); + (world_uuid, pos) + } else { + (player.world().uuid, player.position()) + }; + let (to_world_uuid, to_pos) = if let Some(loc) = player_portal_event_data.to { + let world_uuid = loc + .world + .and_then(|w| w.uuid) + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) + .unwrap_or_else(|| player.world().uuid); + let pos = location_to_vec3(loc).unwrap_or_else(|| player.position()); + (world_uuid, pos) + } else { + (player.world().uuid, player.position()) + }; + let cause = if player_portal_event_data.cause.is_empty() { + "UNKNOWN".to_string() + } else { + player_portal_event_data.cause + }; + let pumpkin_event = PlayerPortalEvent::new( + player, + from_pos, + from_world_uuid, + to_pos, + to_world_uuid, + cause, + player_portal_event_data.search_radius, + player_portal_event_data.can_create_portal, + player_portal_event_data.creation_radius, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerRecipeDiscover(player_recipe_discover_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_recipe_discover_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let pumpkin_event = PlayerRecipeDiscoverEvent::new( + player, + player_recipe_discover_event_data.recipe_key, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerRiptide(player_riptide_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_riptide_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let key = if player_riptide_event_data.item_key.is_empty() { + "minecraft:air" + } else { + player_riptide_event_data.item_key.as_str() + }; + let item = item_stack_from_key(key, player_riptide_event_data.item_amount); + let velocity = player_riptide_event_data + .velocity + .map(|v| Vector3::new(v.x, v.y, v.z)) + .unwrap_or_else(Vector3::default); + let pumpkin_event = PlayerRiptideEvent::new(player, item, velocity); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerShearEntity(player_shear_entity_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_shear_entity_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let entity_uuid = player_shear_entity_event_data + .entity_uuid + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) + .unwrap_or_else(uuid::Uuid::new_v4); + let key = if player_shear_entity_event_data.item_key.is_empty() { + "minecraft:air" + } else { + player_shear_entity_event_data.item_key.as_str() + }; + let item = item_stack_from_key(key, player_shear_entity_event_data.item_amount); + let hand = if player_shear_entity_event_data.hand.is_empty() { + "HAND".to_string() + } else { + player_shear_entity_event_data.hand + }; + let entity_type = player_shear_entity_event_data.entity_type; + let pumpkin_event = PlayerShearEntityEvent::new( + player, + entity_uuid, + entity_type, + item, + hand, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerSpawnLocation(player_spawn_location_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_spawn_location_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let (world_uuid, pos) = if let Some(loc) = player_spawn_location_event_data.spawn_location { + let world_uuid = loc + .world + .and_then(|w| w.uuid) + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) + .unwrap_or_else(|| player.world().uuid); + let pos = location_to_vec3(loc).unwrap_or_else(|| player.position()); + (world_uuid, pos) + } else { + (player.world().uuid, player.position()) + }; + let pumpkin_event = PlayerSpawnLocationEvent::new(player, pos, world_uuid); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerStatisticIncrement(player_statistic_increment_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_statistic_increment_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let pumpkin_event = PlayerStatisticIncrementEvent::new( + player, + player_statistic_increment_event_data.statistic, + player_statistic_increment_event_data.initial_value, + player_statistic_increment_event_data.new_value, + player_statistic_increment_event_data.entity_type, + player_statistic_increment_event_data.material_key, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerVelocity(player_velocity_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_velocity_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let velocity = player_velocity_event_data + .velocity + .map(|v| Vector3::new(v.x, v.y, v.z)) + .unwrap_or_else(Vector3::default); + let pumpkin_event = PlayerVelocityEvent::new(player, velocity); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerHarvestBlock(player_harvest_block_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_harvest_block_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let (world_uuid, pos) = + if let Some(loc) = player_harvest_block_event_data.block_location { + let world_uuid = loc + .world + .and_then(|w| w.uuid) + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) + .unwrap_or_else(|| player.world().uuid); + let pos = location_to_vec3(loc).unwrap_or_else(|| player.position()); + (world_uuid, pos) + } else { + (player.world().uuid, player.position()) + }; + let block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + let key = if player_harvest_block_event_data.item_key.is_empty() { + "minecraft:air" + } else { + player_harvest_block_event_data.item_key.as_str() + }; + let item = item_stack_from_key( + key, + player_harvest_block_event_data.item_amount, + ); + let block_key = if player_harvest_block_event_data.block_key.is_empty() { + "minecraft:air".to_string() + } else { + player_harvest_block_event_data.block_key + }; + let pumpkin_event = PlayerHarvestBlockEvent::new( + player, + block_pos, + block_key, + item, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::PlayerInteract(player_interact_event_data) => { + let uuid = + uuid::Uuid::parse_str(&player_interact_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let action = match player_interact_event_data.action.as_str() { + "LEFT_CLICK_BLOCK" => InteractAction::LeftClickBlock, + "LEFT_CLICK_AIR" => InteractAction::LeftClickAir, + "RIGHT_CLICK_BLOCK" => InteractAction::RightClickBlock, + "RIGHT_CLICK_AIR" => InteractAction::RightClickAir, + _ => InteractAction::RightClickAir, + }; + + let clicked_pos = player_interact_event_data + .clicked + .and_then(|loc| loc.position) + .map(|pos| { + pumpkin_util::math::position::BlockPos::new( + pos.x as i32, + pos.y as i32, + pos.z as i32, + ) + }); + + let block = block_from_key(&player_interact_event_data.block_key); + let item = Arc::new(Mutex::new(item_from_key( + &player_interact_event_data.item_key, + ))); + let face = bukkit_block_face_to_direction( + &player_interact_event_data.block_face, + ); + + let pumpkin_event = PlayerInteractEvent::new( + &player, + action, + &item, + player_interact_event_data.item_key, + block, + clicked_pos, + face, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::BlockBreak(block_break_event_data) => { + let uuid = uuid::Uuid::parse_str(&block_break_event_data.player_uuid?.value) + .ok()?; + let player = context.server.get_player_by_uuid(uuid); + let block = block_from_key(&block_break_event_data.block_key); + let position = block_break_event_data + .location + .and_then(|loc| loc.position) + .map(|pos| { + pumpkin_util::math::position::BlockPos::new( + pos.x as i32, + pos.y as i32, + pos.z as i32, + ) + }) + .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); + + let pumpkin_event = BlockBreakEvent::new( + player, + block, + position, + block_break_event_data.exp, + block_break_event_data.drop, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::BlockDamage(block_damage_event_data) => { + let uuid = uuid::Uuid::parse_str(&block_damage_event_data.player_uuid?.value) + .ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let block = block_from_key(&block_damage_event_data.block_key); + let position = block_damage_event_data + .location + .and_then(|loc| loc.position) + .map(|pos| { + pumpkin_util::math::position::BlockPos::new( + pos.x as i32, + pos.y as i32, + pos.z as i32, + ) + }) + .unwrap_or_else(|| player.position().to_block_pos()); + let key = if block_damage_event_data.item_key.is_empty() { + "minecraft:air" + } else { + block_damage_event_data.item_key.as_str() + }; + let item_stack = item_stack_from_key(key, 1); + let pumpkin_event = BlockDamageEvent::new( + player, + block, + position, + item_stack, + block_damage_event_data.insta_break, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::BlockDamageAbort(block_damage_abort_event_data) => { + let uuid = uuid::Uuid::parse_str(&block_damage_abort_event_data.player_uuid?.value) + .ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let block = block_from_key(&block_damage_abort_event_data.block_key); + let position = block_damage_abort_event_data + .location + .and_then(|loc| loc.position) + .map(|pos| { + pumpkin_util::math::position::BlockPos::new( + pos.x as i32, + pos.y as i32, + pos.z as i32, + ) + }) + .unwrap_or_else(|| player.position().to_block_pos()); + let key = if block_damage_abort_event_data.item_key.is_empty() { + "minecraft:air" + } else { + block_damage_abort_event_data.item_key.as_str() + }; + let item_stack = item_stack_from_key(key, 1); + let pumpkin_event = + BlockDamageAbortEvent::new(player, block, position, item_stack); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::BlockDispense(block_dispense_event_data) => { + let block = block_from_key(&block_dispense_event_data.block_key); + let position = block_dispense_event_data + .location + .and_then(|loc| loc.position) + .map(|pos| { + pumpkin_util::math::position::BlockPos::new( + pos.x as i32, + pos.y as i32, + pos.z as i32, + ) + }) + .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); + let key = if block_dispense_event_data.item_key.is_empty() { + "minecraft:air" + } else { + block_dispense_event_data.item_key.as_str() + }; + let item_stack = + item_stack_from_key(key, block_dispense_event_data.item_amount); + let velocity = block_dispense_event_data + .velocity + .map(|v| Vector3::new(v.x, v.y, v.z)) + .unwrap_or_else(|| Vector3::new(0.0, 0.0, 0.0)); + let pumpkin_event = + BlockDispenseEvent::new(block, position, item_stack, velocity); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::BlockDropItem(block_drop_item_event_data) => { + let uuid = uuid::Uuid::parse_str(&block_drop_item_event_data.player_uuid?.value) + .ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let block = block_from_key(&block_drop_item_event_data.block_key); + let position = block_drop_item_event_data + .location + .and_then(|loc| loc.position) + .map(|pos| { + pumpkin_util::math::position::BlockPos::new( + pos.x as i32, + pos.y as i32, + pos.z as i32, + ) + }) + .unwrap_or_else(|| player.position().to_block_pos()); + let mut items = Vec::new(); + for entry in block_drop_item_event_data.items { + if entry.item_key.is_empty() && entry.item_amount <= 0 { + continue; + } + let key = if entry.item_key.is_empty() { + "minecraft:air" + } else { + entry.item_key.as_str() + }; + let stack = item_stack_from_key(key, entry.item_amount); + if !stack.is_empty() { + items.push(stack); + } + } + let pumpkin_event = BlockDropItemEvent::new(player, block, position, items); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::BlockExplode(block_explode_event_data) => { + let block = block_from_key(&block_explode_event_data.block_key); + let position = block_explode_event_data + .location + .and_then(|loc| loc.position) + .map(|pos| { + pumpkin_util::math::position::BlockPos::new( + pos.x as i32, + pos.y as i32, + pos.z as i32, + ) + }) + .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); + let world_uuid = block_explode_event_data + .location + .and_then(|loc| loc.world) + .and_then(|w| w.uuid) + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) + .unwrap_or_else(|| { + context + .server + .worlds + .load() + .first() + .map(|world| world.uuid) + .unwrap_or_default() + }); + let mut blocks = Vec::new(); + for entry in block_explode_event_data.blocks { + if let Some(loc) = entry.location + && let Some(pos) = location_to_vec3(loc.clone()) + { + blocks.push(pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + )); + } + } + let pumpkin_event = BlockExplodeEvent::new( + block, + position, + world_uuid, + blocks, + block_explode_event_data.yield_, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::BlockFade(block_fade_event_data) => { + let block = block_from_key(&block_fade_event_data.block_key); + let new_block = block_from_key(&block_fade_event_data.new_block_key); + let position = block_fade_event_data + .location + .and_then(|loc| loc.position) + .map(|pos| { + pumpkin_util::math::position::BlockPos::new( + pos.x as i32, + pos.y as i32, + pos.z as i32, + ) + }) + .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); + let world_uuid = block_fade_event_data + .location + .and_then(|loc| loc.world) + .and_then(|w| w.uuid) + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) + .unwrap_or_else(|| { + context + .server + .worlds + .load() + .first() + .map(|world| world.uuid) + .unwrap_or_default() + }); + let pumpkin_event = BlockFadeEvent::new(block, new_block, position, world_uuid); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::BlockFertilize(block_fertilize_event_data) => { + let uuid = uuid::Uuid::parse_str(&block_fertilize_event_data.player_uuid?.value) + .ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let block = block_from_key(&block_fertilize_event_data.block_key); + let position = block_fertilize_event_data + .location + .and_then(|loc| loc.position) + .map(|pos| { + pumpkin_util::math::position::BlockPos::new( + pos.x as i32, + pos.y as i32, + pos.z as i32, + ) + }) + .unwrap_or_else(|| player.position().to_block_pos()); + let mut blocks = Vec::new(); + for entry in block_fertilize_event_data.blocks { + if let Some(loc) = entry.location + && let Some(pos) = location_to_vec3(loc.clone()) + { + blocks.push(pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + )); + } + } + let pumpkin_event = + BlockFertilizeEvent::new(player, block, position, blocks); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::BlockForm(block_form_event_data) => { + let old_block = block_from_key(&block_form_event_data.block_key); + let new_block = block_from_key(&block_form_event_data.new_block_key); + let position = block_form_event_data + .location + .and_then(|loc| loc.position) + .map(|pos| { + pumpkin_util::math::position::BlockPos::new( + pos.x as i32, + pos.y as i32, + pos.z as i32, + ) + }) + .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); + let world_uuid = block_form_event_data + .location + .and_then(|loc| loc.world) + .and_then(|w| w.uuid) + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) + .unwrap_or_else(|| { + context + .server + .worlds + .load() + .first() + .map(|world| world.uuid) + .unwrap_or_default() + }); + let pumpkin_event = BlockFormEvent::new(old_block, new_block, position, world_uuid); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::BlockFromTo(block_from_to_event_data) => { + let block = block_from_key(&block_from_to_event_data.block_key); + let to_block = block_from_key(&block_from_to_event_data.to_block_key); + let position = block_from_to_event_data + .location + .and_then(|loc| loc.position) + .map(|pos| { + pumpkin_util::math::position::BlockPos::new( + pos.x as i32, + pos.y as i32, + pos.z as i32, + ) + }) + .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); + let to_position = block_from_to_event_data + .to_location + .and_then(|loc| loc.position) + .map(|pos| { + pumpkin_util::math::position::BlockPos::new( + pos.x as i32, + pos.y as i32, + pos.z as i32, + ) + }) + .unwrap_or_else(|| position); + let world_uuid = block_from_to_event_data + .location + .and_then(|loc| loc.world) + .and_then(|w| w.uuid) + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) + .unwrap_or_else(|| { + context + .server + .worlds + .load() + .first() + .map(|world| world.uuid) + .unwrap_or_default() + }); + let face = + bukkit_block_face_to_direction(&block_from_to_event_data.face).unwrap_or( + BlockDirection::Down, + ); + let pumpkin_event = BlockFromToEvent::new( + block, + position, + to_block, + to_position, + face, + world_uuid, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::BlockGrow(block_grow_event_data) => { + let block = block_from_key(&block_grow_event_data.block_key); + let new_block = block_from_key(&block_grow_event_data.new_block_key); + let position = block_grow_event_data + .location + .and_then(|loc| loc.position) + .map(|pos| { + pumpkin_util::math::position::BlockPos::new( + pos.x as i32, + pos.y as i32, + pos.z as i32, + ) + }) + .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); + let world_uuid = block_grow_event_data + .location + .and_then(|loc| loc.world) + .and_then(|w| w.uuid) + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) + .unwrap_or_else(|| { + context + .server + .worlds + .load() + .first() + .map(|world| world.uuid) + .unwrap_or_default() + }); + let pumpkin_event = BlockGrowEvent::new(block, new_block, position, world_uuid); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::BlockPistonExtend(block_piston_extend_event_data) => { + let block = block_from_key(&block_piston_extend_event_data.block_key); + let position = block_piston_extend_event_data + .location + .and_then(|loc| loc.position) + .map(|pos| { + pumpkin_util::math::position::BlockPos::new( + pos.x as i32, + pos.y as i32, + pos.z as i32, + ) + }) + .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); + let world_uuid = block_piston_extend_event_data + .location + .and_then(|loc| loc.world) + .and_then(|w| w.uuid) + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) + .unwrap_or_else(|| { + context + .server + .worlds + .load() + .first() + .map(|world| world.uuid) + .unwrap_or_default() + }); + let face = + bukkit_block_face_to_direction(&block_piston_extend_event_data.direction) + .unwrap_or(BlockDirection::Down); + let mut blocks = Vec::new(); + for entry in block_piston_extend_event_data.blocks { + if let Some(loc) = entry.location + && let Some(pos) = location_to_vec3(loc.clone()) + { + blocks.push(pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + )); + } + } + let pumpkin_event = BlockPistonExtendEvent::new( + block, + position, + face, + block_piston_extend_event_data.length, + blocks, + world_uuid, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::BlockPistonRetract(block_piston_retract_event_data) => { + let block = block_from_key(&block_piston_retract_event_data.block_key); + let position = block_piston_retract_event_data + .location + .and_then(|loc| loc.position) + .map(|pos| { + pumpkin_util::math::position::BlockPos::new( + pos.x as i32, + pos.y as i32, + pos.z as i32, + ) + }) + .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); + let world_uuid = block_piston_retract_event_data + .location + .and_then(|loc| loc.world) + .and_then(|w| w.uuid) + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) + .unwrap_or_else(|| { + context + .server + .worlds + .load() + .first() + .map(|world| world.uuid) + .unwrap_or_default() + }); + let face = + bukkit_block_face_to_direction(&block_piston_retract_event_data.direction) + .unwrap_or(BlockDirection::Down); + let mut blocks = Vec::new(); + for entry in block_piston_retract_event_data.blocks { + if let Some(loc) = entry.location + && let Some(pos) = location_to_vec3(loc.clone()) + { + blocks.push(pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + )); + } + } + let pumpkin_event = BlockPistonRetractEvent::new( + block, + position, + face, + block_piston_retract_event_data.length, + blocks, + world_uuid, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::BlockRedstone(block_redstone_event_data) => { + let block = block_from_key(&block_redstone_event_data.block_key); + let position = block_redstone_event_data + .location + .and_then(|loc| loc.position) + .map(|pos| { + pumpkin_util::math::position::BlockPos::new( + pos.x as i32, + pos.y as i32, + pos.z as i32, + ) + }) + .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); + let pumpkin_event = BlockRedstoneEvent::new( + block, + position, + block_redstone_event_data.old_current, + block_redstone_event_data.new_current, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::BlockMultiPlace(block_multi_place_event_data) => { + let uuid = uuid::Uuid::parse_str(&block_multi_place_event_data.player_uuid?.value) + .ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let block = block_from_key(&block_multi_place_event_data.block_key); + let mut positions = Vec::new(); + for entry in block_multi_place_event_data.blocks { + if let Some(loc) = entry.location + && let Some(pos) = location_to_vec3(loc.clone()) + { + positions.push(pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + )); + } + } + let pumpkin_event = + BlockMultiPlaceEvent::new(player, block, positions); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::BlockPhysics(block_physics_event_data) => { + let block = block_from_key(&block_physics_event_data.block_key); + let source_block = block_from_key(&block_physics_event_data.source_block_key); + let position = block_physics_event_data + .location + .and_then(|loc| loc.position) + .map(|pos| { + pumpkin_util::math::position::BlockPos::new( + pos.x as i32, + pos.y as i32, + pos.z as i32, + ) + }) + .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); + let source_pos = block_physics_event_data + .source_location + .and_then(|loc| loc.position) + .map(|pos| { + pumpkin_util::math::position::BlockPos::new( + pos.x as i32, + pos.y as i32, + pos.z as i32, + ) + }) + .unwrap_or_else(|| position); + let world_uuid = block_physics_event_data + .location + .and_then(|loc| loc.world) + .and_then(|w| w.uuid) + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) + .unwrap_or_else(|| { + context + .server + .worlds + .load() + .first() + .map(|world| world.uuid) + .unwrap_or_default() + }); + let pumpkin_event = BlockPhysicsEvent::new( + block, + position, + source_block, + source_pos, + world_uuid, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::BlockPlace(block_place_event_data) => { + let uuid = uuid::Uuid::parse_str(&block_place_event_data.player_uuid?.value) + .ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let block = block_from_key(&block_place_event_data.block_key); + let against = block_from_key(&block_place_event_data.block_against_key); + let position = block_place_event_data + .location + .and_then(|loc| loc.position) + .map(|pos| { + pumpkin_util::math::position::BlockPos::new( + pos.x as i32, + pos.y as i32, + pos.z as i32, + ) + }) + .unwrap_or_else(|| player.position().to_block_pos()); + + let pumpkin_event = BlockPlaceEvent { + player, + block_placed: block, + block_placed_against: against, + position, + can_build: block_place_event_data.can_build, + cancelled: false, + }; + + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::BlockCanBuild(block_can_build_event_data) => { + let uuid = + uuid::Uuid::parse_str(&block_can_build_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let block_to_build = block_from_key(&block_can_build_event_data.block_key); + let block_against = block_from_key(&block_can_build_event_data.block_against_key); + let position = block_can_build_event_data + .location + .and_then(|loc| loc.position) + .map(|pos| { + pumpkin_util::math::position::BlockPos::new( + pos.x as i32, + pos.y as i32, + pos.z as i32, + ) + }) + .unwrap_or_else(|| player.position().to_block_pos()); + let pumpkin_event = BlockCanBuildEvent { + player, + block_to_build, + buildable: block_can_build_event_data.can_build, + block: block_against, + block_pos: position, + cancelled: false, + }; + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::BlockBurn(block_burn_event_data) => { + let block = block_from_key(&block_burn_event_data.block_key); + let igniting_block = + block_from_key(&block_burn_event_data.igniting_block_key); + let (world_uuid, pos) = if let Some(loc) = block_burn_event_data.location { + let world_uuid = loc + .world + .and_then(|w| w.uuid) + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) + .unwrap_or_else(|| { + context + .server + .worlds + .load() + .first() + .map(|w| w.uuid) + .unwrap_or_else(uuid::Uuid::new_v4) + }); + let pos = location_to_vec3(loc).unwrap_or_else(Vector3::default); + (world_uuid, pos) + } else { + ( + context + .server + .worlds + .load() + .first() + .map(|w| w.uuid) + .unwrap_or_else(uuid::Uuid::new_v4), + Vector3::default(), + ) + }; + let block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + let pumpkin_event = BlockBurnEvent { + igniting_block, + block, + block_pos, + world_uuid, + cancelled: false, + }; + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::BlockIgnite(block_ignite_event_data) => { + let uuid = + uuid::Uuid::parse_str(&block_ignite_event_data.player_uuid?.value).ok()?; + let player = context.server.get_player_by_uuid(uuid)?; + let block = block_from_key(&block_ignite_event_data.block_key); + let igniting_block = + block_from_key(&block_ignite_event_data.igniting_block_key); + let (world_uuid, pos) = if let Some(loc) = block_ignite_event_data.location { + let world_uuid = loc + .world + .and_then(|w| w.uuid) + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) + .unwrap_or_else(|| player.world().uuid); + let pos = location_to_vec3(loc).unwrap_or_else(Vector3::default); + (world_uuid, pos) + } else { + (player.world().uuid, Vector3::default()) + }; + let block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + let cause = if block_ignite_event_data.cause.is_empty() { + "UNKNOWN".to_string() + } else { + block_ignite_event_data.cause + }; + let pumpkin_event = BlockIgniteEvent { + player, + block, + igniting_block, + block_pos, + world_uuid, + cause, + cancelled: false, + }; + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::BlockSpread(block_spread_event_data) => { + let source_block = block_from_key(&block_spread_event_data.source_block_key); + let block = block_from_key(&block_spread_event_data.block_key); + let (world_uuid, source_pos) = + if let Some(loc) = block_spread_event_data.source_location { + let world_uuid = loc + .world + .and_then(|w| w.uuid) + .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) + .unwrap_or_else(|| { + context + .server + .worlds + .load() + .first() + .map(|w| w.uuid) + .unwrap_or_else(uuid::Uuid::new_v4) + }); + let pos = location_to_vec3(loc).unwrap_or_else(Vector3::default); + ( + world_uuid, + pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ), + ) + } else { + ( + context + .server + .worlds + .load() + .first() + .map(|w| w.uuid) + .unwrap_or_else(uuid::Uuid::new_v4), + pumpkin_util::math::position::BlockPos::new(0, 0, 0), + ) + }; + let block_pos = if let Some(loc) = block_spread_event_data.location { + let pos = location_to_vec3(loc).unwrap_or_else(Vector3::default); + pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ) + } else { + source_pos + }; + let pumpkin_event = BlockSpreadEvent { + source_block, + source_pos, + block, + block_pos, + world_uuid, + cancelled: false, + }; + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::EntitySpawn(entity_spawn_event_data) => { + let uuid = uuid::Uuid::parse_str(&entity_spawn_event_data.entity_uuid?.value) + .ok()?; + let pumpkin_event = + pumpkin::plugin::entity::entity_spawn::EntitySpawnEvent::new( + uuid, + &pumpkin_data::entity::EntityType::PLAYER, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::EntityDamage(entity_damage_event_data) => { + let uuid = uuid::Uuid::parse_str(&entity_damage_event_data.entity_uuid?.value) + .ok()?; + let pumpkin_event = + pumpkin::plugin::entity::entity_damage::EntityDamageEvent::new( + uuid, + entity_damage_event_data.damage, + pumpkin_data::damage::DamageType::GENERIC, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::EntityDeath(entity_death_event_data) => { + let uuid = uuid::Uuid::parse_str(&entity_death_event_data.entity_uuid?.value) + .ok()?; + let pumpkin_event = + pumpkin::plugin::entity::entity_death::EntityDeathEvent::new( + uuid, + pumpkin_data::damage::DamageType::GENERIC, + ); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::ServerCommand(server_command_event_data) => { + let pumpkin_event = + ServerCommandEvent::new(server_command_event_data.command); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + Data::ServerBroadcast(server_broadcast_event_data) => { + let message = serde_json::from_str(&server_broadcast_event_data.message) + .unwrap_or_else(|_| { + TextComponent::from_legacy_string(&server_broadcast_event_data.message) + }); + let sender = serde_json::from_str(&server_broadcast_event_data.sender) + .unwrap_or_else(|_| { + TextComponent::from_legacy_string(&server_broadcast_event_data.sender) + }); + let pumpkin_event = ServerBroadcastEvent::new(message, sender); + context.server.plugin_manager.fire(pumpkin_event).await; + Some(true) + } + } + }) + })?; + + Some(CallEventResponse { handled }) +} + +fn block_from_key(key: &str) -> &'static Block { + let trimmed = key.strip_prefix("minecraft:").unwrap_or(key); + Block::from_registry_key(trimmed).unwrap_or(&Block::AIR) +} + +fn item_from_key(key: &str) -> ItemStack { + let trimmed = key.strip_prefix("minecraft:").unwrap_or(key); + let item = Item::from_registry_key(trimmed).unwrap_or(&Item::AIR); + ItemStack::new(1, item) +} + +fn item_stack_from_key(key: &str, amount: i32) -> ItemStack { + let trimmed = key.strip_prefix("minecraft:").unwrap_or(key); + let item = Item::from_registry_key(trimmed).unwrap_or(&Item::AIR); + let count = amount.clamp(0, u8::MAX as i32) as u8; + ItemStack::new(count, item) +} + +fn equipment_slot_from_bukkit(slot: &str) -> Option { + match slot { + "HAND" => Some(EquipmentSlot::MAIN_HAND), + "OFF_HAND" => Some(EquipmentSlot::OFF_HAND), + "FEET" => Some(EquipmentSlot::FEET), + "LEGS" => Some(EquipmentSlot::LEGS), + "CHEST" => Some(EquipmentSlot::CHEST), + "HEAD" => Some(EquipmentSlot::HEAD), + "BODY" => Some(EquipmentSlot::BODY), + "SADDLE" => Some(EquipmentSlot::SADDLE), + _ => None, + } +} + +fn bukkit_block_face_to_direction(face: &str) -> Option { + match face { + "UP" => Some(BlockDirection::Up), + "DOWN" => Some(BlockDirection::Down), + "NORTH" => Some(BlockDirection::North), + "SOUTH" => Some(BlockDirection::South), + "WEST" => Some(BlockDirection::West), + "EAST" => Some(BlockDirection::East), + _ => None, + } +} + +fn gamemode_from_bukkit(mode: &str) -> Option { + match mode { + "SURVIVAL" => Some(pumpkin_util::GameMode::Survival), + "CREATIVE" => Some(pumpkin_util::GameMode::Creative), + "ADVENTURE" => Some(pumpkin_util::GameMode::Adventure), + "SPECTATOR" => Some(pumpkin_util::GameMode::Spectator), + _ => None, + } +} + +fn main_hand_from_bukkit(hand: &str) -> Option { + match hand { + "LEFT" => Some(Hand::Left), + "RIGHT" => Some(Hand::Right), + _ => None, + } +} From 6ee1092cbbaeb14ffb51615b65e0f3cb324055a3 Mon Sep 17 00:00:00 2001 From: yunuservices Date: Fri, 6 Feb 2026 01:34:25 +0300 Subject: [PATCH 50/56] Align bridge with local Pumpkin events and verify server-test --- rust/Cargo.lock | 64 +- rust/Cargo.toml | 12 +- rust/build/java.rs | 7 + rust/src/commands/mod.rs | 2 +- rust/src/events/handler.rs | 1325 +++++++++++++++++++++- rust/src/java/native_callbacks/events.rs | 432 ++++++- rust/src/java/plugin/event_manager.rs | 2 +- 7 files changed, 1765 insertions(+), 79 deletions(-) diff --git a/rust/Cargo.lock b/rust/Cargo.lock index b538281..a0949b1 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -50,12 +50,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "allocator-api2" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" - [[package]] name = "annotate-snippets" version = "0.12.11" @@ -549,9 +543,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crossfire" -version = "3.0.3" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9c756fd351d7bc1f95698a33a90ce39c8f7458335cc7e95132d3d36124902a" +checksum = "86db11309bffee9435040d648c13c3efbdbcdcd3ead9872e65ce9dff4c3f79ce" dependencies = [ "crossbeam-utils", "futures-core", @@ -955,9 +949,9 @@ checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" [[package]] name = "flate2" -version = "1.1.8" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b375d6465b98090a5f25b1c7703f3859783755aa9a80433b36e0379a3ec2f369" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" dependencies = [ "crc32fast", "miniz_oxide", @@ -976,12 +970,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" -[[package]] -name = "foldhash" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" - [[package]] name = "form_urlencoded" version = "1.2.2" @@ -1193,7 +1181,7 @@ version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ - "foldhash 0.1.5", + "foldhash", ] [[package]] @@ -1201,11 +1189,6 @@ name = "hashbrown" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" -dependencies = [ - "allocator-api2", - "equivalent", - "foldhash 0.2.0", -] [[package]] name = "heck" @@ -1631,15 +1614,6 @@ version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" -[[package]] -name = "lru" -version = "0.16.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1dc47f592c06f33f8e3aea9591776ec7c9f9e4124778ff8a3c3b87159f7e593" -dependencies = [ - "hashbrown 0.16.1", -] - [[package]] name = "lz4-java-wrc" version = "0.2.0" @@ -2252,13 +2226,11 @@ dependencies = [ [[package]] name = "pumpkin" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#441040105bb8ceb8b118bf84039727e6423046aa" dependencies = [ "arc-swap", "base64", "bytes", "crossbeam", - "dashmap", "flate2", "futures", "hmac 0.13.0-rc.4", @@ -2282,7 +2254,6 @@ dependencies = [ "serde_json", "sha1 0.11.0-rc.4", "sha2 0.11.0-rc.4", - "signature 2.2.0", "simplelog", "thiserror", "time", @@ -2295,7 +2266,6 @@ dependencies = [ [[package]] name = "pumpkin-api-macros" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#441040105bb8ceb8b118bf84039727e6423046aa" dependencies = [ "proc-macro-error2", "proc-macro2", @@ -2306,7 +2276,6 @@ dependencies = [ [[package]] name = "pumpkin-config" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#441040105bb8ceb8b118bf84039727e6423046aa" dependencies = [ "log", "pumpkin-util", @@ -2318,7 +2287,6 @@ dependencies = [ [[package]] name = "pumpkin-data" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#441040105bb8ceb8b118bf84039727e6423046aa" dependencies = [ "crc-fast", "heck", @@ -2338,7 +2306,6 @@ dependencies = [ [[package]] name = "pumpkin-inventory" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#441040105bb8ceb8b118bf84039727e6423046aa" dependencies = [ "crossbeam-utils", "log", @@ -2353,10 +2320,8 @@ dependencies = [ [[package]] name = "pumpkin-macros" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#441040105bb8ceb8b118bf84039727e6423046aa" dependencies = [ "proc-macro-error2", - "proc-macro2", "pumpkin-data", "quote", "syn", @@ -2365,7 +2330,6 @@ dependencies = [ [[package]] name = "pumpkin-nbt" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#441040105bb8ceb8b118bf84039727e6423046aa" dependencies = [ "bytes", "cesu8", @@ -2377,7 +2341,6 @@ dependencies = [ [[package]] name = "pumpkin-protocol" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#441040105bb8ceb8b118bf84039727e6423046aa" dependencies = [ "aes", "async-compression", @@ -2399,7 +2362,6 @@ dependencies = [ [[package]] name = "pumpkin-util" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#441040105bb8ceb8b118bf84039727e6423046aa" dependencies = [ "base64", "bytes", @@ -2424,7 +2386,6 @@ dependencies = [ [[package]] name = "pumpkin-world" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/Pumpkin-MC/Pumpkin.git?branch=master#441040105bb8ceb8b118bf84039727e6423046aa" dependencies = [ "bitflags", "bytes", @@ -2436,7 +2397,6 @@ dependencies = [ "futures", "itertools", "log", - "lru", "lz4-java-wrc", "num-derive", "num-traits", @@ -2453,7 +2413,6 @@ dependencies = [ "sha2 0.11.0-rc.4", "slotmap", "thiserror", - "thread_local", "tokio", "tokio-util", "uuid", @@ -3215,15 +3174,6 @@ dependencies = [ "syn", ] -[[package]] -name = "thread_local" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" -dependencies = [ - "cfg-if", -] - [[package]] name = "time" version = "0.3.46" @@ -4121,9 +4071,9 @@ dependencies = [ [[package]] name = "zlib-rs" -version = "0.5.5" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40990edd51aae2c2b6907af74ffb635029d5788228222c4bb811e9351c0caad3" +checksum = "a7948af682ccbc3342b6e9420e8c51c1fe5d7bf7756002b4a3c6cabfe96a7e3c" [[package]] name = "zmij" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index c82d7e4..346f5ee 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -9,12 +9,12 @@ build = "build/main.rs" crate-type = ["cdylib"] [dependencies] -pumpkin = { git = "https://github.com/Pumpkin-MC/Pumpkin.git", branch = "master", package = "pumpkin" } -pumpkin-data = { git = "https://github.com/Pumpkin-MC/Pumpkin.git", branch = "master", package = "pumpkin-data" } -pumpkin-protocol = { git = "https://github.com/Pumpkin-MC/Pumpkin.git", branch = "master", package = "pumpkin-protocol" } -pumpkin-util = { git = "https://github.com/Pumpkin-MC/Pumpkin.git", branch = "master", package = "pumpkin-util" } -pumpkin-world = { git = "https://github.com/Pumpkin-MC/Pumpkin.git", branch = "master", package = "pumpkin-world" } -pumpkin-api-macros = { git = "https://github.com/Pumpkin-MC/Pumpkin.git", branch = "master", package = "pumpkin-api-macros" } +pumpkin = { path = "../../Pumpkin/pumpkin", package = "pumpkin" } +pumpkin-data = { path = "../../Pumpkin/pumpkin-data", package = "pumpkin-data" } +pumpkin-protocol = { path = "../../Pumpkin/pumpkin-protocol", package = "pumpkin-protocol" } +pumpkin-util = { path = "../../Pumpkin/pumpkin-util", package = "pumpkin-util" } +pumpkin-world = { path = "../../Pumpkin/pumpkin-world", package = "pumpkin-world" } +pumpkin-api-macros = { path = "../../Pumpkin/pumpkin-api-macros", package = "pumpkin-api-macros" } tokio = "1" log = "0.4" diff --git a/rust/build/java.rs b/rust/build/java.rs index 4cd8795..a5cb866 100644 --- a/rust/build/java.rs +++ b/rust/build/java.rs @@ -91,6 +91,13 @@ pub fn setup_java(base: PathBuf) { // These are deps of patchbukkit itself ("io.papermc.paper", "paper-api", "1.21.11-R0.1-SNAPSHOT"), ("com.google.protobuf", "protobuf-java", "4.33.5"), + // Netty for ViaVersion / ViaBackwards + ("io.netty", "netty-common", "4.1.108.Final"), + ("io.netty", "netty-buffer", "4.1.108.Final"), + ("io.netty", "netty-transport", "4.1.108.Final"), + ("io.netty", "netty-codec", "4.1.108.Final"), + ("io.netty", "netty-handler", "4.1.108.Final"), + ("io.netty", "netty-resolver", "4.1.108.Final"), ]; let jvm = JvmBuilder::new() diff --git a/rust/src/commands/mod.rs b/rust/src/commands/mod.rs index 13598b1..9fb37de 100644 --- a/rust/src/commands/mod.rs +++ b/rust/src/commands/mod.rs @@ -142,7 +142,7 @@ impl CommandExecutor for JavaCommandExecutor { }) .await .unwrap(); - Ok(()) + Ok(1) }) } } diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index 1ae08d8..2c0691a 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -7,18 +7,28 @@ use pumpkin::plugin::{BoxFuture, Cancellable, EventHandler, Payload}; use pumpkin::server::Server; use pumpkin::world::World as PumpkinWorld; use pumpkin_api_macros::with_runtime; -use pumpkin_data::Block; +use pumpkin_data::block_properties::Instrument; +use pumpkin_data::data_component_impl::EquipmentSlot; +use pumpkin_data::item::Item; +use pumpkin_data::{Block, BlockDirection}; +use pumpkin_util::Hand; use pumpkin_util::math::vector3::Vector3; use pumpkin_util::text::TextComponent; +use pumpkin_world::item::ItemStack; use tokio::sync::{mpsc, oneshot}; use crate::java::jvm::commands::JvmCommand; use crate::proto::patchbukkit::common::{Location, Uuid, Vec3, World as ProtoWorld}; use crate::proto::patchbukkit::events::event::Data; use crate::proto::patchbukkit::events::{ - BlockBreakEvent, BlockBurnEvent, BlockCanBuildEvent, BlockPlaceEvent, Event, PlayerChangeWorldEvent, - PlayerChatEvent, PlayerCommandSendEvent, PlayerGamemodeChangeEvent, PlayerInteractEvent, PlayerJoinEvent, - PlayerLeaveEvent, PlayerLoginEvent, PlayerMoveEvent, PlayerTeleportEvent, ServerBroadcastEvent, ServerCommandEvent, + BlockBreakEvent, BlockBurnEvent, BlockCanBuildEvent, BlockDispenseEvent, BlockFormEvent, BlockIgniteEvent, + BlockMultiPlaceBlockEntry, BlockMultiPlaceEvent, BlockPlaceEvent, BlockRedstoneEvent, Event, MoistureChangeEvent, + NotePlayEvent, PlayerBedEnterEvent, PlayerBucketEmptyEvent, PlayerBucketFillEvent, PlayerChangeWorldEvent, + PlayerChatEvent, PlayerCommandSendEvent, PlayerDropItemEvent, PlayerExpChangeEvent, PlayerGamemodeChangeEvent, + PlayerInteractEvent, PlayerItemBreakEvent, PlayerItemConsumeEvent, PlayerItemDamageEvent, PlayerItemHeldEvent, + PlayerItemMendEvent, PlayerJoinEvent, PlayerKickEvent, PlayerLeaveEvent, PlayerLevelChangeEvent, PlayerLoginEvent, + PlayerMoveEvent, PlayerTeleportEvent, PlayerToggleFlightEvent, ServerBroadcastEvent, ServerCommandEvent, + SignChangeEvent, TntPrimeEvent, }; pub struct EventContext { @@ -354,7 +364,7 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_command_s player_uuid: Some(Uuid { value: self.player.gameprofile.id.to_string(), }), - commands: vec![self.command.clone()], + commands: self.commands.clone(), })), }, context: EventContext { @@ -367,8 +377,8 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_command_s fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { match data { Data::PlayerCommandSend(event) => { - if let Some(command) = event.commands.first() { - self.command = command.clone(); + if !event.commands.is_empty() { + self.commands = event.commands; } } _ => {} @@ -679,6 +689,1117 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::server::server_broadcast } } +impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_bed_enter::PlayerBedEnterEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let world_uuid = self.player.world().uuid; + + JvmEventPayload { + event: Event { + data: Some(Data::PlayerBedEnter(PlayerBedEnterEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + bed_location: Some(build_location(world_uuid, &self.bed_position, 0.0, 0.0)), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerBedEnter(event) => { + if let Some(location) = event.bed_location { + if let Some(pos) = location_to_vec3(location) { + self.bed_position = pos; + } + } + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_bucket_empty::PlayerBucketEmptyEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let world_uuid = self.player.world().uuid; + JvmEventPayload { + event: Event { + data: Some(Data::PlayerBucketEmpty(PlayerBucketEmptyEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + location: Some(build_location(world_uuid, &self.position, 0.0, 0.0)), + block_key: self.block_key.clone(), + block_face: block_face_to_bukkit(self.face), + bucket_item_key: self.bucket_item_key.clone(), + hand: self.hand.clone(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerBucketEmpty(event) => { + if let Some(location) = event.location { + if let Some(pos) = location_to_vec3(location) { + self.position = pos; + } + } + if !event.block_key.is_empty() { + self.block_key = event.block_key; + } + if !event.bucket_item_key.is_empty() { + self.bucket_item_key = event.bucket_item_key; + } + if !event.hand.is_empty() { + self.hand = event.hand; + } + self.face = bukkit_block_face_from_string(&event.block_face); + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_bucket_fill::PlayerBucketFillEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let world_uuid = self.player.world().uuid; + JvmEventPayload { + event: Event { + data: Some(Data::PlayerBucketFill(PlayerBucketFillEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + location: Some(build_location(world_uuid, &self.position, 0.0, 0.0)), + block_key: self.block_key.clone(), + block_face: block_face_to_bukkit(self.face), + bucket_item_key: self.bucket_item_key.clone(), + hand: self.hand.clone(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerBucketFill(event) => { + if let Some(location) = event.location { + if let Some(pos) = location_to_vec3(location) { + self.position = pos; + } + } + if !event.block_key.is_empty() { + self.block_key = event.block_key; + } + if !event.bucket_item_key.is_empty() { + self.bucket_item_key = event.bucket_item_key; + } + if !event.hand.is_empty() { + self.hand = event.hand; + } + self.face = bukkit_block_face_from_string(&event.block_face); + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_drop_item::PlayerDropItemEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerDropItem(PlayerDropItemEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + item_uuid: Some(Uuid { + value: self.item_uuid.to_string(), + }), + item_key: item_to_key(self.item_stack.item), + item_amount: i32::from(self.item_stack.item_count), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerDropItem(event) => { + if let Some(uuid) = event.item_uuid { + if let Ok(item_uuid) = uuid::Uuid::from_str(&uuid.value) { + self.item_uuid = item_uuid; + } + } + let mut key = if event.item_key.is_empty() { + None + } else { + Some(event.item_key) + }; + let mut amount = if event.item_amount > 0 { + Some(event.item_amount as u8) + } else { + None + }; + + if key.is_some() || amount.is_some() { + let fallback_key = item_to_key(self.item_stack.item); + let key = key.take().unwrap_or(fallback_key); + let count = amount.take().unwrap_or(self.item_stack.item_count); + self.item_stack = item_stack_from_key(&key, count); + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_exp_change::PlayerExpChangeEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerExpChange(PlayerExpChangeEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + amount: self.amount, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerExpChange(event) => { + self.amount = event.amount; + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_item_break::PlayerItemBreakEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerItemBreak(PlayerItemBreakEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + item_key: item_to_key(self.item_stack.item), + item_amount: i32::from(self.item_stack.item_count), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerItemBreak(event) => { + let mut key = if event.item_key.is_empty() { + None + } else { + Some(event.item_key) + }; + let mut amount = if event.item_amount > 0 { + Some(event.item_amount as u8) + } else { + None + }; + + if key.is_some() || amount.is_some() { + let fallback_key = item_to_key(self.item_stack.item); + let key = key.take().unwrap_or(fallback_key); + let count = amount.take().unwrap_or(self.item_stack.item_count); + self.item_stack = item_stack_from_key(&key, count); + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_item_consume::PlayerItemConsumeEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let hand = match self.hand { + Hand::Left => "OFF_HAND", + Hand::Right => "HAND", + }; + JvmEventPayload { + event: Event { + data: Some(Data::PlayerItemConsume(PlayerItemConsumeEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + item_key: item_to_key(self.item_stack.item), + item_amount: i32::from(self.item_stack.item_count), + hand: hand.to_string(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerItemConsume(event) => { + if !event.hand.is_empty() { + self.hand = if event.hand == "OFF_HAND" { + Hand::Left + } else { + Hand::Right + }; + } + + let mut key = if event.item_key.is_empty() { + None + } else { + Some(event.item_key) + }; + let mut amount = if event.item_amount > 0 { + Some(event.item_amount as u8) + } else { + None + }; + + if key.is_some() || amount.is_some() { + let fallback_key = item_to_key(self.item_stack.item); + let key = key.take().unwrap_or(fallback_key); + let count = amount.take().unwrap_or(self.item_stack.item_count); + self.item_stack = item_stack_from_key(&key, count); + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_item_damage::PlayerItemDamageEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerItemDamage(PlayerItemDamageEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + item_key: item_to_key(self.item_stack.item), + item_amount: i32::from(self.item_stack.item_count), + damage: self.damage, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerItemDamage(event) => { + self.damage = event.damage; + let mut key = if event.item_key.is_empty() { + None + } else { + Some(event.item_key) + }; + let mut amount = if event.item_amount > 0 { + Some(event.item_amount as u8) + } else { + None + }; + + if key.is_some() || amount.is_some() { + let fallback_key = item_to_key(self.item_stack.item); + let key = key.take().unwrap_or(fallback_key); + let count = amount.take().unwrap_or(self.item_stack.item_count); + self.item_stack = item_stack_from_key(&key, count); + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_item_held::PlayerItemHeldEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerItemHeld(PlayerItemHeldEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + previous_slot: self.previous_slot, + new_slot: self.new_slot, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerItemHeld(event) => { + self.previous_slot = event.previous_slot; + self.new_slot = event.new_slot; + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_item_mend::PlayerItemMendEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerItemMend(PlayerItemMendEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + item_key: item_to_key(self.item_stack.item), + item_amount: i32::from(self.item_stack.item_count), + slot: equipment_slot_to_bukkit(&self.slot), + repair_amount: self.repair_amount, + orb_uuid: self.orb_uuid.map(|id| Uuid { value: id.to_string() }), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerItemMend(event) => { + self.repair_amount = event.repair_amount; + if !event.slot.is_empty() { + if let Some(slot) = equipment_slot_from_bukkit(&event.slot) { + self.slot = slot; + } + } + if let Some(uuid) = event.orb_uuid { + if let Ok(orb_uuid) = uuid::Uuid::from_str(&uuid.value) { + self.orb_uuid = Some(orb_uuid); + } + } + let mut key = if event.item_key.is_empty() { + None + } else { + Some(event.item_key) + }; + let mut amount = if event.item_amount > 0 { + Some(event.item_amount as u8) + } else { + None + }; + + if key.is_some() || amount.is_some() { + let fallback_key = item_to_key(self.item_stack.item); + let key = key.take().unwrap_or(fallback_key); + let count = amount.take().unwrap_or(self.item_stack.item_count); + self.item_stack = item_stack_from_key(&key, count); + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_kick::PlayerKickEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerKick(PlayerKickEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + reason: serde_json::to_string(&self.reason).unwrap_or_default(), + leave_message: serde_json::to_string(&self.leave_message).unwrap_or_default(), + cause: self.cause.clone(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerKick(event) => { + if !event.reason.is_empty() { + if let Ok(reason) = serde_json::from_str(&event.reason) { + self.reason = reason; + } + } + if !event.leave_message.is_empty() { + if let Ok(msg) = serde_json::from_str(&event.leave_message) { + self.leave_message = msg; + } + } + if !event.cause.is_empty() { + self.cause = event.cause; + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_level_change::PlayerLevelChangeEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerLevelChange(PlayerLevelChangeEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + old_level: self.old_level, + new_level: self.new_level, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerLevelChange(event) => { + self.old_level = event.old_level; + self.new_level = event.new_level; + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_toggle_flight::PlayerToggleFlightEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + JvmEventPayload { + event: Event { + data: Some(Data::PlayerToggleFlight(PlayerToggleFlightEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + is_flying: self.is_flying, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::PlayerToggleFlight(event) => { + self.is_flying = event.is_flying; + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::api::events::block::block_dispense::BlockDispenseEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let world_uuid = server + .worlds + .load() + .first() + .map(|world| world.uuid) + .unwrap_or_default(); + let location = build_location( + world_uuid, + &Vector3::new( + f64::from(self.block_position.0.x), + f64::from(self.block_position.0.y), + f64::from(self.block_position.0.z), + ), + 0.0, + 0.0, + ); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockDispense(BlockDispenseEvent { + block_key: block_to_key(self.block), + location: Some(location), + item_key: item_to_key(self.item_stack.item), + item_amount: i32::from(self.item_stack.item_count), + velocity: Some(Vec3 { + x: self.velocity.x, + y: self.velocity.y, + z: self.velocity.z, + }), + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::BlockDispense(event) => { + if !event.item_key.is_empty() || event.item_amount > 0 { + let key = if event.item_key.is_empty() { + item_to_key(self.item_stack.item) + } else { + event.item_key + }; + let count = if event.item_amount > 0 { + event.item_amount as u8 + } else { + self.item_stack.item_count + }; + self.item_stack = item_stack_from_key(&key, count); + } + if let Some(vel) = event.velocity { + self.velocity = Vector3::new(vel.x, vel.y, vel.z); + } + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::api::events::block::block_form::BlockFormEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockForm(BlockFormEvent { + block_key: block_to_key(self.old_block), + new_block_key: block_to_key(self.new_block), + location: Some(location), + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::BlockForm(event) => { + if !event.new_block_key.is_empty() { + if let Some(block) = Block::from_name(&event.new_block_key) { + self.new_block = block; + } + } + if let Some(loc) = event.location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + } + if !event.block_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_key) { + self.old_block = block; + } + } + } + _ => {} + } + + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::api::events::block::block_ignite::BlockIgniteEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockIgnite(BlockIgniteEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + block_key: block_to_key(self.block), + igniting_block_key: block_to_key(self.igniting_block), + location: Some(location), + cause: self.cause.clone(), + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::BlockIgnite(event) => { + if !event.block_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_key) { + self.block = block; + } + } + if !event.igniting_block_key.is_empty() { + if let Some(block) = Block::from_name(&event.igniting_block_key) { + self.igniting_block = block; + } + } + if let Some(loc) = event.location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + if let Some(world) = loc.world.and_then(|w| w.uuid) { + if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { + self.world_uuid = uuid; + } + } + } + if !event.cause.is_empty() { + self.cause = event.cause; + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::api::events::block::block_multi_place::BlockMultiPlaceEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let world_uuid = self.player.world().uuid; + let origin = self + .positions + .first() + .copied() + .unwrap_or_else(|| self.player.position().to_block_pos()); + let location = build_location( + world_uuid, + &Vector3::new( + f64::from(origin.0.x), + f64::from(origin.0.y), + f64::from(origin.0.z), + ), + 0.0, + 0.0, + ); + let blocks = self + .positions + .iter() + .map(|pos| { + let loc = build_location( + world_uuid, + &Vector3::new(f64::from(pos.0.x), f64::from(pos.0.y), f64::from(pos.0.z)), + 0.0, + 0.0, + ); + BlockMultiPlaceBlockEntry { + block_key: block_to_key(self.block_placed), + location: Some(loc), + } + }) + .collect(); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockMultiPlace(BlockMultiPlaceEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + block_key: block_to_key(self.block_placed), + location: Some(location), + blocks, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, _data: Data) -> Option<()> { + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::api::events::block::block_redstone::BlockRedstoneEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let world_uuid = server + .worlds + .load() + .first() + .map(|world| world.uuid) + .unwrap_or_default(); + let location = build_location( + world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + + JvmEventPayload { + event: Event { + data: Some(Data::BlockRedstone(BlockRedstoneEvent { + block_key: block_to_key(self.block), + location: Some(location), + old_current: self.old_current, + new_current: self.new_current, + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::BlockRedstone(event) => { + self.new_current = event.new_current; + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::api::events::block::moisture_change::MoistureChangeEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + let new_block_key = block_to_key(Block::from_state_id(self.new_state_id)); + + JvmEventPayload { + event: Event { + data: Some(Data::MoistureChange(MoistureChangeEvent { + block_key: block_to_key(self.block), + location: Some(location), + new_block_key, + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::MoistureChange(event) => { + if !event.block_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_key) { + self.block = block; + } + } + if let Some(loc) = event.location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + if let Some(world) = loc.world.and_then(|w| w.uuid) { + if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { + self.world_uuid = uuid; + } + } + } + if !event.new_block_key.is_empty() { + if let Some(block) = Block::from_name(&event.new_block_key) { + self.new_state_id = block.default_state.id; + } + } + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::api::events::block::note_play::NotePlayEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + + JvmEventPayload { + event: Event { + data: Some(Data::NotePlay(NotePlayEvent { + block_key: block_to_key(self.block), + location: Some(location), + instrument: instrument_to_bukkit(self.instrument), + note: i32::from(self.note), + })), + }, + context: EventContext { server, player: None }, + } + } + + fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { + match data { + Data::NotePlay(event) => { + if !event.block_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_key) { + self.block = block; + } + } + if let Some(loc) = event.location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + if let Some(world) = loc.world.and_then(|w| w.uuid) { + if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { + self.world_uuid = uuid; + } + } + } + if !event.instrument.is_empty() { + if let Some(instrument) = instrument_from_bukkit(&event.instrument) { + self.instrument = instrument; + } + } + self.note = event.note.clamp(0, 24) as u8; + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::api::events::block::sign_change::SignChangeEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let world_uuid = self.player.world().uuid; + let location = build_location( + world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + + JvmEventPayload { + event: Event { + data: Some(Data::SignChange(SignChangeEvent { + player_uuid: Some(Uuid { + value: self.player.gameprofile.id.to_string(), + }), + block_key: block_to_key(self.block), + location: Some(location), + lines: self.lines.clone(), + is_front_text: self.is_front_text, + })), + }, + context: EventContext { + server, + player: Some(self.player.clone()), + }, + } + } + + fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { + match data { + Data::SignChange(event) => { + if let Some(uuid) = event.player_uuid { + if let Ok(uuid) = uuid::Uuid::from_str(&uuid.value) { + if let Some(player) = server.get_player_by_uuid(uuid) { + self.player = player; + } + } + } + if !event.block_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_key) { + self.block = block; + } + } + if let Some(loc) = event.location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + } + if !event.lines.is_empty() { + self.lines = event.lines; + } + self.is_front_text = event.is_front_text; + } + _ => {} + } + Some(()) + } +} + +impl PatchBukkitEvent for pumpkin::plugin::api::events::block::tnt_prime::TNTPrimeEvent { + fn to_payload(&self, server: Arc) -> JvmEventPayload { + let location = build_location( + self.world_uuid, + &Vector3::new( + f64::from(self.block_pos.0.x), + f64::from(self.block_pos.0.y), + f64::from(self.block_pos.0.z), + ), + 0.0, + 0.0, + ); + let player_uuid = self.player.as_ref().map(|player| Uuid { + value: player.gameprofile.id.to_string(), + }); + + JvmEventPayload { + event: Event { + data: Some(Data::TntPrime(TntPrimeEvent { + player_uuid, + block_key: block_to_key(self.block), + location: Some(location), + cause: self.cause.clone(), + })), + }, + context: EventContext { + server, + player: self.player.clone(), + }, + } + } + + fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { + match data { + Data::TntPrime(event) => { + if let Some(uuid) = event.player_uuid { + if let Ok(uuid) = uuid::Uuid::from_str(&uuid.value) { + self.player = server.get_player_by_uuid(uuid); + } + } else { + self.player = None; + } + if !event.block_key.is_empty() { + if let Some(block) = Block::from_name(&event.block_key) { + self.block = block; + } + } + if let Some(loc) = event.location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + if let Some(world) = loc.world.and_then(|w| w.uuid) { + if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { + self.world_uuid = uuid; + } + } + } + if !event.cause.is_empty() { + self.cause = event.cause; + } + } + _ => {} + } + Some(()) + } +} + fn build_location(world_uuid: uuid::Uuid, position: &Vector3, yaw: f32, pitch: f32) -> Location { Location { world: Some(ProtoWorld { @@ -705,10 +1826,43 @@ fn block_to_key(block: &Block) -> String { format!("minecraft:{}", block.name) } -fn item_to_key(item: &pumpkin_data::item::Item) -> String { +fn item_to_key(item: &Item) -> String { format!("minecraft:{}", item.registry_key) } +fn item_stack_from_key(key: &str, amount: u8) -> ItemStack { + let trimmed = key.strip_prefix("minecraft:").unwrap_or(key); + let item = Item::from_registry_key(trimmed).unwrap_or(&Item::AIR); + ItemStack::new(amount, item) +} + +fn equipment_slot_to_bukkit(slot: &EquipmentSlot) -> String { + match slot { + EquipmentSlot::MainHand(_) => "HAND".to_string(), + EquipmentSlot::OffHand(_) => "OFF_HAND".to_string(), + EquipmentSlot::Feet(_) => "FEET".to_string(), + EquipmentSlot::Legs(_) => "LEGS".to_string(), + EquipmentSlot::Chest(_) => "CHEST".to_string(), + EquipmentSlot::Head(_) => "HEAD".to_string(), + EquipmentSlot::Body(_) => "BODY".to_string(), + EquipmentSlot::Saddle(_) => "SADDLE".to_string(), + } +} + +fn equipment_slot_from_bukkit(slot: &str) -> Option { + match slot { + "HAND" => Some(EquipmentSlot::MAIN_HAND), + "OFF_HAND" => Some(EquipmentSlot::OFF_HAND), + "FEET" => Some(EquipmentSlot::FEET), + "LEGS" => Some(EquipmentSlot::LEGS), + "CHEST" => Some(EquipmentSlot::CHEST), + "HEAD" => Some(EquipmentSlot::HEAD), + "BODY" => Some(EquipmentSlot::BODY), + "SADDLE" => Some(EquipmentSlot::SADDLE), + _ => None, + } +} + fn find_world_by_uuid(server: &Arc, world_uuid: uuid::Uuid) -> Option> { server .worlds @@ -737,6 +1891,87 @@ fn gamemode_from_bukkit(mode: &str) -> Option { } } +fn block_face_to_bukkit(face: Option) -> String { + match face { + Some(BlockDirection::Up) => "UP".to_string(), + Some(BlockDirection::Down) => "DOWN".to_string(), + Some(BlockDirection::North) => "NORTH".to_string(), + Some(BlockDirection::South) => "SOUTH".to_string(), + Some(BlockDirection::West) => "WEST".to_string(), + Some(BlockDirection::East) => "EAST".to_string(), + None => String::new(), + } +} + +fn bukkit_block_face_from_string(face: &str) -> Option { + match face { + "UP" => Some(BlockDirection::Up), + "DOWN" => Some(BlockDirection::Down), + "NORTH" => Some(BlockDirection::North), + "SOUTH" => Some(BlockDirection::South), + "WEST" => Some(BlockDirection::West), + "EAST" => Some(BlockDirection::East), + _ => None, + } +} + +fn instrument_to_bukkit(instrument: Instrument) -> String { + match instrument { + Instrument::Harp => "PIANO".to_string(), + Instrument::Basedrum => "BASS_DRUM".to_string(), + Instrument::Snare => "SNARE_DRUM".to_string(), + Instrument::Hat => "STICKS".to_string(), + Instrument::Bass => "BASS_GUITAR".to_string(), + Instrument::Flute => "FLUTE".to_string(), + Instrument::Bell => "BELL".to_string(), + Instrument::Guitar => "GUITAR".to_string(), + Instrument::Chime => "CHIME".to_string(), + Instrument::Xylophone => "XYLOPHONE".to_string(), + Instrument::IronXylophone => "IRON_XYLOPHONE".to_string(), + Instrument::CowBell => "COW_BELL".to_string(), + Instrument::Didgeridoo => "DIDGERIDOO".to_string(), + Instrument::Bit => "BIT".to_string(), + Instrument::Banjo => "BANJO".to_string(), + Instrument::Pling => "PLING".to_string(), + Instrument::Zombie => "ZOMBIE".to_string(), + Instrument::Skeleton => "SKELETON".to_string(), + Instrument::Creeper => "CREEPER".to_string(), + Instrument::Dragon => "DRAGON".to_string(), + Instrument::WitherSkeleton => "WITHER_SKELETON".to_string(), + Instrument::Piglin => "PIGLIN".to_string(), + Instrument::CustomHead => "CUSTOM_HEAD".to_string(), + } +} + +fn instrument_from_bukkit(name: &str) -> Option { + match name { + "PIANO" => Some(Instrument::Harp), + "BASS_DRUM" => Some(Instrument::Basedrum), + "SNARE_DRUM" => Some(Instrument::Snare), + "STICKS" => Some(Instrument::Hat), + "BASS_GUITAR" => Some(Instrument::Bass), + "FLUTE" => Some(Instrument::Flute), + "BELL" => Some(Instrument::Bell), + "GUITAR" => Some(Instrument::Guitar), + "CHIME" => Some(Instrument::Chime), + "XYLOPHONE" => Some(Instrument::Xylophone), + "IRON_XYLOPHONE" => Some(Instrument::IronXylophone), + "COW_BELL" => Some(Instrument::CowBell), + "DIDGERIDOO" => Some(Instrument::Didgeridoo), + "BIT" => Some(Instrument::Bit), + "BANJO" => Some(Instrument::Banjo), + "PLING" => Some(Instrument::Pling), + "ZOMBIE" => Some(Instrument::Zombie), + "SKELETON" => Some(Instrument::Skeleton), + "CREEPER" => Some(Instrument::Creeper), + "DRAGON" => Some(Instrument::Dragon), + "WITHER_SKELETON" => Some(Instrument::WitherSkeleton), + "PIGLIN" => Some(Instrument::Piglin), + "CUSTOM_HEAD" => Some(Instrument::CustomHead), + _ => None, + } +} + fn interact_action_to_bukkit( action: &pumpkin::plugin::api::events::player::player_interact_event::InteractAction, ) -> String { @@ -782,6 +2017,75 @@ pub struct PatchBukkitEventHandler { _phantom: PhantomData, } +trait CancellationBridge { + fn apply_cancelled(&mut self, cancelled: bool); +} + +macro_rules! impl_cancellation_bridge { + ($($ty:path),+ $(,)?) => { + $( + impl CancellationBridge for $ty { + fn apply_cancelled(&mut self, cancelled: bool) { + self.set_cancelled(cancelled); + } + } + )+ + }; +} + +impl_cancellation_bridge!( + pumpkin::plugin::api::events::player::player_join::PlayerJoinEvent, + pumpkin::plugin::api::events::player::player_login::PlayerLoginEvent, + pumpkin::plugin::api::events::player::player_leave::PlayerLeaveEvent, + pumpkin::plugin::api::events::player::player_move::PlayerMoveEvent, + pumpkin::plugin::api::events::player::player_teleport::PlayerTeleportEvent, + pumpkin::plugin::api::events::player::player_change_world::PlayerChangeWorldEvent, + pumpkin::plugin::api::events::player::player_gamemode_change::PlayerGamemodeChangeEvent, + pumpkin::plugin::api::events::player::player_chat::PlayerChatEvent, + pumpkin::plugin::api::events::player::player_interact_event::PlayerInteractEvent, + pumpkin::plugin::api::events::player::player_bed_enter::PlayerBedEnterEvent, + pumpkin::plugin::api::events::player::player_bucket_empty::PlayerBucketEmptyEvent, + pumpkin::plugin::api::events::player::player_bucket_fill::PlayerBucketFillEvent, + pumpkin::plugin::api::events::player::player_drop_item::PlayerDropItemEvent, + pumpkin::plugin::api::events::player::player_item_consume::PlayerItemConsumeEvent, + pumpkin::plugin::api::events::player::player_item_damage::PlayerItemDamageEvent, + pumpkin::plugin::api::events::player::player_item_held::PlayerItemHeldEvent, + pumpkin::plugin::api::events::player::player_item_mend::PlayerItemMendEvent, + pumpkin::plugin::api::events::player::player_kick::PlayerKickEvent, + pumpkin::plugin::api::events::player::player_toggle_flight::PlayerToggleFlightEvent, + pumpkin::plugin::api::events::block::block_break::BlockBreakEvent, + pumpkin::plugin::api::events::block::block_burn::BlockBurnEvent, + pumpkin::plugin::api::events::block::block_can_build::BlockCanBuildEvent, + pumpkin::plugin::api::events::block::block_place::BlockPlaceEvent, + pumpkin::plugin::api::events::block::block_dispense::BlockDispenseEvent, + pumpkin::plugin::api::events::block::block_form::BlockFormEvent, + pumpkin::plugin::api::events::block::block_ignite::BlockIgniteEvent, + pumpkin::plugin::api::events::block::block_multi_place::BlockMultiPlaceEvent, + pumpkin::plugin::api::events::block::block_redstone::BlockRedstoneEvent, + pumpkin::plugin::api::events::block::moisture_change::MoistureChangeEvent, + pumpkin::plugin::api::events::block::note_play::NotePlayEvent, + pumpkin::plugin::api::events::block::sign_change::SignChangeEvent, + pumpkin::plugin::api::events::block::tnt_prime::TNTPrimeEvent, + pumpkin::plugin::api::events::server::server_command::ServerCommandEvent, + pumpkin::plugin::api::events::server::server_broadcast::ServerBroadcastEvent, +); + +impl CancellationBridge for pumpkin::plugin::api::events::player::player_command_send::PlayerCommandSendEvent { + fn apply_cancelled(&mut self, _cancelled: bool) {} +} + +impl CancellationBridge for pumpkin::plugin::api::events::player::player_exp_change::PlayerExpChangeEvent { + fn apply_cancelled(&mut self, _cancelled: bool) {} +} + +impl CancellationBridge for pumpkin::plugin::api::events::player::player_item_break::PlayerItemBreakEvent { + fn apply_cancelled(&mut self, _cancelled: bool) {} +} + +impl CancellationBridge for pumpkin::plugin::api::events::player::player_level_change::PlayerLevelChangeEvent { + fn apply_cancelled(&mut self, _cancelled: bool) {} +} + impl PatchBukkitEventHandler { #[must_use] pub const fn new(plugin_name: String, command_tx: mpsc::Sender) -> Self { @@ -796,7 +2100,7 @@ impl PatchBukkitEventHandler { #[with_runtime(global)] impl EventHandler for PatchBukkitEventHandler where - E: PatchBukkitEvent + Payload + Cancellable + 'static, + E: PatchBukkitEvent + Payload + CancellationBridge + 'static, { fn handle_blocking<'a>( &'a self, @@ -821,7 +2125,7 @@ where match rx.await { Ok(response) => { - event.set_cancelled(response.cancelled); + event.apply_cancelled(response.cancelled); if let Some(data) = response.data.and_then(|d| d.data) { event.apply_modifications(server, data); } @@ -833,3 +2137,4 @@ where }) } } + diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index 86e3847..e5c3d24 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -1,8 +1,9 @@ use std::sync::Arc; use pumpkin::plugin::EventPriority; -use pumpkin_data::Block; +use pumpkin_data::{Block, BlockDirection}; use pumpkin_data::item::Item; +use pumpkin_util::math::position::BlockPos; use pumpkin_world::item::ItemStack; use pumpkin_util::math::vector3::Vector3; use pumpkin_util::text::TextComponent; @@ -310,7 +311,380 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O ) .await; } - _ => { + "org.bukkit.event.player.PlayerBedEnterEvent" => { + context + .register_event::< + pumpkin::plugin::api::events::player::player_bed_enter::PlayerBedEnterEvent, + PatchBukkitEventHandler< + pumpkin::plugin::api::events::player::player_bed_enter::PlayerBedEnterEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerBucketEmptyEvent" => { + context + .register_event::< + pumpkin::plugin::api::events::player::player_bucket_empty::PlayerBucketEmptyEvent, + PatchBukkitEventHandler< + pumpkin::plugin::api::events::player::player_bucket_empty::PlayerBucketEmptyEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerBucketFillEvent" => { + context + .register_event::< + pumpkin::plugin::api::events::player::player_bucket_fill::PlayerBucketFillEvent, + PatchBukkitEventHandler< + pumpkin::plugin::api::events::player::player_bucket_fill::PlayerBucketFillEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerDropItemEvent" => { + context + .register_event::< + pumpkin::plugin::api::events::player::player_drop_item::PlayerDropItemEvent, + PatchBukkitEventHandler< + pumpkin::plugin::api::events::player::player_drop_item::PlayerDropItemEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerExpChangeEvent" => { + context + .register_event::< + pumpkin::plugin::api::events::player::player_exp_change::PlayerExpChangeEvent, + PatchBukkitEventHandler< + pumpkin::plugin::api::events::player::player_exp_change::PlayerExpChangeEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerItemBreakEvent" => { + context + .register_event::< + pumpkin::plugin::api::events::player::player_item_break::PlayerItemBreakEvent, + PatchBukkitEventHandler< + pumpkin::plugin::api::events::player::player_item_break::PlayerItemBreakEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerItemConsumeEvent" => { + context + .register_event::< + pumpkin::plugin::api::events::player::player_item_consume::PlayerItemConsumeEvent, + PatchBukkitEventHandler< + pumpkin::plugin::api::events::player::player_item_consume::PlayerItemConsumeEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerItemDamageEvent" => { + context + .register_event::< + pumpkin::plugin::api::events::player::player_item_damage::PlayerItemDamageEvent, + PatchBukkitEventHandler< + pumpkin::plugin::api::events::player::player_item_damage::PlayerItemDamageEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerItemHeldEvent" => { + context + .register_event::< + pumpkin::plugin::api::events::player::player_item_held::PlayerItemHeldEvent, + PatchBukkitEventHandler< + pumpkin::plugin::api::events::player::player_item_held::PlayerItemHeldEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerItemMendEvent" => { + context + .register_event::< + pumpkin::plugin::api::events::player::player_item_mend::PlayerItemMendEvent, + PatchBukkitEventHandler< + pumpkin::plugin::api::events::player::player_item_mend::PlayerItemMendEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerKickEvent" => { + context + .register_event::< + pumpkin::plugin::api::events::player::player_kick::PlayerKickEvent, + PatchBukkitEventHandler< + pumpkin::plugin::api::events::player::player_kick::PlayerKickEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerLevelChangeEvent" => { + context + .register_event::< + pumpkin::plugin::api::events::player::player_level_change::PlayerLevelChangeEvent, + PatchBukkitEventHandler< + pumpkin::plugin::api::events::player::player_level_change::PlayerLevelChangeEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.player.PlayerToggleFlightEvent" => { + context + .register_event::< + pumpkin::plugin::api::events::player::player_toggle_flight::PlayerToggleFlightEvent, + PatchBukkitEventHandler< + pumpkin::plugin::api::events::player::player_toggle_flight::PlayerToggleFlightEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.BlockDispenseEvent" => { + context + .register_event::< + pumpkin::plugin::api::events::block::block_dispense::BlockDispenseEvent, + PatchBukkitEventHandler< + pumpkin::plugin::api::events::block::block_dispense::BlockDispenseEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.BlockFormEvent" => { + context + .register_event::< + pumpkin::plugin::api::events::block::block_form::BlockFormEvent, + PatchBukkitEventHandler< + pumpkin::plugin::api::events::block::block_form::BlockFormEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.BlockIgniteEvent" => { + context + .register_event::< + pumpkin::plugin::api::events::block::block_ignite::BlockIgniteEvent, + PatchBukkitEventHandler< + pumpkin::plugin::api::events::block::block_ignite::BlockIgniteEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.BlockMultiPlaceEvent" => { + context + .register_event::< + pumpkin::plugin::api::events::block::block_multi_place::BlockMultiPlaceEvent, + PatchBukkitEventHandler< + pumpkin::plugin::api::events::block::block_multi_place::BlockMultiPlaceEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.BlockRedstoneEvent" => { + context + .register_event::< + pumpkin::plugin::api::events::block::block_redstone::BlockRedstoneEvent, + PatchBukkitEventHandler< + pumpkin::plugin::api::events::block::block_redstone::BlockRedstoneEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.MoistureChangeEvent" => { + context + .register_event::< + pumpkin::plugin::api::events::block::moisture_change::MoistureChangeEvent, + PatchBukkitEventHandler< + pumpkin::plugin::api::events::block::moisture_change::MoistureChangeEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.NotePlayEvent" => { + context + .register_event::< + pumpkin::plugin::api::events::block::note_play::NotePlayEvent, + PatchBukkitEventHandler< + pumpkin::plugin::api::events::block::note_play::NotePlayEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.SignChangeEvent" => { + context + .register_event::< + pumpkin::plugin::api::events::block::sign_change::SignChangeEvent, + PatchBukkitEventHandler< + pumpkin::plugin::api::events::block::sign_change::SignChangeEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } + "org.bukkit.event.block.TNTPrimeEvent" => { + context + .register_event::< + pumpkin::plugin::api::events::block::tnt_prime::TNTPrimeEvent, + PatchBukkitEventHandler< + pumpkin::plugin::api::events::block::tnt_prime::TNTPrimeEvent, + >, + >( + Arc::new(PatchBukkitEventHandler::new( + request.plugin_name.clone(), + command_tx.clone(), + )), + pumpkin_priority, + request.blocking, + ) + .await; + } _ => { log::warn!("Unsupported Bukkit event registration: {}", request.event_type); } } @@ -352,11 +726,15 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { let uuid = uuid::Uuid::parse_str(&event.player_uuid?.value).ok()?; let player = ctx.plugin_context.server.get_player_by_uuid(uuid)?; - let command = event.commands.first().cloned().unwrap_or_default(); + let commands = if event.commands.is_empty() { + vec![String::new()] + } else { + event.commands + }; let pumpkin_event = pumpkin::plugin::api::events::player::player_command_send::PlayerCommandSendEvent::new( player, - command, + commands, ); ctx.plugin_context.server.plugin_manager.fire(pumpkin_event).await; Some(true) @@ -381,13 +759,17 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option Option { let block = block_from_key(&event.block_key); let igniting_block = block_from_key(&event.igniting_block_key); + let block_pos = location_to_block_pos(event.location.as_ref()); + let world_uuid = + location_world_uuid(event.location.as_ref(), &ctx.plugin_context.server); let pumpkin_event = pumpkin::plugin::api::events::block::block_burn::BlockBurnEvent { igniting_block, block, + block_pos, + world_uuid, cancelled: false, }; ctx.plugin_context.server.plugin_manager.fire(pumpkin_event).await; @@ -512,12 +899,14 @@ pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option Option Option { } } +fn block_face_from_bukkit(face: &str) -> Option { + match face { + "DOWN" => Some(BlockDirection::Down), + "UP" => Some(BlockDirection::Up), + "NORTH" => Some(BlockDirection::North), + "SOUTH" => Some(BlockDirection::South), + "WEST" => Some(BlockDirection::West), + "EAST" => Some(BlockDirection::East), + _ => None, + } +} + +fn location_to_block_pos(location: Option<&crate::proto::patchbukkit::common::Location>) -> BlockPos { + let pos = location.and_then(|loc| loc.position.clone()); + match pos { + Some(pos) => BlockPos::new(pos.x.floor() as i32, pos.y.floor() as i32, pos.z.floor() as i32), + None => BlockPos::new(0, 0, 0), + } +} + +fn location_world_uuid( + location: Option<&crate::proto::patchbukkit::common::Location>, + server: &std::sync::Arc, +) -> uuid::Uuid { + location + .and_then(|loc| loc.world.as_ref()) + .and_then(|world| world.uuid.as_ref()) + .and_then(|id| uuid::Uuid::parse_str(&id.value).ok()) + .or_else(|| server.worlds.load().first().map(|world| world.uuid)) + .unwrap_or_else(uuid::Uuid::new_v4) +} + fn find_world_by_uuid( server: &std::sync::Arc, world_uuid: uuid::Uuid, @@ -607,3 +1030,4 @@ fn find_world_by_uuid( .cloned() } + diff --git a/rust/src/java/plugin/event_manager.rs b/rust/src/java/plugin/event_manager.rs index f295f98..e24e549 100644 --- a/rust/src/java/plugin/event_manager.rs +++ b/rust/src/java/plugin/event_manager.rs @@ -35,7 +35,7 @@ impl EventManager { let event_manager = jvm.invoke(&patch_server, "getEventManager", InvocationArg::empty())?; if let Some(ref event) = payload.event.data - && matches!(event, Data::PlayerJoin(_)) + && matches!(event, Data::PlayerJoin(_) | Data::PlayerLogin(_)) && let Some(ref player) = payload.context.player { Self::register_player(jvm, &patch_server, player, &payload.context.server)?; From 63e874a816d2d7acbc37f761928efed0158508b5 Mon Sep 17 00:00:00 2001 From: yunuservices Date: Fri, 6 Feb 2026 02:06:10 +0300 Subject: [PATCH 51/56] Use git-based Pumpkin dependencies on feat/events --- rust/Cargo.lock | 36 +++++++++++++++++++++++------------- rust/Cargo.toml | 12 ++++++------ 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/rust/Cargo.lock b/rust/Cargo.lock index a0949b1..e9549f9 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -316,13 +316,13 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chacha20" -version = "0.10.0-rc.9" +version = "0.10.0-rc.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c81d916c6ae06736ec667b51f95ee5ff660a75f4ea6ce1bd932c942365c0ea43" +checksum = "14f3c04cdd19f5ed3271e460267fb1d94b7899ae1f7bb10ac3dfc3afb749d659" dependencies = [ "cfg-if", "cpufeatures", - "rand_core 0.10.0-rc-6", + "rand_core 0.10.0", ] [[package]] @@ -573,7 +573,7 @@ checksum = "053c3561863ce55e3226ecc48b08679f4b66cb1b92b9afb42c2c402dfe8b9b51" dependencies = [ "ctutils", "num-traits", - "rand_core 0.10.0-rc-6", + "rand_core 0.10.0", "serdect", "zeroize", ] @@ -605,7 +605,7 @@ checksum = "334a79c97c0b7fa536716dc132fd417d0afbf471440a41fc25a5d9f66d8771cd" dependencies = [ "crypto-bigint 0.7.0-rc.22", "libm", - "rand_core 0.10.0-rc-6", + "rand_core 0.10.0", ] [[package]] @@ -1141,7 +1141,7 @@ dependencies = [ "cfg-if", "libc", "r-efi", - "rand_core 0.10.0-rc-6", + "rand_core 0.10.0", "wasip2", "wasip3", ] @@ -2226,6 +2226,7 @@ dependencies = [ [[package]] name = "pumpkin" version = "0.1.0-dev+1.21.11" +source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#5d8bd30994a1e303fe4ecd9ba0873e093f6d3128" dependencies = [ "arc-swap", "base64", @@ -2266,6 +2267,7 @@ dependencies = [ [[package]] name = "pumpkin-api-macros" version = "0.1.0-dev+1.21.11" +source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#5d8bd30994a1e303fe4ecd9ba0873e093f6d3128" dependencies = [ "proc-macro-error2", "proc-macro2", @@ -2276,6 +2278,7 @@ dependencies = [ [[package]] name = "pumpkin-config" version = "0.1.0-dev+1.21.11" +source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#5d8bd30994a1e303fe4ecd9ba0873e093f6d3128" dependencies = [ "log", "pumpkin-util", @@ -2287,6 +2290,7 @@ dependencies = [ [[package]] name = "pumpkin-data" version = "0.1.0-dev+1.21.11" +source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#5d8bd30994a1e303fe4ecd9ba0873e093f6d3128" dependencies = [ "crc-fast", "heck", @@ -2306,6 +2310,7 @@ dependencies = [ [[package]] name = "pumpkin-inventory" version = "0.1.0-dev+1.21.11" +source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#5d8bd30994a1e303fe4ecd9ba0873e093f6d3128" dependencies = [ "crossbeam-utils", "log", @@ -2320,6 +2325,7 @@ dependencies = [ [[package]] name = "pumpkin-macros" version = "0.1.0-dev+1.21.11" +source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#5d8bd30994a1e303fe4ecd9ba0873e093f6d3128" dependencies = [ "proc-macro-error2", "pumpkin-data", @@ -2330,6 +2336,7 @@ dependencies = [ [[package]] name = "pumpkin-nbt" version = "0.1.0-dev+1.21.11" +source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#5d8bd30994a1e303fe4ecd9ba0873e093f6d3128" dependencies = [ "bytes", "cesu8", @@ -2341,6 +2348,7 @@ dependencies = [ [[package]] name = "pumpkin-protocol" version = "0.1.0-dev+1.21.11" +source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#5d8bd30994a1e303fe4ecd9ba0873e093f6d3128" dependencies = [ "aes", "async-compression", @@ -2362,6 +2370,7 @@ dependencies = [ [[package]] name = "pumpkin-util" version = "0.1.0-dev+1.21.11" +source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#5d8bd30994a1e303fe4ecd9ba0873e093f6d3128" dependencies = [ "base64", "bytes", @@ -2386,6 +2395,7 @@ dependencies = [ [[package]] name = "pumpkin-world" version = "0.1.0-dev+1.21.11" +source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#5d8bd30994a1e303fe4ecd9ba0873e093f6d3128" dependencies = [ "bitflags", "bytes", @@ -2445,12 +2455,12 @@ dependencies = [ [[package]] name = "rand" -version = "0.10.0-rc.8" -source = "git+https://github.com/rust-random/rand#a4c9a8e565fa310de423e3ba89593b647b721e8c" +version = "0.10.0-rc.9" +source = "git+https://github.com/rust-random/rand#72afe1e973fcd83d840cf597888223072bbdb04c" dependencies = [ "chacha20", "getrandom 0.4.0-rc.1", - "rand_core 0.10.0-rc-6", + "rand_core 0.10.0", ] [[package]] @@ -2464,9 +2474,9 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.10.0-rc-6" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70765ff7112b0fb2d272d24d9a2f907fc206211304328fe58b2db15a5649ef28" +checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" [[package]] name = "rayon" @@ -2573,7 +2583,7 @@ dependencies = [ "digest 0.11.0-rc.9", "pkcs1", "pkcs8 0.11.0-rc.10", - "rand_core 0.10.0-rc-6", + "rand_core 0.10.0", "sha1 0.11.0-rc.4", "signature 3.0.0-rc.9", "spki 0.8.0-rc.4", @@ -2949,7 +2959,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ad0ce3b3f8efd7406f22e2ca5d02be21cdf3b3d1d53ab141f784de8965c7c7e" dependencies = [ "digest 0.11.0-rc.9", - "rand_core 0.10.0-rc-6", + "rand_core 0.10.0", ] [[package]] diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 346f5ee..ea94e55 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -9,12 +9,12 @@ build = "build/main.rs" crate-type = ["cdylib"] [dependencies] -pumpkin = { path = "../../Pumpkin/pumpkin", package = "pumpkin" } -pumpkin-data = { path = "../../Pumpkin/pumpkin-data", package = "pumpkin-data" } -pumpkin-protocol = { path = "../../Pumpkin/pumpkin-protocol", package = "pumpkin-protocol" } -pumpkin-util = { path = "../../Pumpkin/pumpkin-util", package = "pumpkin-util" } -pumpkin-world = { path = "../../Pumpkin/pumpkin-world", package = "pumpkin-world" } -pumpkin-api-macros = { path = "../../Pumpkin/pumpkin-api-macros", package = "pumpkin-api-macros" } +pumpkin = { git = "https://github.com/yunuservices/Pumpkin.git", branch = "feat/events", package = "pumpkin" } +pumpkin-data = { git = "https://github.com/yunuservices/Pumpkin.git", branch = "feat/events", package = "pumpkin-data" } +pumpkin-protocol = { git = "https://github.com/yunuservices/Pumpkin.git", branch = "feat/events", package = "pumpkin-protocol" } +pumpkin-util = { git = "https://github.com/yunuservices/Pumpkin.git", branch = "feat/events", package = "pumpkin-util" } +pumpkin-world = { git = "https://github.com/yunuservices/Pumpkin.git", branch = "feat/events", package = "pumpkin-world" } +pumpkin-api-macros = { git = "https://github.com/yunuservices/Pumpkin.git", branch = "feat/events", package = "pumpkin-api-macros" } tokio = "1" log = "0.4" From 258062cffe0f18d7c137f0643d5b78ac4f853a1c Mon Sep 17 00:00:00 2001 From: yunuservices Date: Fri, 6 Feb 2026 07:32:10 +0300 Subject: [PATCH 52/56] Refresh lockfile after rebasing Pumpkin feat/events --- rust/Cargo.lock | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/rust/Cargo.lock b/rust/Cargo.lock index e9549f9..a11442f 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -2226,7 +2226,7 @@ dependencies = [ [[package]] name = "pumpkin" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#5d8bd30994a1e303fe4ecd9ba0873e093f6d3128" +source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#27bcdb85c43cac7d332c10ef0238219896affb8f" dependencies = [ "arc-swap", "base64", @@ -2267,7 +2267,7 @@ dependencies = [ [[package]] name = "pumpkin-api-macros" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#5d8bd30994a1e303fe4ecd9ba0873e093f6d3128" +source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#27bcdb85c43cac7d332c10ef0238219896affb8f" dependencies = [ "proc-macro-error2", "proc-macro2", @@ -2278,7 +2278,7 @@ dependencies = [ [[package]] name = "pumpkin-config" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#5d8bd30994a1e303fe4ecd9ba0873e093f6d3128" +source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#27bcdb85c43cac7d332c10ef0238219896affb8f" dependencies = [ "log", "pumpkin-util", @@ -2290,7 +2290,7 @@ dependencies = [ [[package]] name = "pumpkin-data" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#5d8bd30994a1e303fe4ecd9ba0873e093f6d3128" +source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#27bcdb85c43cac7d332c10ef0238219896affb8f" dependencies = [ "crc-fast", "heck", @@ -2310,7 +2310,7 @@ dependencies = [ [[package]] name = "pumpkin-inventory" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#5d8bd30994a1e303fe4ecd9ba0873e093f6d3128" +source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#27bcdb85c43cac7d332c10ef0238219896affb8f" dependencies = [ "crossbeam-utils", "log", @@ -2325,7 +2325,7 @@ dependencies = [ [[package]] name = "pumpkin-macros" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#5d8bd30994a1e303fe4ecd9ba0873e093f6d3128" +source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#27bcdb85c43cac7d332c10ef0238219896affb8f" dependencies = [ "proc-macro-error2", "pumpkin-data", @@ -2336,7 +2336,7 @@ dependencies = [ [[package]] name = "pumpkin-nbt" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#5d8bd30994a1e303fe4ecd9ba0873e093f6d3128" +source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#27bcdb85c43cac7d332c10ef0238219896affb8f" dependencies = [ "bytes", "cesu8", @@ -2348,7 +2348,7 @@ dependencies = [ [[package]] name = "pumpkin-protocol" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#5d8bd30994a1e303fe4ecd9ba0873e093f6d3128" +source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#27bcdb85c43cac7d332c10ef0238219896affb8f" dependencies = [ "aes", "async-compression", @@ -2370,7 +2370,7 @@ dependencies = [ [[package]] name = "pumpkin-util" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#5d8bd30994a1e303fe4ecd9ba0873e093f6d3128" +source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#27bcdb85c43cac7d332c10ef0238219896affb8f" dependencies = [ "base64", "bytes", @@ -2395,7 +2395,7 @@ dependencies = [ [[package]] name = "pumpkin-world" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#5d8bd30994a1e303fe4ecd9ba0873e093f6d3128" +source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#27bcdb85c43cac7d332c10ef0238219896affb8f" dependencies = [ "bitflags", "bytes", @@ -3395,9 +3395,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "ureq" -version = "3.1.4" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d39cb1dbab692d82a977c0392ffac19e188bd9186a9f32806f0aaa859d75585a" +checksum = "fdc97a28575b85cfedf2a7e7d3cc64b3e11bd8ac766666318003abbacc7a21fc" dependencies = [ "base64", "cookie_store", From 635f40d55130401c437c1024e355bb6d2e573514 Mon Sep 17 00:00:00 2001 From: yunuservices Date: Fri, 6 Feb 2026 14:01:15 +0300 Subject: [PATCH 53/56] Fix critical bridge issues for ignite and world mapping --- .../events/PatchBukkitEventFactory.java | 30 ++++++++++++------- .../events/PatchBukkitEventManager.java | 18 ++++++----- rust/Cargo.lock | 20 ++++++------- rust/src/events/handler.rs | 16 ++-------- 4 files changed, 42 insertions(+), 42 deletions(-) diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index 99cdc2b..2f35b0e 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -1806,8 +1806,12 @@ yield new PlayerStatisticIncrementEvent( } case BLOCK_IGNITE -> { patchbukkit.events.BlockIgniteEvent igniteEvent = event.getBlockIgnite(); - Player player = getPlayer(igniteEvent.getPlayerUuid().getValue()); - if (player == null) yield null; + Player player = null; + if (igniteEvent.hasPlayerUuid() + && igniteEvent.getPlayerUuid() != null + && !igniteEvent.getPlayerUuid().getValue().isEmpty()) { + player = getPlayer(igniteEvent.getPlayerUuid().getValue()); + } Location location = BridgeUtils.convertLocation(igniteEvent.getLocation()); if (location == null || !(location.getWorld() instanceof PatchBukkitWorld world)) { yield null; @@ -3134,16 +3138,20 @@ public static byte[] toFireEventResponse(@NotNull org.bukkit.event.Event event) String ignitingKey = ignitingBlock != null ? ignitingBlock.getType().getKey().toString() : "minecraft:fire"; - eventBuilder.setBlockIgnite( - patchbukkit.events.BlockIgniteEvent.newBuilder() - .setPlayerUuid(UUID.newBuilder() + var igniteBuilder = patchbukkit.events.BlockIgniteEvent.newBuilder() + .setBlockKey(block.getType().getKey().toString()) + .setIgnitingBlockKey(ignitingKey) + .setLocation(BridgeUtils.convertLocation(block.getLocation())) + .setCause(cause); + if (igniteEvent.getPlayer() != null) { + igniteBuilder.setPlayerUuid( + UUID.newBuilder() .setValue(igniteEvent.getPlayer().getUniqueId().toString()) - .build()) - .setBlockKey(block.getType().getKey().toString()) - .setIgnitingBlockKey(ignitingKey) - .setLocation(BridgeUtils.convertLocation(block.getLocation())) - .setCause(cause) - .build() + .build() + ); + } + eventBuilder.setBlockIgnite( + igniteBuilder.build() ); } else if (event instanceof BlockSpreadEvent spreadEvent) { Block block = spreadEvent.getBlock(); 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 67625e3..2edda3a 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventManager.java @@ -1488,15 +1488,19 @@ public void callEvent(@NotNull Event event) throws IllegalStateException { String igniteKey = igniteSource != null ? igniteSource.getType().getKey().toString() : "minecraft:fire"; + var igniteBuilder = patchbukkit.events.BlockIgniteEvent.newBuilder() + .setBlockKey(igniteBlock.getType().getKey().toString()) + .setIgnitingBlockKey(igniteKey) + .setLocation(BridgeUtils.convertLocation(igniteBlock.getLocation())) + .setCause(igniteCause); + if (igniteEvent.getPlayer() != null) { + igniteBuilder.setPlayerUuid( + BridgeUtils.convertUuid(igniteEvent.getPlayer().getUniqueId()) + ); + } request.setEvent( patchbukkit.events.Event.newBuilder().setBlockIgnite( - patchbukkit.events.BlockIgniteEvent.newBuilder() - .setPlayerUuid(BridgeUtils.convertUuid(igniteEvent.getPlayer().getUniqueId())) - .setBlockKey(igniteBlock.getType().getKey().toString()) - .setIgnitingBlockKey(igniteKey) - .setLocation(BridgeUtils.convertLocation(igniteBlock.getLocation())) - .setCause(igniteCause) - .build() + igniteBuilder.build() ).build() ); break; diff --git a/rust/Cargo.lock b/rust/Cargo.lock index a11442f..a8d2835 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -2226,7 +2226,7 @@ dependencies = [ [[package]] name = "pumpkin" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#27bcdb85c43cac7d332c10ef0238219896affb8f" +source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#235fbcf70cf686a7f14e5b19ccb279d7ac5d4f5e" dependencies = [ "arc-swap", "base64", @@ -2267,7 +2267,7 @@ dependencies = [ [[package]] name = "pumpkin-api-macros" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#27bcdb85c43cac7d332c10ef0238219896affb8f" +source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#235fbcf70cf686a7f14e5b19ccb279d7ac5d4f5e" dependencies = [ "proc-macro-error2", "proc-macro2", @@ -2278,7 +2278,7 @@ dependencies = [ [[package]] name = "pumpkin-config" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#27bcdb85c43cac7d332c10ef0238219896affb8f" +source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#235fbcf70cf686a7f14e5b19ccb279d7ac5d4f5e" dependencies = [ "log", "pumpkin-util", @@ -2290,7 +2290,7 @@ dependencies = [ [[package]] name = "pumpkin-data" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#27bcdb85c43cac7d332c10ef0238219896affb8f" +source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#235fbcf70cf686a7f14e5b19ccb279d7ac5d4f5e" dependencies = [ "crc-fast", "heck", @@ -2310,7 +2310,7 @@ dependencies = [ [[package]] name = "pumpkin-inventory" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#27bcdb85c43cac7d332c10ef0238219896affb8f" +source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#235fbcf70cf686a7f14e5b19ccb279d7ac5d4f5e" dependencies = [ "crossbeam-utils", "log", @@ -2325,7 +2325,7 @@ dependencies = [ [[package]] name = "pumpkin-macros" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#27bcdb85c43cac7d332c10ef0238219896affb8f" +source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#235fbcf70cf686a7f14e5b19ccb279d7ac5d4f5e" dependencies = [ "proc-macro-error2", "pumpkin-data", @@ -2336,7 +2336,7 @@ dependencies = [ [[package]] name = "pumpkin-nbt" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#27bcdb85c43cac7d332c10ef0238219896affb8f" +source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#235fbcf70cf686a7f14e5b19ccb279d7ac5d4f5e" dependencies = [ "bytes", "cesu8", @@ -2348,7 +2348,7 @@ dependencies = [ [[package]] name = "pumpkin-protocol" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#27bcdb85c43cac7d332c10ef0238219896affb8f" +source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#235fbcf70cf686a7f14e5b19ccb279d7ac5d4f5e" dependencies = [ "aes", "async-compression", @@ -2370,7 +2370,7 @@ dependencies = [ [[package]] name = "pumpkin-util" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#27bcdb85c43cac7d332c10ef0238219896affb8f" +source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#235fbcf70cf686a7f14e5b19ccb279d7ac5d4f5e" dependencies = [ "base64", "bytes", @@ -2395,7 +2395,7 @@ dependencies = [ [[package]] name = "pumpkin-world" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#27bcdb85c43cac7d332c10ef0238219896affb8f" +source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#235fbcf70cf686a7f14e5b19ccb279d7ac5d4f5e" dependencies = [ "bitflags", "bytes", diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index 2c0691a..1392830 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -1253,14 +1253,8 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_toggle_fl impl PatchBukkitEvent for pumpkin::plugin::api::events::block::block_dispense::BlockDispenseEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { - let world_uuid = server - .worlds - .load() - .first() - .map(|world| world.uuid) - .unwrap_or_default(); let location = build_location( - world_uuid, + self.world_uuid, &Vector3::new( f64::from(self.block_position.0.x), f64::from(self.block_position.0.y), @@ -1499,14 +1493,8 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::block::block_multi_place impl PatchBukkitEvent for pumpkin::plugin::api::events::block::block_redstone::BlockRedstoneEvent { fn to_payload(&self, server: Arc) -> JvmEventPayload { - let world_uuid = server - .worlds - .load() - .first() - .map(|world| world.uuid) - .unwrap_or_default(); let location = build_location( - world_uuid, + self.world_uuid, &Vector3::new( f64::from(self.block_pos.0.x), f64::from(self.block_pos.0.y), From 54da03fed14f7549c1b46f0f0a3d82668c851c92 Mon Sep 17 00:00:00 2001 From: yunuservices Date: Fri, 6 Feb 2026 14:22:22 +0300 Subject: [PATCH 54/56] chore(rust): bump Pumpkin dependency lock to ba0410c3 --- rust/Cargo.lock | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/rust/Cargo.lock b/rust/Cargo.lock index a8d2835..b14a5b5 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -2226,7 +2226,7 @@ dependencies = [ [[package]] name = "pumpkin" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#235fbcf70cf686a7f14e5b19ccb279d7ac5d4f5e" +source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#ba0410c324819ba5cfb693ac722e3a0bb3bab378" dependencies = [ "arc-swap", "base64", @@ -2267,7 +2267,7 @@ dependencies = [ [[package]] name = "pumpkin-api-macros" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#235fbcf70cf686a7f14e5b19ccb279d7ac5d4f5e" +source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#ba0410c324819ba5cfb693ac722e3a0bb3bab378" dependencies = [ "proc-macro-error2", "proc-macro2", @@ -2278,7 +2278,7 @@ dependencies = [ [[package]] name = "pumpkin-config" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#235fbcf70cf686a7f14e5b19ccb279d7ac5d4f5e" +source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#ba0410c324819ba5cfb693ac722e3a0bb3bab378" dependencies = [ "log", "pumpkin-util", @@ -2290,7 +2290,7 @@ dependencies = [ [[package]] name = "pumpkin-data" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#235fbcf70cf686a7f14e5b19ccb279d7ac5d4f5e" +source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#ba0410c324819ba5cfb693ac722e3a0bb3bab378" dependencies = [ "crc-fast", "heck", @@ -2310,7 +2310,7 @@ dependencies = [ [[package]] name = "pumpkin-inventory" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#235fbcf70cf686a7f14e5b19ccb279d7ac5d4f5e" +source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#ba0410c324819ba5cfb693ac722e3a0bb3bab378" dependencies = [ "crossbeam-utils", "log", @@ -2325,7 +2325,7 @@ dependencies = [ [[package]] name = "pumpkin-macros" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#235fbcf70cf686a7f14e5b19ccb279d7ac5d4f5e" +source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#ba0410c324819ba5cfb693ac722e3a0bb3bab378" dependencies = [ "proc-macro-error2", "pumpkin-data", @@ -2336,7 +2336,7 @@ dependencies = [ [[package]] name = "pumpkin-nbt" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#235fbcf70cf686a7f14e5b19ccb279d7ac5d4f5e" +source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#ba0410c324819ba5cfb693ac722e3a0bb3bab378" dependencies = [ "bytes", "cesu8", @@ -2348,7 +2348,7 @@ dependencies = [ [[package]] name = "pumpkin-protocol" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#235fbcf70cf686a7f14e5b19ccb279d7ac5d4f5e" +source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#ba0410c324819ba5cfb693ac722e3a0bb3bab378" dependencies = [ "aes", "async-compression", @@ -2370,7 +2370,7 @@ dependencies = [ [[package]] name = "pumpkin-util" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#235fbcf70cf686a7f14e5b19ccb279d7ac5d4f5e" +source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#ba0410c324819ba5cfb693ac722e3a0bb3bab378" dependencies = [ "base64", "bytes", @@ -2395,7 +2395,7 @@ dependencies = [ [[package]] name = "pumpkin-world" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#235fbcf70cf686a7f14e5b19ccb279d7ac5d4f5e" +source = "git+https://github.com/yunuservices/Pumpkin.git?branch=feat%2Fevents#ba0410c324819ba5cfb693ac722e3a0bb3bab378" dependencies = [ "bitflags", "bytes", From 1dd858f764fbd6dded0395a7da340ff27f3ed24c Mon Sep 17 00:00:00 2001 From: yunuservices Date: Fri, 6 Feb 2026 14:35:51 +0300 Subject: [PATCH 55/56] fix(rust): resolve clippy warnings in event bridge handlers --- rust/src/events/handler.rs | 1180 +++++++++++----------- rust/src/java/native_callbacks/block.rs | 4 +- rust/src/java/native_callbacks/events.rs | 24 +- 3 files changed, 592 insertions(+), 616 deletions(-) diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index 1392830..92404fb 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -1,4 +1,4 @@ -use std::marker::PhantomData; +use std::marker::PhantomData; use std::str::FromStr; use std::sync::Arc; @@ -21,14 +21,16 @@ use crate::java::jvm::commands::JvmCommand; use crate::proto::patchbukkit::common::{Location, Uuid, Vec3, World as ProtoWorld}; use crate::proto::patchbukkit::events::event::Data; use crate::proto::patchbukkit::events::{ - BlockBreakEvent, BlockBurnEvent, BlockCanBuildEvent, BlockDispenseEvent, BlockFormEvent, BlockIgniteEvent, - BlockMultiPlaceBlockEntry, BlockMultiPlaceEvent, BlockPlaceEvent, BlockRedstoneEvent, Event, MoistureChangeEvent, - NotePlayEvent, PlayerBedEnterEvent, PlayerBucketEmptyEvent, PlayerBucketFillEvent, PlayerChangeWorldEvent, - PlayerChatEvent, PlayerCommandSendEvent, PlayerDropItemEvent, PlayerExpChangeEvent, PlayerGamemodeChangeEvent, - PlayerInteractEvent, PlayerItemBreakEvent, PlayerItemConsumeEvent, PlayerItemDamageEvent, PlayerItemHeldEvent, - PlayerItemMendEvent, PlayerJoinEvent, PlayerKickEvent, PlayerLeaveEvent, PlayerLevelChangeEvent, PlayerLoginEvent, - PlayerMoveEvent, PlayerTeleportEvent, PlayerToggleFlightEvent, ServerBroadcastEvent, ServerCommandEvent, - SignChangeEvent, TntPrimeEvent, + BlockBreakEvent, BlockBurnEvent, BlockCanBuildEvent, BlockDispenseEvent, BlockFormEvent, + BlockIgniteEvent, BlockMultiPlaceBlockEntry, BlockMultiPlaceEvent, BlockPlaceEvent, + BlockRedstoneEvent, Event, MoistureChangeEvent, NotePlayEvent, PlayerBedEnterEvent, + PlayerBucketEmptyEvent, PlayerBucketFillEvent, PlayerChangeWorldEvent, PlayerChatEvent, + PlayerCommandSendEvent, PlayerDropItemEvent, PlayerExpChangeEvent, PlayerGamemodeChangeEvent, + PlayerInteractEvent, PlayerItemBreakEvent, PlayerItemConsumeEvent, PlayerItemDamageEvent, + PlayerItemHeldEvent, PlayerItemMendEvent, PlayerJoinEvent, PlayerKickEvent, PlayerLeaveEvent, + PlayerLevelChangeEvent, PlayerLoginEvent, PlayerMoveEvent, PlayerTeleportEvent, + PlayerToggleFlightEvent, ServerBroadcastEvent, ServerCommandEvent, SignChangeEvent, + TntPrimeEvent, }; pub struct EventContext { @@ -65,12 +67,9 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_join::Pla } fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerJoin(event) => { - self.join_message = serde_json::from_str(&event.join_message).ok()?; - server.get_player_by_uuid(uuid::Uuid::from_str(&event.player_uuid?.value).ok()?)?; - } - _ => {} + if let Data::PlayerJoin(event) = data { + self.join_message = serde_json::from_str(&event.join_message).ok()?; + server.get_player_by_uuid(uuid::Uuid::from_str(&event.player_uuid?.value).ok()?)?; } Some(()) @@ -96,12 +95,9 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_login::Pl } fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerLogin(event) => { - self.kick_message = serde_json::from_str(&event.kick_message).ok()?; - server.get_player_by_uuid(uuid::Uuid::from_str(&event.player_uuid?.value).ok()?)?; - } - _ => {} + if let Data::PlayerLogin(event) = data { + self.kick_message = serde_json::from_str(&event.kick_message).ok()?; + server.get_player_by_uuid(uuid::Uuid::from_str(&event.player_uuid?.value).ok()?)?; } Some(()) @@ -127,12 +123,9 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_leave::Pl } fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerLeave(event) => { - self.leave_message = serde_json::from_str(&event.leave_message).ok()?; - server.get_player_by_uuid(uuid::Uuid::from_str(&event.player_uuid?.value).ok()?)?; - } - _ => {} + if let Data::PlayerLeave(event) = data { + self.leave_message = serde_json::from_str(&event.leave_message).ok()?; + server.get_player_by_uuid(uuid::Uuid::from_str(&event.player_uuid?.value).ok()?)?; } Some(()) @@ -160,23 +153,22 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_move::Pla } fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerMove(event) => { - if let Some(from) = event.from.and_then(location_to_vec3) { - self.from = from; - } - if let Some(to) = event.to.and_then(location_to_vec3) { - self.to = to; - } + if let Data::PlayerMove(event) = data { + if let Some(from) = event.from.and_then(location_to_vec3) { + self.from = from; + } + if let Some(to) = event.to.and_then(location_to_vec3) { + self.to = to; } - _ => {} } Some(()) } } -impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_teleport::PlayerTeleportEvent { +impl PatchBukkitEvent + for pumpkin::plugin::api::events::player::player_teleport::PlayerTeleportEvent +{ fn to_payload(&self, server: Arc) -> JvmEventPayload { let world_uuid = self.player.world().uuid; JvmEventPayload { @@ -198,23 +190,22 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_teleport: } fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerTeleport(event) => { - if let Some(from) = event.from.and_then(location_to_vec3) { - self.from = from; - } - if let Some(to) = event.to.and_then(location_to_vec3) { - self.to = to; - } + if let Data::PlayerTeleport(event) = data { + if let Some(from) = event.from.and_then(location_to_vec3) { + self.from = from; + } + if let Some(to) = event.to.and_then(location_to_vec3) { + self.to = to; } - _ => {} } Some(()) } } -impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_change_world::PlayerChangeWorldEvent { +impl PatchBukkitEvent + for pumpkin::plugin::api::events::player::player_change_world::PlayerChangeWorldEvent +{ fn to_payload(&self, server: Arc) -> JvmEventPayload { JvmEventPayload { event: Event { @@ -232,7 +223,12 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_change_wo value: self.new_world.uuid.to_string(), }), }), - position: Some(build_location(self.new_world.uuid, &self.position, self.yaw, self.pitch)), + position: Some(build_location( + self.new_world.uuid, + &self.position, + self.yaw, + self.pitch, + )), yaw: self.yaw, pitch: self.pitch, })), @@ -245,34 +241,33 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_change_wo } fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerChangeWorld(event) => { - if let Some(world) = event.previous_world.and_then(|w| w.uuid) { - self.previous_world = - find_world_by_uuid(server, uuid::Uuid::from_str(&world.value).ok()?)?; - } - if let Some(world) = event.new_world.and_then(|w| w.uuid) { - self.new_world = - find_world_by_uuid(server, uuid::Uuid::from_str(&world.value).ok()?)?; - } - if let Some(position) = event.position.and_then(location_to_vec3) { - self.position = position; - } - if event.yaw != 0.0 { - self.yaw = event.yaw; - } - if event.pitch != 0.0 { - self.pitch = event.pitch; - } + if let Data::PlayerChangeWorld(event) = data { + if let Some(world) = event.previous_world.and_then(|w| w.uuid) { + self.previous_world = + find_world_by_uuid(server, uuid::Uuid::from_str(&world.value).ok()?)?; + } + if let Some(world) = event.new_world.and_then(|w| w.uuid) { + self.new_world = + find_world_by_uuid(server, uuid::Uuid::from_str(&world.value).ok()?)?; + } + if let Some(position) = event.position.and_then(location_to_vec3) { + self.position = position; + } + if event.yaw != 0.0 { + self.yaw = event.yaw; + } + if event.pitch != 0.0 { + self.pitch = event.pitch; } - _ => {} } Some(()) } } -impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_gamemode_change::PlayerGamemodeChangeEvent { +impl PatchBukkitEvent + for pumpkin::plugin::api::events::player::player_gamemode_change::PlayerGamemodeChangeEvent +{ fn to_payload(&self, server: Arc) -> JvmEventPayload { JvmEventPayload { event: Event { @@ -292,16 +287,13 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_gamemode_ } fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerGamemodeChange(event) => { - if let Some(mode) = gamemode_from_bukkit(&event.previous_gamemode) { - self.previous_gamemode = mode; - } - if let Some(mode) = gamemode_from_bukkit(&event.new_gamemode) { - self.new_gamemode = mode; - } + if let Data::PlayerGamemodeChange(event) = data { + if let Some(mode) = gamemode_from_bukkit(&event.previous_gamemode) { + self.previous_gamemode = mode; + } + if let Some(mode) = gamemode_from_bukkit(&event.new_gamemode) { + self.new_gamemode = mode; } - _ => {} } Some(()) } @@ -334,29 +326,28 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_chat::Pla } fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerChat(event) => { - if !event.message.is_empty() { - self.message = event.message; - } - if !event.recipients.is_empty() { - let mut recipients = Vec::new(); - for uuid in event.recipients { - let player_uuid = uuid::Uuid::from_str(&uuid.value).ok()?; - if let Some(player) = server.get_player_by_uuid(player_uuid) { - recipients.push(player); - } + if let Data::PlayerChat(event) = data { + if !event.message.is_empty() { + self.message = event.message; + } + if !event.recipients.is_empty() { + let mut recipients = Vec::new(); + for uuid in event.recipients { + let player_uuid = uuid::Uuid::from_str(&uuid.value).ok()?; + if let Some(player) = server.get_player_by_uuid(player_uuid) { + recipients.push(player); } - self.recipients = recipients; } + self.recipients = recipients; } - _ => {} } Some(()) } } -impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_command_send::PlayerCommandSendEvent { +impl PatchBukkitEvent + for pumpkin::plugin::api::events::player::player_command_send::PlayerCommandSendEvent +{ fn to_payload(&self, server: Arc) -> JvmEventPayload { JvmEventPayload { event: Event { @@ -375,19 +366,18 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_command_s } fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerCommandSend(event) => { - if !event.commands.is_empty() { - self.commands = event.commands; - } - } - _ => {} + if let Data::PlayerCommandSend(event) = data + && !event.commands.is_empty() + { + self.commands = event.commands; } Some(()) } } -impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_interact_event::PlayerInteractEvent { +impl PatchBukkitEvent + for pumpkin::plugin::api::events::player::player_interact_event::PlayerInteractEvent +{ fn to_payload(&self, server: Arc) -> JvmEventPayload { let world_uuid = self.player.world().uuid; let clicked = self.clicked_pos.as_ref().map(|pos| { @@ -426,25 +416,22 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_interact_ } fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerInteract(event) => { - if let Some(action) = interact_action_from_bukkit(&event.action) { - self.action = action; - } - if let Some(loc) = event.clicked.and_then(location_to_vec3) { - self.clicked_pos = Some(pumpkin_util::math::position::BlockPos::new( - loc.x.floor() as i32, - loc.y.floor() as i32, - loc.z.floor() as i32, - )); - } - if !event.block_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_key) { - self.block = block; - } - } + if let Data::PlayerInteract(event) = data { + if let Some(action) = interact_action_from_bukkit(&event.action) { + self.action = action; + } + if let Some(loc) = event.clicked.and_then(location_to_vec3) { + self.clicked_pos = Some(pumpkin_util::math::position::BlockPos::new( + loc.x.floor() as i32, + loc.y.floor() as i32, + loc.z.floor() as i32, + )); + } + if !event.block_key.is_empty() + && let Some(block) = Block::from_name(&event.block_key) + { + self.block = block; } - _ => {} } Some(()) } @@ -489,17 +476,14 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::block::block_break::Bloc } fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockBreak(event) => { - if !event.block_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_key) { - self.block = block; - } - } - self.exp = event.exp; - self.drop = event.drop; + if let Data::BlockBreak(event) = data { + if !event.block_key.is_empty() + && let Some(block) = Block::from_name(&event.block_key) + { + self.block = block; } - _ => {} + self.exp = event.exp; + self.drop = event.drop; } Some(()) } @@ -515,25 +499,25 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::block::block_burn::Block location: None, })), }, - context: EventContext { server, player: None }, + context: EventContext { + server, + player: None, + }, } } fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockBurn(event) => { - if !event.block_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_key) { - self.block = block; - } - } - if !event.igniting_block_key.is_empty() { - if let Some(block) = Block::from_name(&event.igniting_block_key) { - self.igniting_block = block; - } - } + if let Data::BlockBurn(event) = data { + if !event.block_key.is_empty() + && let Some(block) = Block::from_name(&event.block_key) + { + self.block = block; + } + if !event.igniting_block_key.is_empty() + && let Some(block) = Block::from_name(&event.igniting_block_key) + { + self.igniting_block = block; } - _ => {} } Some(()) } @@ -569,21 +553,18 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::block::block_can_build:: } fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockCanBuild(event) => { - if !event.block_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_key) { - self.block_to_build = block; - } - } - if !event.block_against_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_against_key) { - self.block = block; - } - } - self.buildable = event.can_build; + if let Data::BlockCanBuild(event) = data { + if !event.block_key.is_empty() + && let Some(block) = Block::from_name(&event.block_key) + { + self.block_to_build = block; + } + if !event.block_against_key.is_empty() + && let Some(block) = Block::from_name(&event.block_against_key) + { + self.block = block; } - _ => {} + self.buildable = event.can_build; } Some(()) } @@ -619,21 +600,18 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::block::block_place::Bloc } fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockPlace(event) => { - if !event.block_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_key) { - self.block_placed = block; - } - } - if !event.block_against_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_against_key) { - self.block_placed_against = block; - } - } - self.can_build = event.can_build; + if let Data::BlockPlace(event) = data { + if !event.block_key.is_empty() + && let Some(block) = Block::from_name(&event.block_key) + { + self.block_placed = block; } - _ => {} + if !event.block_against_key.is_empty() + && let Some(block) = Block::from_name(&event.block_against_key) + { + self.block_placed_against = block; + } + self.can_build = event.can_build; } Some(()) } @@ -647,22 +625,24 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::server::server_command:: command: self.command.clone(), })), }, - context: EventContext { server, player: None }, + context: EventContext { + server, + player: None, + }, } } fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::ServerCommand(event) => { - self.command = event.command; - } - _ => {} + if let Data::ServerCommand(event) = data { + self.command = event.command; } Some(()) } } -impl PatchBukkitEvent for pumpkin::plugin::api::events::server::server_broadcast::ServerBroadcastEvent { +impl PatchBukkitEvent + for pumpkin::plugin::api::events::server::server_broadcast::ServerBroadcastEvent +{ fn to_payload(&self, server: Arc) -> JvmEventPayload { JvmEventPayload { event: Event { @@ -671,25 +651,27 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::server::server_broadcast sender: serde_json::to_string(&self.sender).unwrap(), })), }, - context: EventContext { server, player: None }, + context: EventContext { + server, + player: None, + }, } } fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::ServerBroadcast(event) => { - self.message = serde_json::from_str(&event.message) - .unwrap_or_else(|_| TextComponent::from_legacy_string(&event.message)); - self.sender = serde_json::from_str(&event.sender) - .unwrap_or_else(|_| TextComponent::from_legacy_string(&event.sender)); - } - _ => {} + if let Data::ServerBroadcast(event) = data { + self.message = serde_json::from_str(&event.message) + .unwrap_or_else(|_| TextComponent::from_legacy_string(&event.message)); + self.sender = serde_json::from_str(&event.sender) + .unwrap_or_else(|_| TextComponent::from_legacy_string(&event.sender)); } Some(()) } } -impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_bed_enter::PlayerBedEnterEvent { +impl PatchBukkitEvent + for pumpkin::plugin::api::events::player::player_bed_enter::PlayerBedEnterEvent +{ fn to_payload(&self, server: Arc) -> JvmEventPayload { let world_uuid = self.player.world().uuid; @@ -710,22 +692,20 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_bed_enter } fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerBedEnter(event) => { - if let Some(location) = event.bed_location { - if let Some(pos) = location_to_vec3(location) { - self.bed_position = pos; - } - } - } - _ => {} + if let Data::PlayerBedEnter(event) = data + && let Some(location) = event.bed_location + && let Some(pos) = location_to_vec3(location) + { + self.bed_position = pos; } Some(()) } } -impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_bucket_empty::PlayerBucketEmptyEvent { +impl PatchBukkitEvent + for pumpkin::plugin::api::events::player::player_bucket_empty::PlayerBucketEmptyEvent +{ fn to_payload(&self, server: Arc) -> JvmEventPayload { let world_uuid = self.player.world().uuid; JvmEventPayload { @@ -749,31 +729,30 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_bucket_em } fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerBucketEmpty(event) => { - if let Some(location) = event.location { - if let Some(pos) = location_to_vec3(location) { - self.position = pos; - } - } - if !event.block_key.is_empty() { - self.block_key = event.block_key; - } - if !event.bucket_item_key.is_empty() { - self.bucket_item_key = event.bucket_item_key; - } - if !event.hand.is_empty() { - self.hand = event.hand; - } - self.face = bukkit_block_face_from_string(&event.block_face); + if let Data::PlayerBucketEmpty(event) = data { + if let Some(location) = event.location + && let Some(pos) = location_to_vec3(location) + { + self.position = pos; + } + if !event.block_key.is_empty() { + self.block_key = event.block_key; + } + if !event.bucket_item_key.is_empty() { + self.bucket_item_key = event.bucket_item_key; + } + if !event.hand.is_empty() { + self.hand = event.hand; } - _ => {} + self.face = bukkit_block_face_from_string(&event.block_face); } Some(()) } } -impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_bucket_fill::PlayerBucketFillEvent { +impl PatchBukkitEvent + for pumpkin::plugin::api::events::player::player_bucket_fill::PlayerBucketFillEvent +{ fn to_payload(&self, server: Arc) -> JvmEventPayload { let world_uuid = self.player.world().uuid; JvmEventPayload { @@ -797,31 +776,30 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_bucket_fi } fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerBucketFill(event) => { - if let Some(location) = event.location { - if let Some(pos) = location_to_vec3(location) { - self.position = pos; - } - } - if !event.block_key.is_empty() { - self.block_key = event.block_key; - } - if !event.bucket_item_key.is_empty() { - self.bucket_item_key = event.bucket_item_key; - } - if !event.hand.is_empty() { - self.hand = event.hand; - } - self.face = bukkit_block_face_from_string(&event.block_face); + if let Data::PlayerBucketFill(event) = data { + if let Some(location) = event.location + && let Some(pos) = location_to_vec3(location) + { + self.position = pos; + } + if !event.block_key.is_empty() { + self.block_key = event.block_key; } - _ => {} + if !event.bucket_item_key.is_empty() { + self.bucket_item_key = event.bucket_item_key; + } + if !event.hand.is_empty() { + self.hand = event.hand; + } + self.face = bukkit_block_face_from_string(&event.block_face); } Some(()) } } -impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_drop_item::PlayerDropItemEvent { +impl PatchBukkitEvent + for pumpkin::plugin::api::events::player::player_drop_item::PlayerDropItemEvent +{ fn to_payload(&self, server: Arc) -> JvmEventPayload { JvmEventPayload { event: Event { @@ -844,38 +822,37 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_drop_item } fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerDropItem(event) => { - if let Some(uuid) = event.item_uuid { - if let Ok(item_uuid) = uuid::Uuid::from_str(&uuid.value) { - self.item_uuid = item_uuid; - } - } - let mut key = if event.item_key.is_empty() { - None - } else { - Some(event.item_key) - }; - let mut amount = if event.item_amount > 0 { - Some(event.item_amount as u8) - } else { - None - }; - - if key.is_some() || amount.is_some() { - let fallback_key = item_to_key(self.item_stack.item); - let key = key.take().unwrap_or(fallback_key); - let count = amount.take().unwrap_or(self.item_stack.item_count); - self.item_stack = item_stack_from_key(&key, count); - } + if let Data::PlayerDropItem(event) = data { + if let Some(uuid) = event.item_uuid + && let Ok(item_uuid) = uuid::Uuid::from_str(&uuid.value) + { + self.item_uuid = item_uuid; + } + let mut key = if event.item_key.is_empty() { + None + } else { + Some(event.item_key) + }; + let mut amount = if event.item_amount > 0 { + Some(event.item_amount as u8) + } else { + None + }; + + if key.is_some() || amount.is_some() { + let fallback_key = item_to_key(self.item_stack.item); + let key = key.take().unwrap_or(fallback_key); + let count = amount.take().unwrap_or(self.item_stack.item_count); + self.item_stack = item_stack_from_key(&key, count); } - _ => {} } Some(()) } } -impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_exp_change::PlayerExpChangeEvent { +impl PatchBukkitEvent + for pumpkin::plugin::api::events::player::player_exp_change::PlayerExpChangeEvent +{ fn to_payload(&self, server: Arc) -> JvmEventPayload { JvmEventPayload { event: Event { @@ -894,17 +871,16 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_exp_chang } fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerExpChange(event) => { - self.amount = event.amount; - } - _ => {} + if let Data::PlayerExpChange(event) = data { + self.amount = event.amount; } Some(()) } } -impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_item_break::PlayerItemBreakEvent { +impl PatchBukkitEvent + for pumpkin::plugin::api::events::player::player_item_break::PlayerItemBreakEvent +{ fn to_payload(&self, server: Arc) -> JvmEventPayload { JvmEventPayload { event: Event { @@ -924,33 +900,32 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_item_brea } fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerItemBreak(event) => { - let mut key = if event.item_key.is_empty() { - None - } else { - Some(event.item_key) - }; - let mut amount = if event.item_amount > 0 { - Some(event.item_amount as u8) - } else { - None - }; - - if key.is_some() || amount.is_some() { - let fallback_key = item_to_key(self.item_stack.item); - let key = key.take().unwrap_or(fallback_key); - let count = amount.take().unwrap_or(self.item_stack.item_count); - self.item_stack = item_stack_from_key(&key, count); - } + if let Data::PlayerItemBreak(event) = data { + let mut key = if event.item_key.is_empty() { + None + } else { + Some(event.item_key) + }; + let mut amount = if event.item_amount > 0 { + Some(event.item_amount as u8) + } else { + None + }; + + if key.is_some() || amount.is_some() { + let fallback_key = item_to_key(self.item_stack.item); + let key = key.take().unwrap_or(fallback_key); + let count = amount.take().unwrap_or(self.item_stack.item_count); + self.item_stack = item_stack_from_key(&key, count); } - _ => {} } Some(()) } } -impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_item_consume::PlayerItemConsumeEvent { +impl PatchBukkitEvent + for pumpkin::plugin::api::events::player::player_item_consume::PlayerItemConsumeEvent +{ fn to_payload(&self, server: Arc) -> JvmEventPayload { let hand = match self.hand { Hand::Left => "OFF_HAND", @@ -975,41 +950,40 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_item_cons } fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerItemConsume(event) => { - if !event.hand.is_empty() { - self.hand = if event.hand == "OFF_HAND" { - Hand::Left - } else { - Hand::Right - }; - } - - let mut key = if event.item_key.is_empty() { - None - } else { - Some(event.item_key) - }; - let mut amount = if event.item_amount > 0 { - Some(event.item_amount as u8) + if let Data::PlayerItemConsume(event) = data { + if !event.hand.is_empty() { + self.hand = if event.hand == "OFF_HAND" { + Hand::Left } else { - None + Hand::Right }; + } - if key.is_some() || amount.is_some() { - let fallback_key = item_to_key(self.item_stack.item); - let key = key.take().unwrap_or(fallback_key); - let count = amount.take().unwrap_or(self.item_stack.item_count); - self.item_stack = item_stack_from_key(&key, count); - } + let mut key = if event.item_key.is_empty() { + None + } else { + Some(event.item_key) + }; + let mut amount = if event.item_amount > 0 { + Some(event.item_amount as u8) + } else { + None + }; + + if key.is_some() || amount.is_some() { + let fallback_key = item_to_key(self.item_stack.item); + let key = key.take().unwrap_or(fallback_key); + let count = amount.take().unwrap_or(self.item_stack.item_count); + self.item_stack = item_stack_from_key(&key, count); } - _ => {} } Some(()) } } -impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_item_damage::PlayerItemDamageEvent { +impl PatchBukkitEvent + for pumpkin::plugin::api::events::player::player_item_damage::PlayerItemDamageEvent +{ fn to_payload(&self, server: Arc) -> JvmEventPayload { JvmEventPayload { event: Event { @@ -1030,34 +1004,33 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_item_dama } fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerItemDamage(event) => { - self.damage = event.damage; - let mut key = if event.item_key.is_empty() { - None - } else { - Some(event.item_key) - }; - let mut amount = if event.item_amount > 0 { - Some(event.item_amount as u8) - } else { - None - }; - - if key.is_some() || amount.is_some() { - let fallback_key = item_to_key(self.item_stack.item); - let key = key.take().unwrap_or(fallback_key); - let count = amount.take().unwrap_or(self.item_stack.item_count); - self.item_stack = item_stack_from_key(&key, count); - } + if let Data::PlayerItemDamage(event) = data { + self.damage = event.damage; + let mut key = if event.item_key.is_empty() { + None + } else { + Some(event.item_key) + }; + let mut amount = if event.item_amount > 0 { + Some(event.item_amount as u8) + } else { + None + }; + + if key.is_some() || amount.is_some() { + let fallback_key = item_to_key(self.item_stack.item); + let key = key.take().unwrap_or(fallback_key); + let count = amount.take().unwrap_or(self.item_stack.item_count); + self.item_stack = item_stack_from_key(&key, count); } - _ => {} } Some(()) } } -impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_item_held::PlayerItemHeldEvent { +impl PatchBukkitEvent + for pumpkin::plugin::api::events::player::player_item_held::PlayerItemHeldEvent +{ fn to_payload(&self, server: Arc) -> JvmEventPayload { JvmEventPayload { event: Event { @@ -1077,18 +1050,17 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_item_held } fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerItemHeld(event) => { - self.previous_slot = event.previous_slot; - self.new_slot = event.new_slot; - } - _ => {} + if let Data::PlayerItemHeld(event) = data { + self.previous_slot = event.previous_slot; + self.new_slot = event.new_slot; } Some(()) } } -impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_item_mend::PlayerItemMendEvent { +impl PatchBukkitEvent + for pumpkin::plugin::api::events::player::player_item_mend::PlayerItemMendEvent +{ fn to_payload(&self, server: Arc) -> JvmEventPayload { JvmEventPayload { event: Event { @@ -1100,7 +1072,9 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_item_mend item_amount: i32::from(self.item_stack.item_count), slot: equipment_slot_to_bukkit(&self.slot), repair_amount: self.repair_amount, - orb_uuid: self.orb_uuid.map(|id| Uuid { value: id.to_string() }), + orb_uuid: self.orb_uuid.map(|id| Uuid { + value: id.to_string(), + }), })), }, context: EventContext { @@ -1111,38 +1085,35 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_item_mend } fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerItemMend(event) => { - self.repair_amount = event.repair_amount; - if !event.slot.is_empty() { - if let Some(slot) = equipment_slot_from_bukkit(&event.slot) { - self.slot = slot; - } - } - if let Some(uuid) = event.orb_uuid { - if let Ok(orb_uuid) = uuid::Uuid::from_str(&uuid.value) { - self.orb_uuid = Some(orb_uuid); - } - } - let mut key = if event.item_key.is_empty() { - None - } else { - Some(event.item_key) - }; - let mut amount = if event.item_amount > 0 { - Some(event.item_amount as u8) - } else { - None - }; - - if key.is_some() || amount.is_some() { - let fallback_key = item_to_key(self.item_stack.item); - let key = key.take().unwrap_or(fallback_key); - let count = amount.take().unwrap_or(self.item_stack.item_count); - self.item_stack = item_stack_from_key(&key, count); - } + if let Data::PlayerItemMend(event) = data { + self.repair_amount = event.repair_amount; + if !event.slot.is_empty() + && let Some(slot) = equipment_slot_from_bukkit(&event.slot) + { + self.slot = slot; + } + if let Some(uuid) = event.orb_uuid + && let Ok(orb_uuid) = uuid::Uuid::from_str(&uuid.value) + { + self.orb_uuid = Some(orb_uuid); + } + let mut key = if event.item_key.is_empty() { + None + } else { + Some(event.item_key) + }; + let mut amount = if event.item_amount > 0 { + Some(event.item_amount as u8) + } else { + None + }; + + if key.is_some() || amount.is_some() { + let fallback_key = item_to_key(self.item_stack.item); + let key = key.take().unwrap_or(fallback_key); + let count = amount.take().unwrap_or(self.item_stack.item_count); + self.item_stack = item_stack_from_key(&key, count); } - _ => {} } Some(()) } @@ -1169,29 +1140,28 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_kick::Pla } fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerKick(event) => { - if !event.reason.is_empty() { - if let Ok(reason) = serde_json::from_str(&event.reason) { - self.reason = reason; - } - } - if !event.leave_message.is_empty() { - if let Ok(msg) = serde_json::from_str(&event.leave_message) { - self.leave_message = msg; - } - } - if !event.cause.is_empty() { - self.cause = event.cause; - } + if let Data::PlayerKick(event) = data { + if !event.reason.is_empty() + && let Ok(reason) = serde_json::from_str(&event.reason) + { + self.reason = reason; + } + if !event.leave_message.is_empty() + && let Ok(msg) = serde_json::from_str(&event.leave_message) + { + self.leave_message = msg; + } + if !event.cause.is_empty() { + self.cause = event.cause; } - _ => {} } Some(()) } } -impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_level_change::PlayerLevelChangeEvent { +impl PatchBukkitEvent + for pumpkin::plugin::api::events::player::player_level_change::PlayerLevelChangeEvent +{ fn to_payload(&self, server: Arc) -> JvmEventPayload { JvmEventPayload { event: Event { @@ -1211,18 +1181,17 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_level_cha } fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerLevelChange(event) => { - self.old_level = event.old_level; - self.new_level = event.new_level; - } - _ => {} + if let Data::PlayerLevelChange(event) = data { + self.old_level = event.old_level; + self.new_level = event.new_level; } Some(()) } } -impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_toggle_flight::PlayerToggleFlightEvent { +impl PatchBukkitEvent + for pumpkin::plugin::api::events::player::player_toggle_flight::PlayerToggleFlightEvent +{ fn to_payload(&self, server: Arc) -> JvmEventPayload { JvmEventPayload { event: Event { @@ -1241,11 +1210,8 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::player::player_toggle_fl } fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerToggleFlight(event) => { - self.is_flying = event.is_flying; - } - _ => {} + if let Data::PlayerToggleFlight(event) = data { + self.is_flying = event.is_flying; } Some(()) } @@ -1278,31 +1244,31 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::block::block_dispense::B }), })), }, - context: EventContext { server, player: None }, + context: EventContext { + server, + player: None, + }, } } fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockDispense(event) => { - if !event.item_key.is_empty() || event.item_amount > 0 { - let key = if event.item_key.is_empty() { - item_to_key(self.item_stack.item) - } else { - event.item_key - }; - let count = if event.item_amount > 0 { - event.item_amount as u8 - } else { - self.item_stack.item_count - }; - self.item_stack = item_stack_from_key(&key, count); - } - if let Some(vel) = event.velocity { - self.velocity = Vector3::new(vel.x, vel.y, vel.z); - } + if let Data::BlockDispense(event) = data { + if !event.item_key.is_empty() || event.item_amount > 0 { + let key = if event.item_key.is_empty() { + item_to_key(self.item_stack.item) + } else { + event.item_key + }; + let count = if event.item_amount > 0 { + event.item_amount as u8 + } else { + self.item_stack.item_count + }; + self.item_stack = item_stack_from_key(&key, count); + } + if let Some(vel) = event.velocity { + self.velocity = Vector3::new(vel.x, vel.y, vel.z); } - _ => {} } Some(()) @@ -1330,34 +1296,34 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::block::block_form::Block location: Some(location), })), }, - context: EventContext { server, player: None }, + context: EventContext { + server, + player: None, + }, } } fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockForm(event) => { - if !event.new_block_key.is_empty() { - if let Some(block) = Block::from_name(&event.new_block_key) { - self.new_block = block; - } - } - if let Some(loc) = event.location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.block_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - } - } - if !event.block_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_key) { - self.old_block = block; - } - } + if let Data::BlockForm(event) = data { + if !event.new_block_key.is_empty() + && let Some(block) = Block::from_name(&event.new_block_key) + { + self.new_block = block; + } + if let Some(loc) = event.location + && let Some(pos) = location_to_vec3(loc.clone()) + { + self.block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + if !event.block_key.is_empty() + && let Some(block) = Block::from_name(&event.block_key) + { + self.old_block = block; } - _ => {} } Some(()) @@ -1397,43 +1363,42 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::block::block_ignite::Blo } fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockIgnite(event) => { - if !event.block_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_key) { - self.block = block; - } - } - if !event.igniting_block_key.is_empty() { - if let Some(block) = Block::from_name(&event.igniting_block_key) { - self.igniting_block = block; - } - } - if let Some(loc) = event.location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.block_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - } - if let Some(world) = loc.world.and_then(|w| w.uuid) { - if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { - self.world_uuid = uuid; - } - } - } - if !event.cause.is_empty() { - self.cause = event.cause; + if let Data::BlockIgnite(event) = data { + if !event.block_key.is_empty() + && let Some(block) = Block::from_name(&event.block_key) + { + self.block = block; + } + if !event.igniting_block_key.is_empty() + && let Some(block) = Block::from_name(&event.igniting_block_key) + { + self.igniting_block = block; + } + if let Some(loc) = event.location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + if let Some(world) = loc.world.and_then(|w| w.uuid) + && let Ok(uuid) = uuid::Uuid::from_str(&world.value) + { + self.world_uuid = uuid; } } - _ => {} + if !event.cause.is_empty() { + self.cause = event.cause; + } } Some(()) } } -impl PatchBukkitEvent for pumpkin::plugin::api::events::block::block_multi_place::BlockMultiPlaceEvent { +impl PatchBukkitEvent + for pumpkin::plugin::api::events::block::block_multi_place::BlockMultiPlaceEvent +{ fn to_payload(&self, server: Arc) -> JvmEventPayload { let world_uuid = self.player.world().uuid; let origin = self @@ -1513,22 +1478,24 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::block::block_redstone::B new_current: self.new_current, })), }, - context: EventContext { server, player: None }, + context: EventContext { + server, + player: None, + }, } } fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockRedstone(event) => { - self.new_current = event.new_current; - } - _ => {} + if let Data::BlockRedstone(event) = data { + self.new_current = event.new_current; } Some(()) } } -impl PatchBukkitEvent for pumpkin::plugin::api::events::block::moisture_change::MoistureChangeEvent { +impl PatchBukkitEvent + for pumpkin::plugin::api::events::block::moisture_change::MoistureChangeEvent +{ fn to_payload(&self, server: Arc) -> JvmEventPayload { let location = build_location( self.world_uuid, @@ -1550,39 +1517,39 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::block::moisture_change:: new_block_key, })), }, - context: EventContext { server, player: None }, + context: EventContext { + server, + player: None, + }, } } fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::MoistureChange(event) => { - if !event.block_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_key) { - self.block = block; - } - } - if let Some(loc) = event.location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.block_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - } - if let Some(world) = loc.world.and_then(|w| w.uuid) { - if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { - self.world_uuid = uuid; - } - } - } - if !event.new_block_key.is_empty() { - if let Some(block) = Block::from_name(&event.new_block_key) { - self.new_state_id = block.default_state.id; - } + if let Data::MoistureChange(event) = data { + if !event.block_key.is_empty() + && let Some(block) = Block::from_name(&event.block_key) + { + self.block = block; + } + if let Some(loc) = event.location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + if let Some(world) = loc.world.and_then(|w| w.uuid) + && let Ok(uuid) = uuid::Uuid::from_str(&world.value) + { + self.world_uuid = uuid; } } - _ => {} + if !event.new_block_key.is_empty() + && let Some(block) = Block::from_name(&event.new_block_key) + { + self.new_state_id = block.default_state.id; + } } Some(()) } @@ -1610,40 +1577,40 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::block::note_play::NotePl note: i32::from(self.note), })), }, - context: EventContext { server, player: None }, + context: EventContext { + server, + player: None, + }, } } fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::NotePlay(event) => { - if !event.block_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_key) { - self.block = block; - } - } - if let Some(loc) = event.location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.block_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - } - if let Some(world) = loc.world.and_then(|w| w.uuid) { - if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { - self.world_uuid = uuid; - } - } - } - if !event.instrument.is_empty() { - if let Some(instrument) = instrument_from_bukkit(&event.instrument) { - self.instrument = instrument; - } + if let Data::NotePlay(event) = data { + if !event.block_key.is_empty() + && let Some(block) = Block::from_name(&event.block_key) + { + self.block = block; + } + if let Some(loc) = event.location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + if let Some(world) = loc.world.and_then(|w| w.uuid) + && let Ok(uuid) = uuid::Uuid::from_str(&world.value) + { + self.world_uuid = uuid; } - self.note = event.note.clamp(0, 24) as u8; } - _ => {} + if !event.instrument.is_empty() + && let Some(instrument) = instrument_from_bukkit(&event.instrument) + { + self.instrument = instrument; + } + self.note = event.note.clamp(0, 24) as u8; } Some(()) } @@ -1683,35 +1650,31 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::block::sign_change::Sign } fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { - match data { - Data::SignChange(event) => { - if let Some(uuid) = event.player_uuid { - if let Ok(uuid) = uuid::Uuid::from_str(&uuid.value) { - if let Some(player) = server.get_player_by_uuid(uuid) { - self.player = player; - } - } - } - if !event.block_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_key) { - self.block = block; - } - } - if let Some(loc) = event.location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.block_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - } - } - if !event.lines.is_empty() { - self.lines = event.lines; - } - self.is_front_text = event.is_front_text; + if let Data::SignChange(event) = data { + if let Some(uuid) = event.player_uuid + && let Ok(uuid) = uuid::Uuid::from_str(&uuid.value) + && let Some(player) = server.get_player_by_uuid(uuid) + { + self.player = player; + } + if !event.block_key.is_empty() + && let Some(block) = Block::from_name(&event.block_key) + { + self.block = block; + } + if let Some(loc) = event.location + && let Some(pos) = location_to_vec3(loc.clone()) + { + self.block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + if !event.lines.is_empty() { + self.lines = event.lines; } - _ => {} + self.is_front_text = event.is_front_text; } Some(()) } @@ -1750,45 +1713,47 @@ impl PatchBukkitEvent for pumpkin::plugin::api::events::block::tnt_prime::TNTPri } fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { - match data { - Data::TntPrime(event) => { - if let Some(uuid) = event.player_uuid { - if let Ok(uuid) = uuid::Uuid::from_str(&uuid.value) { - self.player = server.get_player_by_uuid(uuid); - } - } else { - self.player = None; - } - if !event.block_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_key) { - self.block = block; - } + if let Data::TntPrime(event) = data { + if let Some(uuid) = event.player_uuid { + if let Ok(uuid) = uuid::Uuid::from_str(&uuid.value) { + self.player = server.get_player_by_uuid(uuid); } - if let Some(loc) = event.location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.block_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - } - if let Some(world) = loc.world.and_then(|w| w.uuid) { - if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { - self.world_uuid = uuid; - } - } - } - if !event.cause.is_empty() { - self.cause = event.cause; + } else { + self.player = None; + } + if !event.block_key.is_empty() + && let Some(block) = Block::from_name(&event.block_key) + { + self.block = block; + } + if let Some(loc) = event.location { + if let Some(pos) = location_to_vec3(loc.clone()) { + self.block_pos = pumpkin_util::math::position::BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ); + } + if let Some(world) = loc.world.and_then(|w| w.uuid) + && let Ok(uuid) = uuid::Uuid::from_str(&world.value) + { + self.world_uuid = uuid; } } - _ => {} + if !event.cause.is_empty() { + self.cause = event.cause; + } } Some(()) } } -fn build_location(world_uuid: uuid::Uuid, position: &Vector3, yaw: f32, pitch: f32) -> Location { +fn build_location( + world_uuid: uuid::Uuid, + position: &Vector3, + yaw: f32, + pitch: f32, +) -> Location { Location { world: Some(ProtoWorld { uuid: Some(Uuid { @@ -2058,19 +2023,27 @@ impl_cancellation_bridge!( pumpkin::plugin::api::events::server::server_broadcast::ServerBroadcastEvent, ); -impl CancellationBridge for pumpkin::plugin::api::events::player::player_command_send::PlayerCommandSendEvent { +impl CancellationBridge + for pumpkin::plugin::api::events::player::player_command_send::PlayerCommandSendEvent +{ fn apply_cancelled(&mut self, _cancelled: bool) {} } -impl CancellationBridge for pumpkin::plugin::api::events::player::player_exp_change::PlayerExpChangeEvent { +impl CancellationBridge + for pumpkin::plugin::api::events::player::player_exp_change::PlayerExpChangeEvent +{ fn apply_cancelled(&mut self, _cancelled: bool) {} } -impl CancellationBridge for pumpkin::plugin::api::events::player::player_item_break::PlayerItemBreakEvent { +impl CancellationBridge + for pumpkin::plugin::api::events::player::player_item_break::PlayerItemBreakEvent +{ fn apply_cancelled(&mut self, _cancelled: bool) {} } -impl CancellationBridge for pumpkin::plugin::api::events::player::player_level_change::PlayerLevelChangeEvent { +impl CancellationBridge + for pumpkin::plugin::api::events::player::player_level_change::PlayerLevelChangeEvent +{ fn apply_cancelled(&mut self, _cancelled: bool) {} } @@ -2125,4 +2098,3 @@ where }) } } - diff --git a/rust/src/java/native_callbacks/block.rs b/rust/src/java/native_callbacks/block.rs index c4437a4..24570d5 100644 --- a/rust/src/java/native_callbacks/block.rs +++ b/rust/src/java/native_callbacks/block.rs @@ -2,9 +2,7 @@ use pumpkin_util::math::position::BlockPos; use crate::{ java::native_callbacks::CALLBACK_CONTEXT, - proto::patchbukkit::{ - block::{GetBlockRequest, GetBlockResponse}, - }, + proto::patchbukkit::block::{GetBlockRequest, GetBlockResponse}, }; pub fn ffi_native_bridge_get_block_impl(request: GetBlockRequest) -> Option { diff --git a/rust/src/java/native_callbacks/events.rs b/rust/src/java/native_callbacks/events.rs index e5c3d24..5cdcf8a 100644 --- a/rust/src/java/native_callbacks/events.rs +++ b/rust/src/java/native_callbacks/events.rs @@ -1,18 +1,20 @@ -use std::sync::Arc; +use std::sync::Arc; use pumpkin::plugin::EventPriority; -use pumpkin_data::{Block, BlockDirection}; use pumpkin_data::item::Item; +use pumpkin_data::{Block, BlockDirection}; use pumpkin_util::math::position::BlockPos; -use pumpkin_world::item::ItemStack; use pumpkin_util::math::vector3::Vector3; use pumpkin_util::text::TextComponent; +use pumpkin_world::item::ItemStack; use tokio::sync::Mutex; use crate::events::handler::PatchBukkitEventHandler; use crate::java::native_callbacks::CALLBACK_CONTEXT; use crate::proto::patchbukkit::events::event::Data; -use crate::proto::patchbukkit::events::{CallEventRequest, CallEventResponse, RegisterEventRequest}; +use crate::proto::patchbukkit::events::{ + CallEventRequest, CallEventResponse, RegisterEventRequest, +}; pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> Option<()> { let ctx = CALLBACK_CONTEXT.get()?; @@ -998,10 +1000,16 @@ fn block_face_from_bukkit(face: &str) -> Option { } } -fn location_to_block_pos(location: Option<&crate::proto::patchbukkit::common::Location>) -> BlockPos { - let pos = location.and_then(|loc| loc.position.clone()); +fn location_to_block_pos( + location: Option<&crate::proto::patchbukkit::common::Location>, +) -> BlockPos { + let pos = location.and_then(|loc| loc.position); match pos { - Some(pos) => BlockPos::new(pos.x.floor() as i32, pos.y.floor() as i32, pos.z.floor() as i32), + Some(pos) => BlockPos::new( + pos.x.floor() as i32, + pos.y.floor() as i32, + pos.z.floor() as i32, + ), None => BlockPos::new(0, 0, 0), } } @@ -1029,5 +1037,3 @@ fn find_world_by_uuid( .find(|world| world.uuid == world_uuid) .cloned() } - - From 85095a489d701fd18b50135b5edab7f7784f1768 Mon Sep 17 00:00:00 2001 From: yunuservices Date: Fri, 6 Feb 2026 23:54:47 +0300 Subject: [PATCH 56/56] fix: address review feedback across bridge and runtime sync --- .../entity/PatchBukkitAbstractArrow.java | 4 + .../entity/PatchBukkitArmorStand.java | 4 + .../patchbukkit/entity/PatchBukkitEntity.java | 10 + .../entity/PatchBukkitExperienceOrb.java | 4 + .../entity/PatchBukkitFishHook.java | 4 + .../patchbukkit/entity/PatchBukkitItem.java | 4 + .../entity/PatchBukkitProjectile.java | 4 + .../events/PatchBukkitEventFactory.java | 36 +- .../patchbukkit/world/PatchBukkitBlock.java | 57 +- .../world/PatchBukkitBlockState.java | 18 +- proto/google/protobuf/wrappers.proto | 17 - proto/patchbukkit/bridge.proto | 1 - rust/build/java.rs | 2 +- rust/src/commands/mod.rs | 6 +- rust/src/events/handler.rs | 2 +- rust/src/events/handler_legacy.rs | 4459 ----------------- rust/src/java/jvm/commands.rs | 2 +- rust/src/java/native_callbacks/block.rs | 14 +- rust/src/java/native_callbacks/events.rs | 612 +-- .../java/native_callbacks/events_legacy.rs | 3458 ------------- rust/src/java/plugin/command_manager.rs | 8 +- 21 files changed, 179 insertions(+), 8547 deletions(-) delete mode 100644 proto/google/protobuf/wrappers.proto delete mode 100644 rust/src/events/handler_legacy.rs delete mode 100644 rust/src/java/native_callbacks/events_legacy.rs diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitAbstractArrow.java b/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitAbstractArrow.java index a2497d8..0328a34 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitAbstractArrow.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitAbstractArrow.java @@ -27,6 +27,10 @@ public class PatchBukkitAbstractArrow extends PatchBukkitProjectile implements A public PatchBukkitAbstractArrow(UUID uuid, String name) { super(uuid, name); + warnSnapshotLimitation( + "entity:abstract_arrow_snapshot", + "PatchBukkitAbstractArrow uses fallback local values; Pumpkin does not fully expose arrow/bow runtime state yet." + ); } public Block getAttachedBlock() { diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitArmorStand.java b/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitArmorStand.java index a7b6cf7..86cf828 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitArmorStand.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitArmorStand.java @@ -18,6 +18,10 @@ public class PatchBukkitArmorStand extends PatchBukkitLivingEntity implements Ar public PatchBukkitArmorStand(UUID uuid, String name) { super(uuid, name); + warnSnapshotLimitation( + "entity:armor_stand_snapshot", + "PatchBukkitArmorStand currently mirrors a limited local snapshot; unsupported fields may not reflect Pumpkin state." + ); } @Override diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitEntity.java b/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitEntity.java index c950b98..46e73e5 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitEntity.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitEntity.java @@ -6,6 +6,8 @@ import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Logger; import org.bukkit.Bukkit; import org.bukkit.EntityEffect; @@ -51,9 +53,11 @@ public class PatchBukkitEntity implements Entity { + private static final Logger LOGGER = Logger.getLogger(PatchBukkitEntity.class.getName()); protected final UUID uuid; private final String name; private static PermissibleBase perm; + private static final Set WARNED_LIMITATIONS = ConcurrentHashMap.newKeySet(); private boolean visibleByDefault = true; public PatchBukkitEntity( @@ -64,6 +68,12 @@ public PatchBukkitEntity( this.name = name; } + protected final void warnSnapshotLimitation(String key, String message) { + if (WARNED_LIMITATIONS.add(key)) { + LOGGER.warning(message); + } + } + private static PermissibleBase getPermissibleBase() { if (PatchBukkitEntity.perm == null) { PatchBukkitEntity.perm = new PermissibleBase(new ServerOperator() { diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitExperienceOrb.java b/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitExperienceOrb.java index 57f6b42..e434d97 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitExperienceOrb.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitExperienceOrb.java @@ -14,6 +14,10 @@ public class PatchBukkitExperienceOrb extends PatchBukkitEntity implements Exper public PatchBukkitExperienceOrb(UUID uuid) { super(uuid, "EXPERIENCE_ORB"); + warnSnapshotLimitation( + "entity:experience_orb_snapshot", + "PatchBukkitExperienceOrb values are local snapshots and are not continuously synchronized from Pumpkin." + ); } @Override diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitFishHook.java b/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitFishHook.java index d46d0f4..5d9b434 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitFishHook.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitFishHook.java @@ -26,6 +26,10 @@ public class PatchBukkitFishHook extends PatchBukkitProjectile implements FishHo public PatchBukkitFishHook(UUID uuid) { super(uuid, "FISHING_BOBBER"); + warnSnapshotLimitation( + "entity:fish_hook_snapshot", + "PatchBukkitFishHook currently relies on local fallback state; values may differ from Pumpkin runtime state." + ); } @Override diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitItem.java b/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitItem.java index 44a7cf1..ed7ed4e 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitItem.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitItem.java @@ -23,6 +23,10 @@ public class PatchBukkitItem extends PatchBukkitEntity implements Item { public PatchBukkitItem(@NotNull UUID uuid, @NotNull ItemStack itemStack) { super(uuid, "ITEM"); this.itemStack = itemStack; + warnSnapshotLimitation( + "entity:item_snapshot", + "PatchBukkitItem currently exposes local snapshot values and is not fully synchronized with Pumpkin item entity internals." + ); } @Override diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitProjectile.java b/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitProjectile.java index 28b083b..ba83139 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitProjectile.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/entity/PatchBukkitProjectile.java @@ -17,6 +17,10 @@ public class PatchBukkitProjectile extends PatchBukkitEntity implements Projecti public PatchBukkitProjectile(UUID uuid, String name) { super(uuid, name); + warnSnapshotLimitation( + "entity:projectile_snapshot", + "PatchBukkit projectile wrappers currently keep local snapshot state and may diverge from Pumpkin runtime state." + ); } @Override diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java index 2f35b0e..2739ac6 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/events/PatchBukkitEventFactory.java @@ -130,6 +130,7 @@ import org.bukkit.Statistic; import org.bukkit.entity.EntityType; import java.net.InetAddress; +import java.net.InetSocketAddress; import patchbukkit.common.UUID; import patchbukkit.events.Event; import patchbukkit.events.FireEventResponse; @@ -175,7 +176,8 @@ public static org.bukkit.event.Event createEvent(@NotNull Event event) { Component kickMessage = GsonComponentSerializer.gson().deserialize(loginEvent.getKickMessage()); PlayerLoginEvent login = createLoginEvent(player); if (login != null) { - login.setKickMessage(PlainTextComponentSerializer.plainText().serialize(kickMessage)); + String plainKickMessage = PlainTextComponentSerializer.plainText().serialize(kickMessage); + applyLoginResult(login, plainKickMessage); yield login; } yield null; @@ -4378,20 +4380,48 @@ private static void setIgnitingBlock(@NotNull BlockBurnEvent event, @Nullable St @Nullable private static PlayerLoginEvent createLoginEvent(@NotNull Player player) { + InetAddress playerAddress = resolvePlayerAddress(player); try { return PlayerLoginEvent.class.getConstructor(Player.class, String.class, InetAddress.class) - .newInstance(player, "", null); + .newInstance(player, "", playerAddress); } catch (ReflectiveOperationException ignored) { try { return PlayerLoginEvent.class.getConstructor(Player.class, String.class, java.net.InetAddress.class, PlayerLoginEvent.Result.class, String.class) - .newInstance(player, "", null, PlayerLoginEvent.Result.ALLOWED, ""); + .newInstance(player, "", playerAddress, PlayerLoginEvent.Result.ALLOWED, ""); } catch (ReflectiveOperationException ignoredAgain) { return null; } } } + @Nullable + private static InetAddress resolvePlayerAddress(@NotNull Player player) { + try { + InetSocketAddress address = player.getAddress(); + return address != null ? address.getAddress() : null; + } catch (UnsupportedOperationException ignored) { + return null; + } + } + + private static void applyLoginResult(@NotNull PlayerLoginEvent event, @NotNull String kickMessage) { + if (kickMessage.isEmpty()) { + try { + event.allow(); + } catch (UnsupportedOperationException ignored) { + // Older API variants may not expose allow/disallow in the same way. + } + return; + } + + try { + event.disallow(PlayerLoginEvent.Result.KICK_OTHER, kickMessage); + } catch (UnsupportedOperationException ignored) { + event.setKickMessage(kickMessage); + } + } + @NotNull private static ItemStack materialToItem(@NotNull String key, int amount) { ItemStack stack = materialToItem(key); diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/world/PatchBukkitBlock.java b/java/patchbukkit/src/main/java/org/patchbukkit/world/PatchBukkitBlock.java index 3ff7096..25805d7 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/world/PatchBukkitBlock.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/world/PatchBukkitBlock.java @@ -4,22 +4,24 @@ import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; +import org.patchbukkit.bridge.BridgeUtils; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Locale; +import patchbukkit.bridge.NativeBridgeFfi; + public final class PatchBukkitBlock { private PatchBukkitBlock() { } public static Block create(PatchBukkitWorld world, int x, int y, int z, String blockKey) { - Material material = resolveMaterial(blockKey); return (Block) Proxy.newProxyInstance( PatchBukkitBlock.class.getClassLoader(), new Class[]{Block.class}, - new Handler(world, x, y, z, material, blockKey) + new Handler(world, x, y, z, blockKey) ); } @@ -44,21 +46,39 @@ static Material resolveMaterial(String blockKey) { return material != null ? material : Material.AIR; } + static String queryBlockKey(PatchBukkitWorld world, int x, int y, int z, String fallbackBlockKey) { + var request = patchbukkit.block.GetBlockRequest.newBuilder() + .setWorld(patchbukkit.common.World.newBuilder() + .setUuid(BridgeUtils.convertUuid(world.getUID())) + .build()) + .setX(x) + .setY(y) + .setZ(z) + .build(); + var response = NativeBridgeFfi.getBlock(request); + if (response == null || response.getBlockKey().isBlank()) { + return fallbackBlockKey; + } + return response.getBlockKey(); + } + + static Material queryMaterial(PatchBukkitWorld world, int x, int y, int z, String fallbackBlockKey) { + return resolveMaterial(queryBlockKey(world, x, y, z, fallbackBlockKey)); + } + private static final class Handler implements InvocationHandler { private final PatchBukkitWorld world; private final int x; private final int y; private final int z; - private final Material material; - private final String blockKey; + private final String fallbackBlockKey; - private Handler(PatchBukkitWorld world, int x, int y, int z, Material material, String blockKey) { + private Handler(PatchBukkitWorld world, int x, int y, int z, String blockKey) { this.world = world; this.x = x; this.y = y; this.z = z; - this.material = material; - this.blockKey = blockKey; + this.fallbackBlockKey = blockKey; } @Override @@ -76,14 +96,16 @@ public Object invoke(Object proxy, Method method, Object[] args) { case "getLocation": return new Location(world, x, y, z); case "getType": - return material; + return queryMaterial(world, x, y, z, fallbackBlockKey); case "getBlockData": - return material.createBlockData(); + return queryMaterial(world, x, y, z, fallbackBlockKey).createBlockData(); case "getState": - return PatchBukkitBlockState.create(world, x, y, z, material, blockKey); + String key = queryBlockKey(world, x, y, z, fallbackBlockKey); + return PatchBukkitBlockState.create(world, x, y, z, key); case "isEmpty": - return material.isAir(); + return queryMaterial(world, x, y, z, fallbackBlockKey).isAir(); case "isLiquid": + Material material = queryMaterial(world, x, y, z, fallbackBlockKey); return material == Material.WATER || material == Material.LAVA; case "getRelative": return getRelative(args); @@ -94,6 +116,7 @@ public Object invoke(Object proxy, Method method, Object[] args) { case "hashCode": return System.identityHashCode(proxy); case "toString": + String blockKey = queryBlockKey(world, x, y, z, fallbackBlockKey); return "PatchBukkitBlock{" + blockKey + " @ " + x + "," + y + "," + z + "}"; default: throw new UnsupportedOperationException("Unimplemented method '" + name + "'"); @@ -102,25 +125,23 @@ public Object invoke(Object proxy, Method method, Object[] args) { private Block getRelative(Object[] args) { if (args == null || args.length == 0) { - return create(world, x, y, z, blockKey); + return world.getBlockAt(x, y, z); } if (args.length == 1 && args[0] instanceof BlockFace face) { - return create(world, x + face.getModX(), y + face.getModY(), z + face.getModZ(), "minecraft:air"); + return world.getBlockAt(x + face.getModX(), y + face.getModY(), z + face.getModZ()); } if (args.length == 2 && args[0] instanceof BlockFace face && args[1] instanceof Integer distance) { - return create( - world, + return world.getBlockAt( x + face.getModX() * distance, y + face.getModY() * distance, - z + face.getModZ() * distance, - "minecraft:air" + z + face.getModZ() * distance ); } if (args.length == 3 && args[0] instanceof Integer dx && args[1] instanceof Integer dy && args[2] instanceof Integer dz) { - return create(world, x + dx, y + dy, z + dz, "minecraft:air"); + return world.getBlockAt(x + dx, y + dy, z + dz); } throw new UnsupportedOperationException("Unimplemented method 'getRelative'"); } diff --git a/java/patchbukkit/src/main/java/org/patchbukkit/world/PatchBukkitBlockState.java b/java/patchbukkit/src/main/java/org/patchbukkit/world/PatchBukkitBlockState.java index f160dce..3f04254 100644 --- a/java/patchbukkit/src/main/java/org/patchbukkit/world/PatchBukkitBlockState.java +++ b/java/patchbukkit/src/main/java/org/patchbukkit/world/PatchBukkitBlockState.java @@ -1,7 +1,6 @@ package org.patchbukkit.world; import org.bukkit.Location; -import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.BlockState; @@ -15,11 +14,11 @@ public final class PatchBukkitBlockState { private PatchBukkitBlockState() { } - public static BlockState create(PatchBukkitWorld world, int x, int y, int z, Material material, String blockKey) { + public static BlockState create(PatchBukkitWorld world, int x, int y, int z, String blockKey) { return (BlockState) Proxy.newProxyInstance( PatchBukkitBlockState.class.getClassLoader(), new Class[]{BlockState.class}, - new Handler(world, x, y, z, material, blockKey) + new Handler(world, x, y, z, blockKey) ); } @@ -28,15 +27,13 @@ private static final class Handler implements InvocationHandler { private final int x; private final int y; private final int z; - private final Material material; private final String blockKey; - private Handler(PatchBukkitWorld world, int x, int y, int z, Material material, String blockKey) { + private Handler(PatchBukkitWorld world, int x, int y, int z, String blockKey) { this.world = world; this.x = x; this.y = y; this.z = z; - this.material = material; this.blockKey = blockKey; } @@ -45,7 +42,7 @@ public Object invoke(Object proxy, Method method, Object[] args) { String name = method.getName(); switch (name) { case "getBlock": - return PatchBukkitBlock.create(world, x, y, z, blockKey); + return world.getBlockAt(x, y, z); case "getWorld": return world; case "getLocation": @@ -57,13 +54,14 @@ public Object invoke(Object proxy, Method method, Object[] args) { case "getZ": return z; case "getType": - return material; + return PatchBukkitBlock.queryMaterial(world, x, y, z, blockKey); case "getBlockData": - return material.createBlockData(); + return PatchBukkitBlock.queryMaterial(world, x, y, z, blockKey).createBlockData(); case "update": return false; case "toString": - return "PatchBukkitBlockState{" + blockKey + " @ " + x + "," + y + "," + z + "}"; + String resolvedKey = PatchBukkitBlock.queryBlockKey(world, x, y, z, blockKey); + return "PatchBukkitBlockState{" + resolvedKey + " @ " + x + "," + y + "," + z + "}"; default: throw new UnsupportedOperationException("Unimplemented method '" + name + "'"); } diff --git a/proto/google/protobuf/wrappers.proto b/proto/google/protobuf/wrappers.proto deleted file mode 100644 index feb2e09..0000000 --- a/proto/google/protobuf/wrappers.proto +++ /dev/null @@ -1,17 +0,0 @@ -syntax = "proto3"; - -package google.protobuf; - -option java_package = "com.google.protobuf"; -option java_outer_classname = "WrappersProto"; -option java_multiple_files = true; - -message DoubleValue { double value = 1; } -message FloatValue { float value = 1; } -message Int64Value { int64 value = 1; } -message UInt64Value { uint64 value = 1; } -message Int32Value { int32 value = 1; } -message UInt32Value { uint32 value = 1; } -message BoolValue { bool value = 1; } -message StringValue { string value = 1; } -message BytesValue { bytes value = 1; } diff --git a/proto/patchbukkit/bridge.proto b/proto/patchbukkit/bridge.proto index fc835de..ad5f8ab 100644 --- a/proto/patchbukkit/bridge.proto +++ b/proto/patchbukkit/bridge.proto @@ -2,7 +2,6 @@ syntax = "proto3"; package patchbukkit.bridge; import "google/protobuf/empty.proto"; -import "google/protobuf/wrappers.proto"; import "patchbukkit/abilities.proto"; import "patchbukkit/block.proto"; import "patchbukkit/common/types.proto"; diff --git a/rust/build/java.rs b/rust/build/java.rs index a5cb866..f1f17f9 100644 --- a/rust/build/java.rs +++ b/rust/build/java.rs @@ -91,7 +91,7 @@ pub fn setup_java(base: PathBuf) { // These are deps of patchbukkit itself ("io.papermc.paper", "paper-api", "1.21.11-R0.1-SNAPSHOT"), ("com.google.protobuf", "protobuf-java", "4.33.5"), - // Netty for ViaVersion / ViaBackwards + // Runtime plugin classpath deps (resolved into jassets), including Netty for ViaVersion/ViaBackwards. ("io.netty", "netty-common", "4.1.108.Final"), ("io.netty", "netty-buffer", "4.1.108.Final"), ("io.netty", "netty-transport", "4.1.108.Final"), diff --git a/rust/src/commands/mod.rs b/rust/src/commands/mod.rs index 9fb37de..5a1c34a 100644 --- a/rust/src/commands/mod.rs +++ b/rust/src/commands/mod.rs @@ -133,7 +133,7 @@ impl CommandExecutor for JavaCommandExecutor { _ => format!("/{}", self.cmd_name), }; - let (tx, _rx) = oneshot::channel(); + let (tx, rx) = oneshot::channel(); self.command_tx .send(JvmCommand::TriggerCommand { full_command, @@ -142,7 +142,9 @@ impl CommandExecutor for JavaCommandExecutor { }) .await .unwrap(); - Ok(1) + + let handled = rx.await.ok().and_then(Result::ok).unwrap_or(false); + Ok(i32::from(handled)) }) } } diff --git a/rust/src/events/handler.rs b/rust/src/events/handler.rs index 92404fb..0732863 100644 --- a/rust/src/events/handler.rs +++ b/rust/src/events/handler.rs @@ -179,7 +179,7 @@ impl PatchBukkitEvent }), from: Some(build_location(world_uuid, &self.from, 0.0, 0.0)), to: Some(build_location(world_uuid, &self.to, 0.0, 0.0)), - cause: String::new(), + cause: "UNKNOWN".to_string(), })), }, context: EventContext { diff --git a/rust/src/events/handler_legacy.rs b/rust/src/events/handler_legacy.rs deleted file mode 100644 index 01babef..0000000 --- a/rust/src/events/handler_legacy.rs +++ /dev/null @@ -1,4459 +0,0 @@ -use std::marker::PhantomData; -use std::str::FromStr; -use std::sync::Arc; - -use pumpkin::entity::player::Player; -use pumpkin::plugin::{BoxFuture, Cancellable, EventHandler, Payload}; -use pumpkin::server::Server; -use pumpkin_api_macros::with_runtime; -use pumpkin_data::data_component_impl::EquipmentSlot; -use pumpkin_data::{Block, BlockDirection}; -use pumpkin_data::block_properties::Instrument; -use pumpkin_data::item::Item; -use pumpkin_util::Hand; -use pumpkin_util::math::vector3::Vector3; -use pumpkin_util::text::TextComponent; -use pumpkin_world::item::ItemStack; -use tokio::sync::{mpsc, oneshot}; - -use crate::java::jvm::commands::JvmCommand; -use crate::proto::patchbukkit::common::{Location, Uuid, Vec3, World}; -use crate::proto::patchbukkit::events::event::Data; -use crate::proto::patchbukkit::events::{ - BlockBreakEvent, BlockDamageEvent, BlockDamageAbortEvent, BlockDispenseEvent, BlockDropItemEntry, BlockDropItemEvent, BlockExplodeBlockEntry, BlockExplodeEvent, BlockFadeEvent, BlockFertilizeBlockEntry, BlockFertilizeEvent, BlockFormEvent, BlockFromToEvent, BlockGrowEvent, BlockPistonBlockEntry, BlockPistonExtendEvent, BlockPistonRetractEvent, BlockRedstoneEvent, BlockMultiPlaceBlockEntry, BlockMultiPlaceEvent, BlockPhysicsEvent, BlockPlaceEvent, BlockCanBuildEvent, BlockBurnEvent, BlockIgniteEvent, BlockSpreadEvent, NotePlayEvent, SignChangeEvent, TntPrimeEvent, MoistureChangeEvent, SpongeAbsorbEvent, SpongeAbsorbBlockEntry, FluidLevelChangeEvent, SpawnChangeEvent, ServerListPingEvent, PluginEnableEvent, PluginDisableEvent, ServiceRegisterEvent, ServiceUnregisterEvent, Event, PlayerChatEvent, PlayerCommandEvent, PlayerCommandSendEvent, PlayerJoinEvent, - PlayerLeaveEvent, PlayerMoveEvent, PlayerInteractEvent, ServerBroadcastEvent, ServerCommandEvent, - EntityDamageEvent, EntityDeathEvent, EntitySpawnEvent, - PlayerLoginEvent, PlayerTeleportEvent, PlayerChangeWorldEvent, PlayerGamemodeChangeEvent, - AsyncPlayerPreLoginEvent, PlayerAdvancementDoneEvent, PlayerAnimationEvent, - PlayerArmorStandManipulateEvent, - PlayerBedEnterEvent, PlayerBedLeaveEvent, - PlayerBucketEmptyEvent, PlayerBucketFillEvent, PlayerBucketEntityEvent, - PlayerChangedMainHandEvent, - PlayerRegisterChannelEvent, PlayerUnregisterChannelEvent, PlayerDropItemEvent, - PlayerEditBookEvent, PlayerEggThrowEvent, PlayerExpChangeEvent, PlayerFishEvent, - PlayerInteractEntityEvent, PlayerInteractAtEntityEvent, PlayerItemHeldEvent, - PlayerItemDamageEvent, PlayerItemBreakEvent, PlayerItemConsumeEvent, PlayerItemMendEvent, - PlayerLevelChangeEvent, PlayerKickEvent, - PlayerToggleSneakEvent, PlayerToggleSprintEvent, PlayerToggleFlightEvent, - PlayerSwapHandItemsEvent, PlayerResourcePackStatusEvent, PlayerRespawnEvent, - PlayerPickupArrowEvent, PlayerPortalEvent, PlayerRecipeDiscoverEvent, PlayerRiptideEvent, - PlayerShearEntityEvent, PlayerSpawnLocationEvent, PlayerStatisticIncrementEvent, - PlayerVelocityEvent, PlayerHarvestBlockEvent, -}; - -pub struct EventContext { - pub server: Arc, - pub player: Option>, -} - -pub struct JvmEventPayload { - pub event: Event, - pub context: EventContext, -} - -pub trait PatchBukkitEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload; - fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()>; -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_join::PlayerJoinEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerJoin(PlayerJoinEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - join_message: serde_json::to_string(&self.join_message).unwrap(), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerJoin(event) => { - self.join_message = serde_json::from_str(&event.join_message).ok()?; - server.get_player_by_uuid(uuid::Uuid::from_str(&event.player_uuid?.value).ok()?)?; - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_login::PlayerLoginEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerLogin(PlayerLoginEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - kick_message: serde_json::to_string(&self.kick_message).unwrap(), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerLogin(event) => { - self.kick_message = serde_json::from_str(&event.kick_message).ok()?; - server.get_player_by_uuid(uuid::Uuid::from_str(&event.player_uuid?.value).ok()?)?; - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_pre_login::PlayerPreLoginEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::AsyncPlayerPreLogin(AsyncPlayerPreLoginEvent { - name: self.name.clone(), - player_uuid: Some(Uuid { - value: self.player_uuid.to_string(), - }), - address: self.address.clone(), - result: self.result.clone(), - kick_message: self.kick_message.clone(), - })), - }, - context: EventContext { - server, - player: None, - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::AsyncPlayerPreLogin(event) => { - self.result = event.result; - self.kick_message = event.kick_message; - if let Some(uuid) = event.player_uuid { - self.player_uuid = uuid::Uuid::from_str(&uuid.value).ok()?; - } - if !event.name.is_empty() { - self.name = event.name; - } - if !event.address.is_empty() { - self.address = event.address; - } - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_leave::PlayerLeaveEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerLeave(PlayerLeaveEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - leave_message: serde_json::to_string(&self.leave_message).unwrap(), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerLeave(event) => { - self.leave_message = serde_json::from_str(&event.leave_message).ok()?; - server.get_player_by_uuid(uuid::Uuid::from_str(&event.player_uuid?.value).ok()?)?; - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_advancement_done::PlayerAdvancementDoneEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerAdvancementDone(PlayerAdvancementDoneEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - advancement_key: self.advancement_key.clone(), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, _data: Data) -> Option<()> { - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_animation::PlayerAnimationEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerAnimation(PlayerAnimationEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - animation_type: self.animation_type.clone(), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, _data: Data) -> Option<()> { - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_armor_stand_manipulate::PlayerArmorStandManipulateEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerArmorStandManipulate( - PlayerArmorStandManipulateEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - armor_stand_uuid: Some(Uuid { - value: self.armor_stand_uuid.to_string(), - }), - item_key: self.item_key.clone(), - armor_stand_item_key: self.armor_stand_item_key.clone(), - slot: self.slot.clone(), - }, - )), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerArmorStandManipulate(event) => { - if !event.item_key.is_empty() { - self.item_key = event.item_key; - } - if !event.armor_stand_item_key.is_empty() { - self.armor_stand_item_key = event.armor_stand_item_key; - } - if !event.slot.is_empty() { - self.slot = event.slot; - } - if let Some(uuid) = event.armor_stand_uuid { - self.armor_stand_uuid = uuid::Uuid::from_str(&uuid.value).ok()?; - } - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_bed_enter::PlayerBedEnterEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let world_uuid = self.player.world().uuid; - - JvmEventPayload { - event: Event { - data: Some(Data::PlayerBedEnter(PlayerBedEnterEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - bed_location: Some(build_location(world_uuid, &self.bed_position, 0.0, 0.0)), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerBedEnter(event) => { - if let Some(location) = event.bed_location { - if let Some(pos) = location_to_vec3(location) { - self.bed_position = pos; - } - } - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_bed_leave::PlayerBedLeaveEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let world_uuid = self.player.world().uuid; - - JvmEventPayload { - event: Event { - data: Some(Data::PlayerBedLeave(PlayerBedLeaveEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - bed_location: Some(build_location(world_uuid, &self.bed_position, 0.0, 0.0)), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerBedLeave(event) => { - if let Some(location) = event.bed_location { - if let Some(pos) = location_to_vec3(location) { - self.bed_position = pos; - } - } - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_bucket_empty::PlayerBucketEmptyEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let world_uuid = self.player.world().uuid; - JvmEventPayload { - event: Event { - data: Some(Data::PlayerBucketEmpty(PlayerBucketEmptyEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - location: Some(build_location(world_uuid, &self.position, 0.0, 0.0)), - block_key: self.block_key.clone(), - block_face: block_face_to_bukkit(self.face), - bucket_item_key: self.bucket_item_key.clone(), - hand: self.hand.clone(), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerBucketEmpty(event) => { - if let Some(location) = event.location { - if let Some(pos) = location_to_vec3(location) { - self.position = pos; - } - } - if !event.block_key.is_empty() { - self.block_key = event.block_key; - } - if !event.bucket_item_key.is_empty() { - self.bucket_item_key = event.bucket_item_key; - } - if !event.hand.is_empty() { - self.hand = event.hand; - } - self.face = bukkit_block_face_from_string(&event.block_face); - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_bucket_fill::PlayerBucketFillEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let world_uuid = self.player.world().uuid; - JvmEventPayload { - event: Event { - data: Some(Data::PlayerBucketFill(PlayerBucketFillEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - location: Some(build_location(world_uuid, &self.position, 0.0, 0.0)), - block_key: self.block_key.clone(), - block_face: block_face_to_bukkit(self.face), - bucket_item_key: self.bucket_item_key.clone(), - hand: self.hand.clone(), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerBucketFill(event) => { - if let Some(location) = event.location { - if let Some(pos) = location_to_vec3(location) { - self.position = pos; - } - } - if !event.block_key.is_empty() { - self.block_key = event.block_key; - } - if !event.bucket_item_key.is_empty() { - self.bucket_item_key = event.bucket_item_key; - } - if !event.hand.is_empty() { - self.hand = event.hand; - } - self.face = bukkit_block_face_from_string(&event.block_face); - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_bucket_entity::PlayerBucketEntityEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerBucketEntity(PlayerBucketEntityEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - entity_uuid: Some(Uuid { - value: self.entity_uuid.to_string(), - }), - entity_type: self.entity_type.clone(), - original_bucket_key: self.original_bucket_key.clone(), - entity_bucket_key: self.entity_bucket_key.clone(), - hand: self.hand.clone(), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerBucketEntity(event) => { - if let Some(uuid) = event.entity_uuid { - self.entity_uuid = uuid::Uuid::from_str(&uuid.value).ok()?; - } - if !event.entity_type.is_empty() { - self.entity_type = event.entity_type; - } - if !event.original_bucket_key.is_empty() { - self.original_bucket_key = event.original_bucket_key; - } - if !event.entity_bucket_key.is_empty() { - self.entity_bucket_key = event.entity_bucket_key; - } - if !event.hand.is_empty() { - self.hand = event.hand; - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_changed_main_hand::PlayerChangedMainHandEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerChangedMainHand(PlayerChangedMainHandEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - main_hand: bukkit_main_hand(self.main_hand), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerChangedMainHand(event) => { - if let Ok(uuid) = uuid::Uuid::from_str(&event.player_uuid?.value) { - server.get_player_by_uuid(uuid)?; - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_register_channel::PlayerRegisterChannelEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerRegisterChannel(PlayerRegisterChannelEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - channel: self.channel.clone(), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerRegisterChannel(event) => { - if let Ok(uuid) = uuid::Uuid::from_str(&event.player_uuid?.value) { - server.get_player_by_uuid(uuid)?; - } - if !event.channel.is_empty() { - self.channel = event.channel; - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_unregister_channel::PlayerUnregisterChannelEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerUnregisterChannel(PlayerUnregisterChannelEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - channel: self.channel.clone(), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerUnregisterChannel(event) => { - if let Ok(uuid) = uuid::Uuid::from_str(&event.player_uuid?.value) { - server.get_player_by_uuid(uuid)?; - } - if !event.channel.is_empty() { - self.channel = event.channel; - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_move::PlayerMoveEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let world_uuid = self.player.world().uuid; - let yaw = self.player.living_entity.entity.yaw.load(); - let pitch = self.player.living_entity.entity.pitch.load(); - - JvmEventPayload { - event: Event { - data: Some(Data::PlayerMove(PlayerMoveEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - from: Some(build_location(world_uuid, &self.from, yaw, pitch)), - to: Some(build_location(world_uuid, &self.to, yaw, pitch)), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerMove(event) => { - server.get_player_by_uuid(uuid::Uuid::from_str(&event.player_uuid?.value).ok()?)?; - if let Some(from) = event.from { - if let Some(from_vec) = location_to_vec3(from) { - self.from = from_vec; - } - } - if let Some(to) = event.to { - if let Some(to_vec) = location_to_vec3(to) { - self.to = to_vec; - } - } - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_teleport::PlayerTeleportEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let world_uuid = self.player.world().uuid; - let yaw = self.player.living_entity.entity.yaw.load(); - let pitch = self.player.living_entity.entity.pitch.load(); - - JvmEventPayload { - event: Event { - data: Some(Data::PlayerTeleport(PlayerTeleportEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - from: Some(build_location(world_uuid, &self.from, yaw, pitch)), - to: Some(build_location(world_uuid, &self.to, yaw, pitch)), - cause: String::new(), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerTeleport(event) => { - server.get_player_by_uuid(uuid::Uuid::from_str(&event.player_uuid?.value).ok()?)?; - if let Some(from) = event.from { - if let Some(from_vec) = location_to_vec3(from) { - self.from = from_vec; - } - } - if let Some(to) = event.to { - if let Some(to_vec) = location_to_vec3(to) { - self.to = to_vec; - } - } - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_change_world::PlayerChangeWorldEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let location = build_location(self.new_world.uuid, &self.position, self.yaw, self.pitch); - - JvmEventPayload { - event: Event { - data: Some(Data::PlayerChangeWorld(PlayerChangeWorldEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - previous_world: Some(World { - uuid: Some(Uuid { - value: self.previous_world.uuid.to_string(), - }), - }), - new_world: Some(World { - uuid: Some(Uuid { - value: self.new_world.uuid.to_string(), - }), - }), - position: Some(location), - yaw: self.yaw, - pitch: self.pitch, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerChangeWorld(event) => { - if let Some(position) = event.position.and_then(location_to_vec3) { - self.position = position; - } - self.yaw = event.yaw; - self.pitch = event.pitch; - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_gamemode_change::PlayerGamemodeChangeEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerGamemodeChange(PlayerGamemodeChangeEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - previous_gamemode: gamemode_to_bukkit(self.previous_gamemode), - new_gamemode: gamemode_to_bukkit(self.new_gamemode), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerGamemodeChange(event) => { - if let Some(prev) = gamemode_from_bukkit(&event.previous_gamemode) { - self.previous_gamemode = prev; - } - if let Some(next) = gamemode_from_bukkit(&event.new_gamemode) { - self.new_gamemode = next; - } - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_chat::PlayerChatEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let recipients = self - .recipients - .iter() - .map(|player| Uuid { - value: player.gameprofile.id.to_string(), - }) - .collect(); - - JvmEventPayload { - event: Event { - data: Some(Data::PlayerChat(PlayerChatEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - message: self.message.clone(), - recipients, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerChat(event) => { - self.message = event.message; - if !event.recipients.is_empty() { - let mut recipients = Vec::new(); - for recipient in event.recipients { - let uuid = uuid::Uuid::from_str(&recipient.value).ok()?; - if let Some(player) = server.get_player_by_uuid(uuid) { - recipients.push(player); - } - } - self.recipients = recipients; - } - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_command_preprocess::PlayerCommandPreprocessEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerCommand(PlayerCommandEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - command: self.command.clone(), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerCommand(event) => { - if !event.command.is_empty() { - self.command = event.command; - } - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_command_send::PlayerCommandSendEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerCommandSend(crate::proto::patchbukkit::events::PlayerCommandSendEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - commands: self.commands.clone(), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerCommandSend(event) => { - self.commands = event.commands; - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_drop_item::PlayerDropItemEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerDropItem(PlayerDropItemEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - item_uuid: Some(Uuid { - value: self.item_uuid.to_string(), - }), - item_key: item_to_key(self.item_stack.item), - item_amount: i32::from(self.item_stack.item_count), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerDropItem(event) => { - if let Some(uuid) = event.item_uuid { - if let Ok(item_uuid) = uuid::Uuid::from_str(&uuid.value) { - self.item_uuid = item_uuid; - } - } - let mut key = if event.item_key.is_empty() { - None - } else { - Some(event.item_key) - }; - let mut amount = if event.item_amount > 0 { - Some(event.item_amount as u8) - } else { - None - }; - - if key.is_some() || amount.is_some() { - let fallback_key = item_to_key(self.item_stack.item); - let key = key.take().unwrap_or(fallback_key); - let count = amount.take().unwrap_or(self.item_stack.item_count); - self.item_stack = item_stack_from_key(&key, count); - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_edit_book::PlayerEditBookEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerEditBook(PlayerEditBookEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - slot: self.slot, - pages: self.pages.clone(), - title: self.title.clone().unwrap_or_default(), - is_signing: self.is_signing, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerEditBook(event) => { - self.slot = event.slot; - self.pages = event.pages; - self.is_signing = event.is_signing; - self.title = if event.title.is_empty() { - None - } else { - Some(event.title) - }; - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_egg_throw::PlayerEggThrowEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerEggThrow(PlayerEggThrowEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - egg_uuid: Some(Uuid { - value: self.egg_uuid.to_string(), - }), - hatching: self.hatching, - num_hatches: i32::from(self.num_hatches), - hatching_type: self.hatching_type.clone(), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerEggThrow(event) => { - if let Some(uuid) = event.egg_uuid { - if let Ok(egg_uuid) = uuid::Uuid::from_str(&uuid.value) { - self.egg_uuid = egg_uuid; - } - } - self.hatching = event.hatching; - if event.num_hatches >= 0 { - self.num_hatches = event.num_hatches.min(u8::MAX as i32) as u8; - } - if !event.hatching_type.is_empty() { - self.hatching_type = event.hatching_type; - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_exp_change::PlayerExpChangeEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerExpChange(PlayerExpChangeEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - amount: self.amount, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerExpChange(event) => { - self.amount = event.amount; - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_fish::PlayerFishEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerFish(PlayerFishEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - caught_uuid: self.caught_uuid.map(|uuid| Uuid { - value: uuid.to_string(), - }), - caught_type: self.caught_type.clone(), - hook_uuid: Some(Uuid { - value: self.hook_uuid.to_string(), - }), - state: self.state.clone(), - hand: self.hand.clone(), - exp_to_drop: self.exp_to_drop, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerFish(event) => { - self.caught_uuid = event - .caught_uuid - .and_then(|uuid| uuid::Uuid::from_str(&uuid.value).ok()); - if !event.caught_type.is_empty() { - self.caught_type = event.caught_type; - } - if let Some(uuid) = event.hook_uuid { - if let Ok(hook_uuid) = uuid::Uuid::from_str(&uuid.value) { - self.hook_uuid = hook_uuid; - } - } - if !event.state.is_empty() { - self.state = event.state; - } - if !event.hand.is_empty() { - self.hand = event.hand; - } - self.exp_to_drop = event.exp_to_drop; - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_interact_entity::PlayerInteractEntityEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerInteractEntity(PlayerInteractEntityEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - entity_uuid: Some(Uuid { - value: self.entity_uuid.to_string(), - }), - entity_type: self.entity_type.clone(), - hand: self.hand.clone(), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerInteractEntity(event) => { - if let Some(uuid) = event.entity_uuid { - if let Ok(entity_uuid) = uuid::Uuid::from_str(&uuid.value) { - self.entity_uuid = entity_uuid; - } - } - if !event.entity_type.is_empty() { - self.entity_type = event.entity_type; - } - if !event.hand.is_empty() { - self.hand = event.hand; - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_interact_at_entity::PlayerInteractAtEntityEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerInteractAtEntity(PlayerInteractAtEntityEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - entity_uuid: Some(Uuid { - value: self.entity_uuid.to_string(), - }), - entity_type: self.entity_type.clone(), - hand: self.hand.clone(), - clicked_position: Some(Vec3 { - x: f64::from(self.clicked_position.x), - y: f64::from(self.clicked_position.y), - z: f64::from(self.clicked_position.z), - }), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerInteractAtEntity(event) => { - if let Some(uuid) = event.entity_uuid { - if let Ok(entity_uuid) = uuid::Uuid::from_str(&uuid.value) { - self.entity_uuid = entity_uuid; - } - } - if !event.entity_type.is_empty() { - self.entity_type = event.entity_type; - } - if !event.hand.is_empty() { - self.hand = event.hand; - } - if let Some(pos) = event.clicked_position { - self.clicked_position = Vector3::new(pos.x as f32, pos.y as f32, pos.z as f32); - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_item_held::PlayerItemHeldEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerItemHeld(PlayerItemHeldEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - previous_slot: self.previous_slot, - new_slot: self.new_slot, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerItemHeld(event) => { - self.previous_slot = event.previous_slot; - self.new_slot = event.new_slot; - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_item_damage::PlayerItemDamageEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerItemDamage(PlayerItemDamageEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - item_key: item_to_key(self.item_stack.item), - item_amount: i32::from(self.item_stack.item_count), - damage: self.damage, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerItemDamage(event) => { - self.damage = event.damage; - let mut key = if event.item_key.is_empty() { - None - } else { - Some(event.item_key) - }; - let mut amount = if event.item_amount > 0 { - Some(event.item_amount as u8) - } else { - None - }; - - if key.is_some() || amount.is_some() { - let fallback_key = item_to_key(self.item_stack.item); - let key = key.take().unwrap_or(fallback_key); - let count = amount.take().unwrap_or(self.item_stack.item_count); - self.item_stack = item_stack_from_key(&key, count); - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_item_break::PlayerItemBreakEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerItemBreak(PlayerItemBreakEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - item_key: item_to_key(self.item_stack.item), - item_amount: i32::from(self.item_stack.item_count), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerItemBreak(event) => { - let mut key = if event.item_key.is_empty() { - None - } else { - Some(event.item_key) - }; - let mut amount = if event.item_amount > 0 { - Some(event.item_amount as u8) - } else { - None - }; - - if key.is_some() || amount.is_some() { - let fallback_key = item_to_key(self.item_stack.item); - let key = key.take().unwrap_or(fallback_key); - let count = amount.take().unwrap_or(self.item_stack.item_count); - self.item_stack = item_stack_from_key(&key, count); - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_item_consume::PlayerItemConsumeEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let hand = match self.hand { - Hand::Left => "OFF_HAND", - Hand::Right => "HAND", - }; - JvmEventPayload { - event: Event { - data: Some(Data::PlayerItemConsume(PlayerItemConsumeEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - item_key: item_to_key(self.item_stack.item), - item_amount: i32::from(self.item_stack.item_count), - hand: hand.to_string(), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerItemConsume(event) => { - if !event.hand.is_empty() { - self.hand = if event.hand == "OFF_HAND" { - Hand::Left - } else { - Hand::Right - }; - } - - let mut key = if event.item_key.is_empty() { - None - } else { - Some(event.item_key) - }; - let mut amount = if event.item_amount > 0 { - Some(event.item_amount as u8) - } else { - None - }; - - if key.is_some() || amount.is_some() { - let fallback_key = item_to_key(self.item_stack.item); - let key = key.take().unwrap_or(fallback_key); - let count = amount.take().unwrap_or(self.item_stack.item_count); - self.item_stack = item_stack_from_key(&key, count); - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_item_mend::PlayerItemMendEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerItemMend(PlayerItemMendEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - item_key: item_to_key(self.item_stack.item), - item_amount: i32::from(self.item_stack.item_count), - slot: equipment_slot_to_bukkit(&self.slot), - repair_amount: self.repair_amount, - orb_uuid: self.orb_uuid.map(|id| Uuid { value: id.to_string() }), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerItemMend(event) => { - self.repair_amount = event.repair_amount; - if !event.slot.is_empty() { - if let Some(slot) = equipment_slot_from_bukkit(&event.slot) { - self.slot = slot; - } - } - if let Some(uuid) = event.orb_uuid { - if let Ok(orb_uuid) = uuid::Uuid::from_str(&uuid.value) { - self.orb_uuid = Some(orb_uuid); - } - } - let mut key = if event.item_key.is_empty() { - None - } else { - Some(event.item_key) - }; - let mut amount = if event.item_amount > 0 { - Some(event.item_amount as u8) - } else { - None - }; - - if key.is_some() || amount.is_some() { - let fallback_key = item_to_key(self.item_stack.item); - let key = key.take().unwrap_or(fallback_key); - let count = amount.take().unwrap_or(self.item_stack.item_count); - self.item_stack = item_stack_from_key(&key, count); - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_level_change::PlayerLevelChangeEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerLevelChange(PlayerLevelChangeEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - old_level: self.old_level, - new_level: self.new_level, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerLevelChange(event) => { - self.old_level = event.old_level; - self.new_level = event.new_level; - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_kick::PlayerKickEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerKick(PlayerKickEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - reason: serde_json::to_string(&self.reason).unwrap_or_default(), - leave_message: serde_json::to_string(&self.leave_message).unwrap_or_default(), - cause: self.cause.clone(), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerKick(event) => { - if !event.reason.is_empty() { - if let Ok(reason) = serde_json::from_str(&event.reason) { - self.reason = reason; - } - } - if !event.leave_message.is_empty() { - if let Ok(msg) = serde_json::from_str(&event.leave_message) { - self.leave_message = msg; - } - } - if !event.cause.is_empty() { - self.cause = event.cause; - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_toggle_sneak::PlayerToggleSneakEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerToggleSneak(PlayerToggleSneakEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - is_sneaking: self.is_sneaking, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerToggleSneak(event) => { - self.is_sneaking = event.is_sneaking; - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_toggle_sprint::PlayerToggleSprintEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerToggleSprint(PlayerToggleSprintEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - is_sprinting: self.is_sprinting, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerToggleSprint(event) => { - self.is_sprinting = event.is_sprinting; - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_toggle_flight::PlayerToggleFlightEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerToggleFlight(PlayerToggleFlightEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - is_flying: self.is_flying, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerToggleFlight(event) => { - self.is_flying = event.is_flying; - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_swap_hand_items::PlayerSwapHandItemsEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerSwapHandItems(PlayerSwapHandItemsEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - main_hand_item_key: item_to_key(self.main_hand_item.item), - main_hand_item_amount: i32::from(self.main_hand_item.item_count), - off_hand_item_key: item_to_key(self.off_hand_item.item), - off_hand_item_amount: i32::from(self.off_hand_item.item_count), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerSwapHandItems(event) => { - if !event.main_hand_item_key.is_empty() || event.main_hand_item_amount > 0 { - let key = if event.main_hand_item_key.is_empty() { - item_to_key(self.main_hand_item.item) - } else { - event.main_hand_item_key - }; - let count = if event.main_hand_item_amount > 0 { - event.main_hand_item_amount as u8 - } else { - self.main_hand_item.item_count - }; - self.main_hand_item = item_stack_from_key(&key, count); - } - if !event.off_hand_item_key.is_empty() || event.off_hand_item_amount > 0 { - let key = if event.off_hand_item_key.is_empty() { - item_to_key(self.off_hand_item.item) - } else { - event.off_hand_item_key - }; - let count = if event.off_hand_item_amount > 0 { - event.off_hand_item_amount as u8 - } else { - self.off_hand_item.item_count - }; - self.off_hand_item = item_stack_from_key(&key, count); - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_resource_pack_status::PlayerResourcePackStatusEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerResourcePackStatus(PlayerResourcePackStatusEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - pack_uuid: Some(Uuid { - value: self.pack_uuid.to_string(), - }), - status: self.status.clone(), - hash: self.pack_hash.clone(), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerResourcePackStatus(event) => { - if let Some(uuid) = event.pack_uuid { - if let Ok(pack_uuid) = uuid::Uuid::from_str(&uuid.value) { - self.pack_uuid = pack_uuid; - } - } - if !event.status.is_empty() { - self.status = event.status; - } - if !event.hash.is_empty() { - self.pack_hash = event.hash; - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_respawn::PlayerRespawnEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let yaw = self.player.living_entity.entity.yaw.load(); - let pitch = self.player.living_entity.entity.pitch.load(); - JvmEventPayload { - event: Event { - data: Some(Data::PlayerRespawn(PlayerRespawnEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - respawn_location: Some(build_location( - self.world_uuid, - &Vector3::new( - self.respawn_position.x, - self.respawn_position.y, - self.respawn_position.z, - ), - yaw, - pitch, - )), - is_bed_spawn: self.is_bed_spawn, - is_anchor_spawn: self.is_anchor_spawn, - is_missing_respawn_block: self.is_missing_respawn_block, - respawn_reason: self.reason.clone(), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerRespawn(event) => { - if let Some(loc) = event.respawn_location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.respawn_position = pos; - } - if let Some(world) = loc.world.and_then(|w| w.uuid) { - if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { - self.world_uuid = uuid; - } - } - } - self.is_bed_spawn = event.is_bed_spawn; - self.is_anchor_spawn = event.is_anchor_spawn; - self.is_missing_respawn_block = event.is_missing_respawn_block; - if !event.respawn_reason.is_empty() { - self.reason = event.respawn_reason; - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_pickup_arrow::PlayerPickupArrowEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerPickupArrow(PlayerPickupArrowEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - arrow_uuid: Some(Uuid { - value: self.arrow_uuid.to_string(), - }), - item_uuid: Some(Uuid { - value: self.item_uuid.to_string(), - }), - item_key: item_to_key(self.item_stack.item), - item_amount: self.item_stack.item_count as i32, - remaining: self.remaining, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerPickupArrow(event) => { - if let Some(uuid) = event.arrow_uuid { - if let Ok(arrow_uuid) = uuid::Uuid::from_str(&uuid.value) { - self.arrow_uuid = arrow_uuid; - } - } - if let Some(uuid) = event.item_uuid { - if let Ok(item_uuid) = uuid::Uuid::from_str(&uuid.value) { - self.item_uuid = item_uuid; - } - } - if !event.item_key.is_empty() || event.item_amount > 0 { - let key = if event.item_key.is_empty() { - item_to_key(self.item_stack.item) - } else { - event.item_key - }; - let count = if event.item_amount > 0 { - event.item_amount as u8 - } else { - self.item_stack.item_count - }; - self.item_stack = item_stack_from_key(&key, count); - } - self.remaining = event.remaining; - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_portal::PlayerPortalEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let yaw = self.player.living_entity.entity.yaw.load(); - let pitch = self.player.living_entity.entity.pitch.load(); - JvmEventPayload { - event: Event { - data: Some(Data::PlayerPortal(PlayerPortalEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - from: Some(build_location( - self.from_world_uuid, - &self.from_position, - yaw, - pitch, - )), - to: Some(build_location( - self.to_world_uuid, - &self.to_position, - yaw, - pitch, - )), - cause: self.cause.clone(), - search_radius: self.search_radius, - can_create_portal: self.can_create_portal, - creation_radius: self.creation_radius, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerPortal(event) => { - if let Some(from) = event.from { - if let Some(pos) = location_to_vec3(from.clone()) { - self.from_position = pos; - } - if let Some(world) = from.world.and_then(|w| w.uuid) { - if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { - self.from_world_uuid = uuid; - } - } - } - if let Some(to) = event.to { - if let Some(pos) = location_to_vec3(to.clone()) { - self.to_position = pos; - } - if let Some(world) = to.world.and_then(|w| w.uuid) { - if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { - self.to_world_uuid = uuid; - } - } - } - if !event.cause.is_empty() { - self.cause = event.cause; - } - self.search_radius = event.search_radius; - self.can_create_portal = event.can_create_portal; - self.creation_radius = event.creation_radius; - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_recipe_discover::PlayerRecipeDiscoverEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerRecipeDiscover(PlayerRecipeDiscoverEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - recipe_key: self.recipe_key.clone(), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerRecipeDiscover(event) => { - if !event.recipe_key.is_empty() { - self.recipe_key = event.recipe_key; - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_riptide::PlayerRiptideEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerRiptide(PlayerRiptideEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - item_key: item_to_key(self.item_stack.item), - item_amount: self.item_stack.item_count as i32, - velocity: Some(Vec3 { - x: self.velocity.x, - y: self.velocity.y, - z: self.velocity.z, - }), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerRiptide(event) => { - if !event.item_key.is_empty() || event.item_amount > 0 { - let key = if event.item_key.is_empty() { - item_to_key(self.item_stack.item) - } else { - event.item_key - }; - let count = if event.item_amount > 0 { - event.item_amount as u8 - } else { - self.item_stack.item_count - }; - self.item_stack = item_stack_from_key(&key, count); - } - if let Some(velocity) = event.velocity { - self.velocity = Vector3::new(velocity.x, velocity.y, velocity.z); - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_shear_entity::PlayerShearEntityEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerShearEntity(PlayerShearEntityEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - entity_uuid: Some(Uuid { - value: self.entity_uuid.to_string(), - }), - entity_type: self.entity_type.clone(), - item_key: item_to_key(self.item_stack.item), - item_amount: self.item_stack.item_count as i32, - hand: self.hand.clone(), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerShearEntity(event) => { - if let Some(uuid) = event.entity_uuid { - if let Ok(entity_uuid) = uuid::Uuid::from_str(&uuid.value) { - self.entity_uuid = entity_uuid; - } - } - if !event.entity_type.is_empty() { - self.entity_type = event.entity_type; - } - if !event.item_key.is_empty() || event.item_amount > 0 { - let key = if event.item_key.is_empty() { - item_to_key(self.item_stack.item) - } else { - event.item_key - }; - let count = if event.item_amount > 0 { - event.item_amount as u8 - } else { - self.item_stack.item_count - }; - self.item_stack = item_stack_from_key(&key, count); - } - if !event.hand.is_empty() { - self.hand = event.hand; - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_spawn_location::PlayerSpawnLocationEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let yaw = self.player.living_entity.entity.yaw.load(); - let pitch = self.player.living_entity.entity.pitch.load(); - JvmEventPayload { - event: Event { - data: Some(Data::PlayerSpawnLocation(PlayerSpawnLocationEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - spawn_location: Some(build_location( - self.world_uuid, - &self.spawn_position, - yaw, - pitch, - )), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerSpawnLocation(event) => { - if let Some(loc) = event.spawn_location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.spawn_position = pos; - } - if let Some(world) = loc.world.and_then(|w| w.uuid) { - if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { - self.world_uuid = uuid; - } - } - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_statistic_increment::PlayerStatisticIncrementEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerStatisticIncrement(PlayerStatisticIncrementEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - statistic: self.statistic.clone(), - initial_value: self.initial_value, - new_value: self.new_value, - entity_type: self.entity_type.clone(), - material_key: self.material_key.clone(), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerStatisticIncrement(event) => { - if !event.statistic.is_empty() { - self.statistic = event.statistic; - } - self.initial_value = event.initial_value; - self.new_value = event.new_value; - if !event.entity_type.is_empty() { - self.entity_type = event.entity_type; - } - if !event.material_key.is_empty() { - self.material_key = event.material_key; - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_velocity::PlayerVelocityEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PlayerVelocity(PlayerVelocityEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - velocity: Some(Vec3 { - x: self.velocity.x, - y: self.velocity.y, - z: self.velocity.z, - }), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerVelocity(event) => { - if let Some(velocity) = event.velocity { - self.velocity = Vector3::new(velocity.x, velocity.y, velocity.z); - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_harvest_block::PlayerHarvestBlockEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let yaw = self.player.living_entity.entity.yaw.load(); - let pitch = self.player.living_entity.entity.pitch.load(); - JvmEventPayload { - event: Event { - data: Some(Data::PlayerHarvestBlock(PlayerHarvestBlockEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - block_location: Some(build_location( - self.player.world().uuid, - &Vector3::new( - f64::from(self.block_pos.0.x), - f64::from(self.block_pos.0.y), - f64::from(self.block_pos.0.z), - ), - yaw, - pitch, - )), - block_key: self.block_key.clone(), - item_key: item_to_key(self.item_stack.item), - item_amount: self.item_stack.item_count as i32, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PlayerHarvestBlock(event) => { - if let Some(loc) = event.block_location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.block_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - } - if let Some(world) = loc.world.and_then(|w| w.uuid) { - if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { - if uuid != self.player.world().uuid { - // World changes are not supported for harvest event. - } - } - } - } - if !event.block_key.is_empty() { - self.block_key = event.block_key; - } - if !event.item_key.is_empty() || event.item_amount > 0 { - let key = if event.item_key.is_empty() { - item_to_key(self.item_stack.item) - } else { - event.item_key - }; - let count = if event.item_amount > 0 { - event.item_amount as u8 - } else { - self.item_stack.item_count - }; - self.item_stack = item_stack_from_key(&key, count); - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::player::player_interact_event::PlayerInteractEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let world_uuid = self.player.world().uuid; - let yaw = self.player.living_entity.entity.yaw.load(); - let pitch = self.player.living_entity.entity.pitch.load(); - - let clicked = self.clicked_pos.map(|pos| { - build_location( - world_uuid, - &Vector3::new( - f64::from(pos.0.x), - f64::from(pos.0.y), - f64::from(pos.0.z), - ), - yaw, - pitch, - ) - }); - - JvmEventPayload { - event: Event { - data: Some(Data::PlayerInteract(PlayerInteractEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - action: interact_action_to_bukkit(&self.action), - block_key: block_to_key(self.block), - clicked, - item_key: self.item_key.clone(), - block_face: block_face_to_bukkit(self.face), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, _data: Data) -> Option<()> { - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_break::BlockBreakEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let (player_uuid, world_uuid) = if let Some(player) = &self.player { - (player.gameprofile.id.to_string(), Some(player.world().uuid)) - } else { - ("00000000-0000-0000-0000-000000000000".to_string(), None) - }; - - let location = world_uuid.map(|world_uuid| { - build_location( - world_uuid, - &Vector3::new( - f64::from(self.block_position.0.x), - f64::from(self.block_position.0.y), - f64::from(self.block_position.0.z), - ), - 0.0, - 0.0, - ) - }); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockBreak(BlockBreakEvent { - player_uuid: Some(Uuid { value: player_uuid }), - block_key: block_to_key(self.block), - location, - exp: self.exp, - drop: self.drop, - })), - }, - context: EventContext { - server, - player: self.player.clone(), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockBreak(event) => { - self.exp = event.exp; - self.drop = event.drop; - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_damage::BlockDamageEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let player_uuid = self.player.gameprofile.id.to_string(); - let world_uuid = self.player.world().uuid; - let location = build_location( - world_uuid, - &Vector3::new( - f64::from(self.block_position.0.x), - f64::from(self.block_position.0.y), - f64::from(self.block_position.0.z), - ), - 0.0, - 0.0, - ); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockDamage(BlockDamageEvent { - player_uuid: Some(Uuid { value: player_uuid }), - block_key: block_to_key(self.block), - location: Some(location), - item_key: item_to_key(self.item_stack.item), - insta_break: self.insta_break, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockDamage(event) => { - self.insta_break = event.insta_break; - if !event.item_key.is_empty() { - let count = self.item_stack.item_count; - self.item_stack = item_stack_from_key(&event.item_key, count); - } - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_damage_abort::BlockDamageAbortEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let player_uuid = self.player.gameprofile.id.to_string(); - let world_uuid = self.player.world().uuid; - let location = build_location( - world_uuid, - &Vector3::new( - f64::from(self.block_position.0.x), - f64::from(self.block_position.0.y), - f64::from(self.block_position.0.z), - ), - 0.0, - 0.0, - ); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockDamageAbort(BlockDamageAbortEvent { - player_uuid: Some(Uuid { value: player_uuid }), - block_key: block_to_key(self.block), - location: Some(location), - item_key: item_to_key(self.item_stack.item), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockDamageAbort(event) => { - if !event.item_key.is_empty() { - let count = self.item_stack.item_count; - self.item_stack = item_stack_from_key(&event.item_key, count); - } - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_dispense::BlockDispenseEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let world_uuid = server - .worlds - .load() - .first() - .map(|world| world.uuid) - .unwrap_or_default(); - let location = build_location( - world_uuid, - &Vector3::new( - f64::from(self.block_position.0.x), - f64::from(self.block_position.0.y), - f64::from(self.block_position.0.z), - ), - 0.0, - 0.0, - ); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockDispense(BlockDispenseEvent { - block_key: block_to_key(self.block), - location: Some(location), - item_key: item_to_key(self.item_stack.item), - item_amount: i32::from(self.item_stack.item_count), - velocity: Some(Vec3 { - x: self.velocity.x, - y: self.velocity.y, - z: self.velocity.z, - }), - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockDispense(event) => { - if !event.item_key.is_empty() || event.item_amount > 0 { - let key = if event.item_key.is_empty() { - item_to_key(self.item_stack.item) - } else { - event.item_key - }; - let count = if event.item_amount > 0 { - event.item_amount as u8 - } else { - self.item_stack.item_count - }; - self.item_stack = item_stack_from_key(&key, count); - } - if let Some(vel) = event.velocity { - self.velocity = Vector3::new(vel.x, vel.y, vel.z); - } - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_drop_item::BlockDropItemEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let world_uuid = self.player.world().uuid; - let location = build_location( - world_uuid, - &Vector3::new( - f64::from(self.block_position.0.x), - f64::from(self.block_position.0.y), - f64::from(self.block_position.0.z), - ), - 0.0, - 0.0, - ); - let items = self - .items - .iter() - .map(|item| BlockDropItemEntry { - item_key: item_to_key(item.item), - item_amount: i32::from(item.item_count), - }) - .collect(); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockDropItem(BlockDropItemEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - block_key: block_to_key(self.block), - location: Some(location), - items, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockDropItem(event) => { - if !event.items.is_empty() { - let mut items = Vec::with_capacity(event.items.len()); - for entry in event.items { - if entry.item_key.is_empty() && entry.item_amount <= 0 { - continue; - } - let key = if entry.item_key.is_empty() { - "minecraft:air" - } else { - entry.item_key.as_str() - }; - let stack = item_stack_from_key(key, entry.item_amount.clamp(0, u8::MAX as i32) as u8); - if !stack.is_empty() { - items.push(stack); - } - } - self.items = items; - } - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_explode::BlockExplodeEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let location = build_location( - self.world_uuid, - &Vector3::new( - f64::from(self.block_position.0.x), - f64::from(self.block_position.0.y), - f64::from(self.block_position.0.z), - ), - 0.0, - 0.0, - ); - let blocks = self - .blocks - .iter() - .map(|pos| { - let loc = build_location( - self.world_uuid, - &Vector3::new(f64::from(pos.0.x), f64::from(pos.0.y), f64::from(pos.0.z)), - 0.0, - 0.0, - ); - BlockExplodeBlockEntry { - block_key: String::new(), - location: Some(loc), - } - }) - .collect(); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockExplode(BlockExplodeEvent { - block_key: block_to_key(self.block), - location: Some(location), - yield_: self.yield_rate, - blocks, - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockExplode(event) => { - self.yield_rate = event.yield_; - if !event.blocks.is_empty() { - let mut blocks = Vec::with_capacity(event.blocks.len()); - for entry in event.blocks { - if let Some(loc) = entry.location - && let Some(pos) = location_to_vec3(loc.clone()) - { - blocks.push(pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - )); - } - } - self.blocks = blocks; - } - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_fade::BlockFadeEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let location = build_location( - self.world_uuid, - &Vector3::new( - f64::from(self.block_pos.0.x), - f64::from(self.block_pos.0.y), - f64::from(self.block_pos.0.z), - ), - 0.0, - 0.0, - ); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockFade(BlockFadeEvent { - block_key: block_to_key(self.block), - new_block_key: block_to_key(self.new_block), - location: Some(location), - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockFade(event) => { - if !event.new_block_key.is_empty() { - if let Some(block) = Block::from_name(&event.new_block_key) { - self.new_block = block; - } - } - if let Some(loc) = event.location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.block_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - } - } - if !event.block_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_key) { - self.block = block; - } - } - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_fertilize::BlockFertilizeEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let world_uuid = self.player.world().uuid; - let location = build_location( - world_uuid, - &Vector3::new( - f64::from(self.block_pos.0.x), - f64::from(self.block_pos.0.y), - f64::from(self.block_pos.0.z), - ), - 0.0, - 0.0, - ); - let blocks = self - .blocks - .iter() - .map(|pos| { - let loc = build_location( - world_uuid, - &Vector3::new(f64::from(pos.0.x), f64::from(pos.0.y), f64::from(pos.0.z)), - 0.0, - 0.0, - ); - BlockFertilizeBlockEntry { - block_key: block_to_key(self.block), - location: Some(loc), - } - }) - .collect(); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockFertilize(BlockFertilizeEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - block_key: block_to_key(self.block), - location: Some(location), - blocks, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockFertilize(event) => { - if !event.blocks.is_empty() { - let mut blocks = Vec::with_capacity(event.blocks.len()); - for entry in event.blocks { - if let Some(loc) = entry.location - && let Some(pos) = location_to_vec3(loc.clone()) - { - blocks.push(pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - )); - } - } - self.blocks = blocks; - } - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_form::BlockFormEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let location = build_location( - self.world_uuid, - &Vector3::new( - f64::from(self.block_pos.0.x), - f64::from(self.block_pos.0.y), - f64::from(self.block_pos.0.z), - ), - 0.0, - 0.0, - ); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockForm(BlockFormEvent { - block_key: block_to_key(self.old_block), - new_block_key: block_to_key(self.new_block), - location: Some(location), - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockForm(event) => { - if !event.new_block_key.is_empty() { - if let Some(block) = Block::from_name(&event.new_block_key) { - self.new_block = block; - } - } - if let Some(loc) = event.location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.block_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - } - } - if !event.block_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_key) { - self.old_block = block; - } - } - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_from_to::BlockFromToEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let location = build_location( - self.world_uuid, - &Vector3::new( - f64::from(self.block_pos.0.x), - f64::from(self.block_pos.0.y), - f64::from(self.block_pos.0.z), - ), - 0.0, - 0.0, - ); - let to_location = build_location( - self.world_uuid, - &Vector3::new( - f64::from(self.to_pos.0.x), - f64::from(self.to_pos.0.y), - f64::from(self.to_pos.0.z), - ), - 0.0, - 0.0, - ); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockFromTo(BlockFromToEvent { - block_key: block_to_key(self.block), - location: Some(location), - to_block_key: block_to_key(self.to_block), - to_location: Some(to_location), - face: block_face_to_bukkit(Some(self.face)), - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockFromTo(event) => { - if !event.to_block_key.is_empty() { - if let Some(block) = Block::from_name(&event.to_block_key) { - self.to_block = block; - } - } - if let Some(loc) = event.to_location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.to_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - } - } - if let Some(face) = bukkit_block_face_from_string(&event.face) { - self.face = face; - } - if !event.block_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_key) { - self.block = block; - } - } - if let Some(loc) = event.location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.block_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - } - } - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_grow::BlockGrowEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let location = build_location( - self.world_uuid, - &Vector3::new( - f64::from(self.block_pos.0.x), - f64::from(self.block_pos.0.y), - f64::from(self.block_pos.0.z), - ), - 0.0, - 0.0, - ); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockGrow(BlockGrowEvent { - block_key: block_to_key(self.block), - new_block_key: block_to_key(self.new_block), - location: Some(location), - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockGrow(event) => { - if !event.new_block_key.is_empty() { - if let Some(block) = Block::from_name(&event.new_block_key) { - self.new_block = block; - } - } - if let Some(loc) = event.location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.block_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - } - } - if !event.block_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_key) { - self.block = block; - } - } - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_piston_extend::BlockPistonExtendEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let location = build_location( - self.world_uuid, - &Vector3::new( - f64::from(self.block_pos.0.x), - f64::from(self.block_pos.0.y), - f64::from(self.block_pos.0.z), - ), - 0.0, - 0.0, - ); - let blocks = self - .blocks - .iter() - .map(|pos| { - let loc = build_location( - self.world_uuid, - &Vector3::new(f64::from(pos.0.x), f64::from(pos.0.y), f64::from(pos.0.z)), - 0.0, - 0.0, - ); - BlockPistonBlockEntry { - block_key: String::new(), - location: Some(loc), - } - }) - .collect(); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockPistonExtend(BlockPistonExtendEvent { - block_key: block_to_key(self.block), - location: Some(location), - direction: block_face_to_bukkit(Some(self.direction)), - length: self.length, - blocks, - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockPistonExtend(event) => { - self.length = event.length; - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_piston_retract::BlockPistonRetractEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let location = build_location( - self.world_uuid, - &Vector3::new( - f64::from(self.block_pos.0.x), - f64::from(self.block_pos.0.y), - f64::from(self.block_pos.0.z), - ), - 0.0, - 0.0, - ); - let blocks = self - .blocks - .iter() - .map(|pos| { - let loc = build_location( - self.world_uuid, - &Vector3::new(f64::from(pos.0.x), f64::from(pos.0.y), f64::from(pos.0.z)), - 0.0, - 0.0, - ); - BlockPistonBlockEntry { - block_key: String::new(), - location: Some(loc), - } - }) - .collect(); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockPistonRetract(BlockPistonRetractEvent { - block_key: block_to_key(self.block), - location: Some(location), - direction: block_face_to_bukkit(Some(self.direction)), - length: self.length, - blocks, - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockPistonRetract(event) => { - self.length = event.length; - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_redstone::BlockRedstoneEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let world_uuid = server - .worlds - .load() - .first() - .map(|world| world.uuid) - .unwrap_or_default(); - let location = build_location( - world_uuid, - &Vector3::new( - f64::from(self.block_pos.0.x), - f64::from(self.block_pos.0.y), - f64::from(self.block_pos.0.z), - ), - 0.0, - 0.0, - ); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockRedstone(BlockRedstoneEvent { - block_key: block_to_key(self.block), - location: Some(location), - old_current: self.old_current, - new_current: self.new_current, - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockRedstone(event) => { - self.new_current = event.new_current; - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_multi_place::BlockMultiPlaceEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let world_uuid = self.player.world().uuid; - let origin = self - .positions - .first() - .copied() - .unwrap_or_else(|| self.player.position().to_block_pos()); - let location = build_location( - world_uuid, - &Vector3::new( - f64::from(origin.0.x), - f64::from(origin.0.y), - f64::from(origin.0.z), - ), - 0.0, - 0.0, - ); - let blocks = self - .positions - .iter() - .map(|pos| { - let loc = build_location( - world_uuid, - &Vector3::new(f64::from(pos.0.x), f64::from(pos.0.y), f64::from(pos.0.z)), - 0.0, - 0.0, - ); - BlockMultiPlaceBlockEntry { - block_key: block_to_key(self.block_placed), - location: Some(loc), - } - }) - .collect(); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockMultiPlace(BlockMultiPlaceEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - block_key: block_to_key(self.block_placed), - location: Some(location), - blocks, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, _data: Data) -> Option<()> { - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_physics::BlockPhysicsEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let location = build_location( - self.world_uuid, - &Vector3::new( - f64::from(self.block_pos.0.x), - f64::from(self.block_pos.0.y), - f64::from(self.block_pos.0.z), - ), - 0.0, - 0.0, - ); - let source_location = build_location( - self.world_uuid, - &Vector3::new( - f64::from(self.source_pos.0.x), - f64::from(self.source_pos.0.y), - f64::from(self.source_pos.0.z), - ), - 0.0, - 0.0, - ); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockPhysics(BlockPhysicsEvent { - block_key: block_to_key(self.block), - location: Some(location), - source_block_key: block_to_key(self.source_block), - source_location: Some(source_location), - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, _data: Data) -> Option<()> { - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::note_play::NotePlayEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let location = build_location( - self.world_uuid, - &Vector3::new( - f64::from(self.block_pos.0.x), - f64::from(self.block_pos.0.y), - f64::from(self.block_pos.0.z), - ), - 0.0, - 0.0, - ); - - JvmEventPayload { - event: Event { - data: Some(Data::NotePlay(NotePlayEvent { - block_key: block_to_key(self.block), - location: Some(location), - instrument: instrument_to_bukkit(self.instrument), - note: i32::from(self.note), - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::NotePlay(event) => { - if !event.block_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_key) { - self.block = block; - } - } - if let Some(loc) = event.location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.block_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - } - if let Some(world) = loc.world.and_then(|w| w.uuid) { - if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { - self.world_uuid = uuid; - } - } - } - if !event.instrument.is_empty() { - if let Some(instrument) = instrument_from_bukkit(&event.instrument) { - self.instrument = instrument; - } - } - self.note = event.note.clamp(0, 24) as u8; - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::sign_change::SignChangeEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let world_uuid = self.player.world().uuid; - let location = build_location( - world_uuid, - &Vector3::new( - f64::from(self.block_pos.0.x), - f64::from(self.block_pos.0.y), - f64::from(self.block_pos.0.z), - ), - 0.0, - 0.0, - ); - - JvmEventPayload { - event: Event { - data: Some(Data::SignChange(SignChangeEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - block_key: block_to_key(self.block), - location: Some(location), - lines: self.lines.clone(), - is_front_text: self.is_front_text, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { - match data { - Data::SignChange(event) => { - if let Some(uuid) = event.player_uuid { - if let Ok(uuid) = uuid::Uuid::from_str(&uuid.value) { - if let Some(player) = server.get_player_by_uuid(uuid) { - self.player = player; - } - } - } - if !event.block_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_key) { - self.block = block; - } - } - if let Some(loc) = event.location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.block_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - } - } - if !event.lines.is_empty() { - self.lines = event.lines; - } - self.is_front_text = event.is_front_text; - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::tnt_prime::TNTPrimeEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let location = build_location( - self.world_uuid, - &Vector3::new( - f64::from(self.block_pos.0.x), - f64::from(self.block_pos.0.y), - f64::from(self.block_pos.0.z), - ), - 0.0, - 0.0, - ); - let player_uuid = self.player.as_ref().map(|player| Uuid { - value: player.gameprofile.id.to_string(), - }); - - JvmEventPayload { - event: Event { - data: Some(Data::TntPrime(TntPrimeEvent { - player_uuid, - block_key: block_to_key(self.block), - location: Some(location), - cause: self.cause.clone(), - })), - }, - context: EventContext { - server, - player: self.player.clone(), - }, - } - } - - fn apply_modifications(&mut self, server: &Arc, data: Data) -> Option<()> { - match data { - Data::TntPrime(event) => { - if let Some(uuid) = event.player_uuid { - if let Ok(uuid) = uuid::Uuid::from_str(&uuid.value) { - self.player = server.get_player_by_uuid(uuid); - } - } else { - self.player = None; - } - if !event.block_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_key) { - self.block = block; - } - } - if let Some(loc) = event.location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.block_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - } - if let Some(world) = loc.world.and_then(|w| w.uuid) { - if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { - self.world_uuid = uuid; - } - } - } - if !event.cause.is_empty() { - self.cause = event.cause; - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::moisture_change::MoistureChangeEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let location = build_location( - self.world_uuid, - &Vector3::new( - f64::from(self.block_pos.0.x), - f64::from(self.block_pos.0.y), - f64::from(self.block_pos.0.z), - ), - 0.0, - 0.0, - ); - let new_block_key = Block::from_state_id(self.new_state_id) - .map(block_to_key) - .unwrap_or_default(); - - JvmEventPayload { - event: Event { - data: Some(Data::MoistureChange(MoistureChangeEvent { - block_key: block_to_key(self.block), - location: Some(location), - new_block_key, - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::MoistureChange(event) => { - if !event.block_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_key) { - self.block = block; - } - } - if let Some(loc) = event.location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.block_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - } - if let Some(world) = loc.world.and_then(|w| w.uuid) { - if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { - self.world_uuid = uuid; - } - } - } - if !event.new_block_key.is_empty() { - if let Some(block) = Block::from_name(&event.new_block_key) { - self.new_state_id = block.default_state.id; - } - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::sponge_absorb::SpongeAbsorbEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let location = build_location( - self.world_uuid, - &Vector3::new( - f64::from(self.block_pos.0.x), - f64::from(self.block_pos.0.y), - f64::from(self.block_pos.0.z), - ), - 0.0, - 0.0, - ); - let blocks = self - .blocks - .iter() - .map(|pos| { - let loc = build_location( - self.world_uuid, - &Vector3::new(f64::from(pos.0.x), f64::from(pos.0.y), f64::from(pos.0.z)), - 0.0, - 0.0, - ); - SpongeAbsorbBlockEntry { - block_key: block_to_key(&Block::WATER), - location: Some(loc), - } - }) - .collect(); - - JvmEventPayload { - event: Event { - data: Some(Data::SpongeAbsorb(SpongeAbsorbEvent { - block_key: block_to_key(self.block), - location: Some(location), - blocks, - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::SpongeAbsorb(event) => { - if !event.block_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_key) { - self.block = block; - } - } - if let Some(loc) = event.location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.block_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - } - if let Some(world) = loc.world.and_then(|w| w.uuid) { - if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { - self.world_uuid = uuid; - } - } - } - if !event.blocks.is_empty() { - let mut blocks = Vec::with_capacity(event.blocks.len()); - for entry in event.blocks { - if let Some(loc) = entry.location.and_then(location_to_vec3) { - blocks.push(pumpkin_util::math::position::BlockPos::new( - loc.x.floor() as i32, - loc.y.floor() as i32, - loc.z.floor() as i32, - )); - } - } - self.blocks = blocks; - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::fluid_level_change::FluidLevelChangeEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let location = build_location( - self.world_uuid, - &Vector3::new( - f64::from(self.block_pos.0.x), - f64::from(self.block_pos.0.y), - f64::from(self.block_pos.0.z), - ), - 0.0, - 0.0, - ); - let new_block_key = Block::from_state_id(self.new_state_id) - .map(block_to_key) - .unwrap_or_default(); - - JvmEventPayload { - event: Event { - data: Some(Data::FluidLevelChange(FluidLevelChangeEvent { - block_key: block_to_key(self.block), - location: Some(location), - new_block_key, - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::FluidLevelChange(event) => { - if !event.block_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_key) { - self.block = block; - } - } - if let Some(loc) = event.location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.block_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - } - if let Some(world) = loc.world.and_then(|w| w.uuid) { - if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { - self.world_uuid = uuid; - } - } - } - if !event.new_block_key.is_empty() { - if let Some(block) = Block::from_name(&event.new_block_key) { - self.new_state_id = block.default_state.id; - } - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::world::spawn_change::SpawnChangeEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let world_uuid = self.world.uuid; - let previous_location = build_location( - world_uuid, - &Vector3::new( - f64::from(self.previous_position.0.x), - f64::from(self.previous_position.0.y), - f64::from(self.previous_position.0.z), - ), - 0.0, - 0.0, - ); - let location = build_location( - world_uuid, - &Vector3::new( - f64::from(self.new_position.0.x), - f64::from(self.new_position.0.y), - f64::from(self.new_position.0.z), - ), - 0.0, - 0.0, - ); - - JvmEventPayload { - event: Event { - data: Some(Data::SpawnChange(SpawnChangeEvent { - previous_location: Some(previous_location), - location: Some(location), - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::SpawnChange(event) => { - if let Some(loc) = event.location.and_then(location_to_vec3) { - self.new_position = pumpkin_util::math::position::BlockPos::new( - loc.x.floor() as i32, - loc.y.floor() as i32, - loc.z.floor() as i32, - ); - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::server::server_list_ping::ServerListPingEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::ServerListPing(ServerListPingEvent { - motd: self.motd.clone(), - max_players: self.max_players as i32, - online_players: self.num_players as i32, - favicon: self.favicon.clone().unwrap_or_default(), - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::ServerListPing(event) => { - if !event.motd.is_empty() { - self.motd = event.motd; - } - if event.max_players >= 0 { - self.max_players = event.max_players as u32; - } - if event.online_players >= 0 { - self.num_players = event.online_players as u32; - } - if !event.favicon.is_empty() { - self.favicon = Some(event.favicon); - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::server::plugin_enable::PluginEnableEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PluginEnable(PluginEnableEvent { - plugin_name: self.plugin_name.clone(), - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PluginEnable(event) => { - if !event.plugin_name.is_empty() { - self.plugin_name = event.plugin_name; - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::server::plugin_disable::PluginDisableEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::PluginDisable(PluginDisableEvent { - plugin_name: self.plugin_name.clone(), - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::PluginDisable(event) => { - if !event.plugin_name.is_empty() { - self.plugin_name = event.plugin_name; - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::server::service_register::ServiceRegisterEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::ServiceRegister(ServiceRegisterEvent { - plugin_name: self.plugin_name.clone(), - service_name: self.service_name.clone(), - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::ServiceRegister(event) => { - if !event.plugin_name.is_empty() { - self.plugin_name = event.plugin_name; - } - if !event.service_name.is_empty() { - self.service_name = event.service_name; - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::server::service_unregister::ServiceUnregisterEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::ServiceUnregister(ServiceUnregisterEvent { - plugin_name: self.plugin_name.clone(), - service_name: self.service_name.clone(), - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::ServiceUnregister(event) => { - if !event.plugin_name.is_empty() { - self.plugin_name = event.plugin_name; - } - if !event.service_name.is_empty() { - self.service_name = event.service_name; - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_place::BlockPlaceEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let player_uuid = self.player.gameprofile.id.to_string(); - let world_uuid = self.player.world().uuid; - let location = build_location( - world_uuid, - &Vector3::new( - f64::from(self.position.0.x), - f64::from(self.position.0.y), - f64::from(self.position.0.z), - ), - 0.0, - 0.0, - ); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockPlace(BlockPlaceEvent { - player_uuid: Some(Uuid { value: player_uuid }), - block_key: block_to_key(self.block_placed), - block_against_key: block_to_key(self.block_placed_against), - location: Some(location), - can_build: self.can_build, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockPlace(event) => { - self.can_build = event.can_build; - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_can_build::BlockCanBuildEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let player_uuid = self.player.gameprofile.id.to_string(); - let world_uuid = self.player.world().uuid; - let location = build_location( - world_uuid, - &Vector3::new( - f64::from(self.block_pos.0.x), - f64::from(self.block_pos.0.y), - f64::from(self.block_pos.0.z), - ), - 0.0, - 0.0, - ); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockCanBuild(BlockCanBuildEvent { - player_uuid: Some(Uuid { value: player_uuid }), - block_key: block_to_key(self.block_to_build), - block_against_key: block_to_key(self.block), - location: Some(location), - can_build: self.buildable, - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockCanBuild(event) => { - self.buildable = event.can_build; - if let Some(loc) = event.location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.block_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - } - } - if !event.block_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_key) { - self.block_to_build = block; - } - } - if !event.block_against_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_against_key) { - self.block = block; - } - } - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_burn::BlockBurnEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let location = build_location( - self.world_uuid, - &Vector3::new( - f64::from(self.block_pos.0.x), - f64::from(self.block_pos.0.y), - f64::from(self.block_pos.0.z), - ), - 0.0, - 0.0, - ); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockBurn(BlockBurnEvent { - block_key: block_to_key(self.block), - igniting_block_key: block_to_key(self.igniting_block), - location: Some(location), - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, _data: Data) -> Option<()> { - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_ignite::BlockIgniteEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let location = build_location( - self.world_uuid, - &Vector3::new( - f64::from(self.block_pos.0.x), - f64::from(self.block_pos.0.y), - f64::from(self.block_pos.0.z), - ), - 0.0, - 0.0, - ); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockIgnite(BlockIgniteEvent { - player_uuid: Some(Uuid { - value: self.player.gameprofile.id.to_string(), - }), - block_key: block_to_key(self.block), - igniting_block_key: block_to_key(self.igniting_block), - location: Some(location), - cause: self.cause.clone(), - })), - }, - context: EventContext { - server, - player: Some(self.player.clone()), - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockIgnite(event) => { - if !event.block_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_key) { - self.block = block; - } - } - if !event.igniting_block_key.is_empty() { - if let Some(block) = Block::from_name(&event.igniting_block_key) { - self.igniting_block = block; - } - } - if let Some(loc) = event.location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.block_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - } - if let Some(world) = loc.world.and_then(|w| w.uuid) { - if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { - self.world_uuid = uuid; - } - } - } - if !event.cause.is_empty() { - self.cause = event.cause; - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::block::block_spread::BlockSpreadEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - let source_location = build_location( - self.world_uuid, - &Vector3::new( - f64::from(self.source_pos.0.x), - f64::from(self.source_pos.0.y), - f64::from(self.source_pos.0.z), - ), - 0.0, - 0.0, - ); - let location = build_location( - self.world_uuid, - &Vector3::new( - f64::from(self.block_pos.0.x), - f64::from(self.block_pos.0.y), - f64::from(self.block_pos.0.z), - ), - 0.0, - 0.0, - ); - - JvmEventPayload { - event: Event { - data: Some(Data::BlockSpread(BlockSpreadEvent { - source_block_key: block_to_key(self.source_block), - source_location: Some(source_location), - block_key: block_to_key(self.block), - location: Some(location), - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::BlockSpread(event) => { - if !event.source_block_key.is_empty() { - if let Some(block) = Block::from_name(&event.source_block_key) { - self.source_block = block; - } - } - if !event.block_key.is_empty() { - if let Some(block) = Block::from_name(&event.block_key) { - self.block = block; - } - } - if let Some(loc) = event.source_location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.source_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - } - if let Some(world) = loc.world.and_then(|w| w.uuid) { - if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { - self.world_uuid = uuid; - } - } - } - if let Some(loc) = event.location { - if let Some(pos) = location_to_vec3(loc.clone()) { - self.block_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - } - if let Some(world) = loc.world.and_then(|w| w.uuid) { - if let Ok(uuid) = uuid::Uuid::from_str(&world.value) { - self.world_uuid = uuid; - } - } - } - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::entity::entity_spawn::EntitySpawnEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::EntitySpawn(EntitySpawnEvent { - entity_uuid: Some(Uuid { - value: self.entity_uuid.to_string(), - }), - entity_type: self.entity_type.id.to_string(), - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, _data: Data) -> Option<()> { - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::entity::entity_damage::EntityDamageEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::EntityDamage(EntityDamageEvent { - entity_uuid: Some(Uuid { - value: self.entity_uuid.to_string(), - }), - damage: self.damage, - damage_type: self.damage_type.message_id.to_string(), - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::EntityDamage(event) => { - self.damage = event.damage; - } - _ => {} - } - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::entity::entity_death::EntityDeathEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::EntityDeath(EntityDeathEvent { - entity_uuid: Some(Uuid { - value: self.entity_uuid.to_string(), - }), - damage_type: self.damage_type.message_id.to_string(), - })), - }, - context: EventContext { server, player: None }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, _data: Data) -> Option<()> { - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::server::server_command::ServerCommandEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::ServerCommand(ServerCommandEvent { - command: self.command.clone(), - })), - }, - context: EventContext { - server, - player: None, - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::ServerCommand(event) => { - self.command = event.command; - } - _ => {} - } - - Some(()) - } -} - -impl PatchBukkitEvent for pumpkin::plugin::server::server_broadcast::ServerBroadcastEvent { - fn to_payload(&self, server: Arc) -> JvmEventPayload { - JvmEventPayload { - event: Event { - data: Some(Data::ServerBroadcast(ServerBroadcastEvent { - message: serde_json::to_string(&self.message).unwrap(), - sender: serde_json::to_string(&self.sender).unwrap(), - })), - }, - context: EventContext { - server, - player: None, - }, - } - } - - fn apply_modifications(&mut self, _server: &Arc, data: Data) -> Option<()> { - match data { - Data::ServerBroadcast(event) => { - self.message = serde_json::from_str(&event.message).unwrap_or_else(|_| { - TextComponent::from_legacy_string(&event.message) - }); - self.sender = serde_json::from_str(&event.sender).unwrap_or_else(|_| { - TextComponent::from_legacy_string(&event.sender) - }); - } - _ => {} - } - - Some(()) - } -} - -fn build_location(world_uuid: uuid::Uuid, position: &Vector3, yaw: f32, pitch: f32) -> Location { - Location { - world: Some(World { - uuid: Some(Uuid { - value: world_uuid.to_string(), - }), - }), - position: Some(Vec3 { - x: position.x, - y: position.y, - z: position.z, - }), - yaw, - pitch, - } -} - -fn location_to_vec3(location: Location) -> Option> { - let pos = location.position?; - Some(Vector3::new(pos.x, pos.y, pos.z)) -} - -fn block_to_key(block: &Block) -> String { - format!("minecraft:{}", block.name) -} - -fn item_to_key(item: &Item) -> String { - format!("minecraft:{}", item.registry_key) -} - -fn item_stack_from_key(key: &str, amount: u8) -> ItemStack { - let trimmed = key.strip_prefix("minecraft:").unwrap_or(key); - let item = Item::from_registry_key(trimmed).unwrap_or(&Item::AIR); - ItemStack::new(amount, item) -} - -fn equipment_slot_to_bukkit(slot: &EquipmentSlot) -> String { - match slot { - EquipmentSlot::MainHand(_) => "HAND".to_string(), - EquipmentSlot::OffHand(_) => "OFF_HAND".to_string(), - EquipmentSlot::Feet(_) => "FEET".to_string(), - EquipmentSlot::Legs(_) => "LEGS".to_string(), - EquipmentSlot::Chest(_) => "CHEST".to_string(), - EquipmentSlot::Head(_) => "HEAD".to_string(), - EquipmentSlot::Body(_) => "BODY".to_string(), - EquipmentSlot::Saddle(_) => "SADDLE".to_string(), - } -} - -fn equipment_slot_from_bukkit(slot: &str) -> Option { - match slot { - "HAND" => Some(EquipmentSlot::MAIN_HAND), - "OFF_HAND" => Some(EquipmentSlot::OFF_HAND), - "FEET" => Some(EquipmentSlot::FEET), - "LEGS" => Some(EquipmentSlot::LEGS), - "CHEST" => Some(EquipmentSlot::CHEST), - "HEAD" => Some(EquipmentSlot::HEAD), - "BODY" => Some(EquipmentSlot::BODY), - "SADDLE" => Some(EquipmentSlot::SADDLE), - _ => None, - } -} - -fn interact_action_to_bukkit(action: &pumpkin::plugin::player::player_interact_event::InteractAction) -> String { - match action { - pumpkin::plugin::player::player_interact_event::InteractAction::LeftClickBlock => { - "LEFT_CLICK_BLOCK".to_string() - } - pumpkin::plugin::player::player_interact_event::InteractAction::LeftClickAir => { - "LEFT_CLICK_AIR".to_string() - } - pumpkin::plugin::player::player_interact_event::InteractAction::RightClickAir => { - "RIGHT_CLICK_AIR".to_string() - } - pumpkin::plugin::player::player_interact_event::InteractAction::RightClickBlock => { - "RIGHT_CLICK_BLOCK".to_string() - } - } -} - -fn gamemode_to_bukkit(mode: pumpkin_util::GameMode) -> String { - match mode { - pumpkin_util::GameMode::Survival => "SURVIVAL".to_string(), - pumpkin_util::GameMode::Creative => "CREATIVE".to_string(), - pumpkin_util::GameMode::Adventure => "ADVENTURE".to_string(), - pumpkin_util::GameMode::Spectator => "SPECTATOR".to_string(), - } -} - -fn gamemode_from_bukkit(mode: &str) -> Option { - match mode { - "SURVIVAL" => Some(pumpkin_util::GameMode::Survival), - "CREATIVE" => Some(pumpkin_util::GameMode::Creative), - "ADVENTURE" => Some(pumpkin_util::GameMode::Adventure), - "SPECTATOR" => Some(pumpkin_util::GameMode::Spectator), - _ => None, - } -} - -fn block_face_to_bukkit(face: Option) -> String { - match face { - Some(BlockDirection::Up) => "UP".to_string(), - Some(BlockDirection::Down) => "DOWN".to_string(), - Some(BlockDirection::North) => "NORTH".to_string(), - Some(BlockDirection::South) => "SOUTH".to_string(), - Some(BlockDirection::West) => "WEST".to_string(), - Some(BlockDirection::East) => "EAST".to_string(), - None => String::new(), - } -} - -fn bukkit_block_face_from_string(face: &str) -> Option { - match face { - "UP" => Some(BlockDirection::Up), - "DOWN" => Some(BlockDirection::Down), - "NORTH" => Some(BlockDirection::North), - "SOUTH" => Some(BlockDirection::South), - "WEST" => Some(BlockDirection::West), - "EAST" => Some(BlockDirection::East), - _ => None, - } -} - -fn bukkit_main_hand(hand: Hand) -> String { - match hand { - Hand::Left => "LEFT".to_string(), - Hand::Right => "RIGHT".to_string(), - } -} - -fn instrument_to_bukkit(instrument: Instrument) -> String { - match instrument { - Instrument::Harp => "PIANO".to_string(), - Instrument::Basedrum => "BASS_DRUM".to_string(), - Instrument::Snare => "SNARE_DRUM".to_string(), - Instrument::Hat => "STICKS".to_string(), - Instrument::Bass => "BASS_GUITAR".to_string(), - Instrument::Flute => "FLUTE".to_string(), - Instrument::Bell => "BELL".to_string(), - Instrument::Guitar => "GUITAR".to_string(), - Instrument::Chime => "CHIME".to_string(), - Instrument::Xylophone => "XYLOPHONE".to_string(), - Instrument::IronXylophone => "IRON_XYLOPHONE".to_string(), - Instrument::CowBell => "COW_BELL".to_string(), - Instrument::Didgeridoo => "DIDGERIDOO".to_string(), - Instrument::Bit => "BIT".to_string(), - Instrument::Banjo => "BANJO".to_string(), - Instrument::Pling => "PLING".to_string(), - Instrument::Zombie => "ZOMBIE".to_string(), - Instrument::Skeleton => "SKELETON".to_string(), - Instrument::Creeper => "CREEPER".to_string(), - Instrument::Dragon => "DRAGON".to_string(), - Instrument::WitherSkeleton => "WITHER_SKELETON".to_string(), - Instrument::Piglin => "PIGLIN".to_string(), - Instrument::CustomHead => "CUSTOM_HEAD".to_string(), - } -} - -fn instrument_from_bukkit(name: &str) -> Option { - match name { - "PIANO" => Some(Instrument::Harp), - "BASS_DRUM" => Some(Instrument::Basedrum), - "SNARE_DRUM" => Some(Instrument::Snare), - "STICKS" => Some(Instrument::Hat), - "BASS_GUITAR" => Some(Instrument::Bass), - "FLUTE" => Some(Instrument::Flute), - "BELL" => Some(Instrument::Bell), - "GUITAR" => Some(Instrument::Guitar), - "CHIME" => Some(Instrument::Chime), - "XYLOPHONE" => Some(Instrument::Xylophone), - "IRON_XYLOPHONE" => Some(Instrument::IronXylophone), - "COW_BELL" => Some(Instrument::CowBell), - "DIDGERIDOO" => Some(Instrument::Didgeridoo), - "BIT" => Some(Instrument::Bit), - "BANJO" => Some(Instrument::Banjo), - "PLING" => Some(Instrument::Pling), - "ZOMBIE" => Some(Instrument::Zombie), - "SKELETON" => Some(Instrument::Skeleton), - "CREEPER" => Some(Instrument::Creeper), - "DRAGON" => Some(Instrument::Dragon), - "WITHER_SKELETON" => Some(Instrument::WitherSkeleton), - "PIGLIN" => Some(Instrument::Piglin), - "CUSTOM_HEAD" => Some(Instrument::CustomHead), - _ => None, - } -} - -pub struct PatchBukkitEventHandler { - plugin_name: String, - command_tx: mpsc::Sender, - _phantom: PhantomData, -} - -impl PatchBukkitEventHandler { - #[must_use] - pub const fn new(plugin_name: String, command_tx: mpsc::Sender) -> Self { - Self { - plugin_name, - command_tx, - _phantom: PhantomData, - } - } -} - -#[with_runtime(global)] -impl EventHandler for PatchBukkitEventHandler -where - E: PatchBukkitEvent + Payload + Cancellable + 'static, -{ - fn handle_blocking<'a>( - &'a self, - server: &'a Arc, - event: &'a mut E, - ) -> BoxFuture<'a, ()> { - let command_tx = self.command_tx.clone(); - - Box::pin(async move { - let (tx, rx) = oneshot::channel(); - if let Err(e) = command_tx - .send(JvmCommand::FireEvent { - payload: event.to_payload(server.clone()), - respond_to: tx, - plugin: self.plugin_name.clone(), - }) - .await - { - log::error!("Failed to send event to JVM worker: {e}"); - return; - } - - match rx.await { - Ok(response) => { - event.set_cancelled(response.cancelled); - event.apply_modifications(server, response.data.unwrap().data.unwrap()); - } - Err(_) => { - log::warn!("JVM worker dropped response channel for event"); - } - } - }) - } -} diff --git a/rust/src/java/jvm/commands.rs b/rust/src/java/jvm/commands.rs index a8301f6..d0c32cf 100644 --- a/rust/src/java/jvm/commands.rs +++ b/rust/src/java/jvm/commands.rs @@ -53,7 +53,7 @@ pub enum JvmCommand { TriggerCommand { full_command: String, command_sender: SimpleCommandSender, - respond_to: oneshot::Sender>, + respond_to: oneshot::Sender>, }, GetCommandTabComplete { command_sender: SimpleCommandSender, diff --git a/rust/src/java/native_callbacks/block.rs b/rust/src/java/native_callbacks/block.rs index 24570d5..ea89540 100644 --- a/rust/src/java/native_callbacks/block.rs +++ b/rust/src/java/native_callbacks/block.rs @@ -14,12 +14,14 @@ pub fn ffi_native_bridge_get_block_impl(request: GetBlockRequest) -> Option O tokio::task::block_in_place(|| { ctx.runtime.block_on(async { - match request.event_type.as_str() { - "org.bukkit.event.player.PlayerJoinEvent" => { + macro_rules! register_bridge_event { + ($event_ty:path) => { context - .register_event::< - pumpkin::plugin::api::events::player::player_join::PlayerJoinEvent, - PatchBukkitEventHandler< - pumpkin::plugin::api::events::player::player_join::PlayerJoinEvent, - >, - >( + .register_event::<$event_ty, PatchBukkitEventHandler<$event_ty>>( Arc::new(PatchBukkitEventHandler::new( request.plugin_name.clone(), command_tx.clone(), @@ -56,637 +51,126 @@ pub fn ffi_native_bridge_register_event_impl(request: RegisterEventRequest) -> O request.blocking, ) .await; + }; + } + + match request.event_type.as_str() { + "org.bukkit.event.player.PlayerJoinEvent" => { + register_bridge_event!(pumpkin::plugin::api::events::player::player_join::PlayerJoinEvent); } "org.bukkit.event.player.PlayerLoginEvent" => { - context - .register_event::< - pumpkin::plugin::api::events::player::player_login::PlayerLoginEvent, - PatchBukkitEventHandler< - pumpkin::plugin::api::events::player::player_login::PlayerLoginEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + register_bridge_event!(pumpkin::plugin::api::events::player::player_login::PlayerLoginEvent); } "org.bukkit.event.player.PlayerQuitEvent" => { - context - .register_event::< - pumpkin::plugin::api::events::player::player_leave::PlayerLeaveEvent, - PatchBukkitEventHandler< - pumpkin::plugin::api::events::player::player_leave::PlayerLeaveEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + register_bridge_event!(pumpkin::plugin::api::events::player::player_leave::PlayerLeaveEvent); } "org.bukkit.event.player.PlayerMoveEvent" => { - context - .register_event::< - pumpkin::plugin::api::events::player::player_move::PlayerMoveEvent, - PatchBukkitEventHandler< - pumpkin::plugin::api::events::player::player_move::PlayerMoveEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + register_bridge_event!(pumpkin::plugin::api::events::player::player_move::PlayerMoveEvent); } "org.bukkit.event.player.PlayerTeleportEvent" => { - context - .register_event::< - pumpkin::plugin::api::events::player::player_teleport::PlayerTeleportEvent, - PatchBukkitEventHandler< - pumpkin::plugin::api::events::player::player_teleport::PlayerTeleportEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + register_bridge_event!(pumpkin::plugin::api::events::player::player_teleport::PlayerTeleportEvent); } "org.bukkit.event.player.PlayerChangedWorldEvent" => { - context - .register_event::< - pumpkin::plugin::api::events::player::player_change_world::PlayerChangeWorldEvent, - PatchBukkitEventHandler< - pumpkin::plugin::api::events::player::player_change_world::PlayerChangeWorldEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + register_bridge_event!(pumpkin::plugin::api::events::player::player_change_world::PlayerChangeWorldEvent); } "org.bukkit.event.player.PlayerGameModeChangeEvent" => { - context - .register_event::< - pumpkin::plugin::api::events::player::player_gamemode_change::PlayerGamemodeChangeEvent, - PatchBukkitEventHandler< - pumpkin::plugin::api::events::player::player_gamemode_change::PlayerGamemodeChangeEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + register_bridge_event!(pumpkin::plugin::api::events::player::player_gamemode_change::PlayerGamemodeChangeEvent); } "org.bukkit.event.player.AsyncPlayerChatEvent" | "org.bukkit.event.player.PlayerChatEvent" => { - context - .register_event::< - pumpkin::plugin::api::events::player::player_chat::PlayerChatEvent, - PatchBukkitEventHandler< - pumpkin::plugin::api::events::player::player_chat::PlayerChatEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + register_bridge_event!(pumpkin::plugin::api::events::player::player_chat::PlayerChatEvent); } "org.bukkit.event.player.PlayerCommandSendEvent" => { - context - .register_event::< - pumpkin::plugin::api::events::player::player_command_send::PlayerCommandSendEvent, - PatchBukkitEventHandler< - pumpkin::plugin::api::events::player::player_command_send::PlayerCommandSendEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + register_bridge_event!(pumpkin::plugin::api::events::player::player_command_send::PlayerCommandSendEvent); } "org.bukkit.event.player.PlayerInteractEvent" => { - context - .register_event::< - pumpkin::plugin::api::events::player::player_interact_event::PlayerInteractEvent, - PatchBukkitEventHandler< - pumpkin::plugin::api::events::player::player_interact_event::PlayerInteractEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + register_bridge_event!(pumpkin::plugin::api::events::player::player_interact_event::PlayerInteractEvent); } "org.bukkit.event.block.BlockBreakEvent" => { - context - .register_event::< - pumpkin::plugin::api::events::block::block_break::BlockBreakEvent, - PatchBukkitEventHandler< - pumpkin::plugin::api::events::block::block_break::BlockBreakEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + register_bridge_event!(pumpkin::plugin::api::events::block::block_break::BlockBreakEvent); } "org.bukkit.event.block.BlockBurnEvent" => { - context - .register_event::< - pumpkin::plugin::api::events::block::block_burn::BlockBurnEvent, - PatchBukkitEventHandler< - pumpkin::plugin::api::events::block::block_burn::BlockBurnEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + register_bridge_event!(pumpkin::plugin::api::events::block::block_burn::BlockBurnEvent); } "org.bukkit.event.block.BlockCanBuildEvent" => { - context - .register_event::< - pumpkin::plugin::api::events::block::block_can_build::BlockCanBuildEvent, - PatchBukkitEventHandler< - pumpkin::plugin::api::events::block::block_can_build::BlockCanBuildEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + register_bridge_event!(pumpkin::plugin::api::events::block::block_can_build::BlockCanBuildEvent); } "org.bukkit.event.block.BlockPlaceEvent" => { - context - .register_event::< - pumpkin::plugin::api::events::block::block_place::BlockPlaceEvent, - PatchBukkitEventHandler< - pumpkin::plugin::api::events::block::block_place::BlockPlaceEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + register_bridge_event!(pumpkin::plugin::api::events::block::block_place::BlockPlaceEvent); } "org.bukkit.event.server.ServerCommandEvent" => { - context - .register_event::< - pumpkin::plugin::api::events::server::server_command::ServerCommandEvent, - PatchBukkitEventHandler< - pumpkin::plugin::api::events::server::server_command::ServerCommandEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + register_bridge_event!(pumpkin::plugin::api::events::server::server_command::ServerCommandEvent); } "org.bukkit.event.server.BroadcastMessageEvent" => { - context - .register_event::< - pumpkin::plugin::api::events::server::server_broadcast::ServerBroadcastEvent, - PatchBukkitEventHandler< - pumpkin::plugin::api::events::server::server_broadcast::ServerBroadcastEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + register_bridge_event!(pumpkin::plugin::api::events::server::server_broadcast::ServerBroadcastEvent); } "org.bukkit.event.player.PlayerBedEnterEvent" => { - context - .register_event::< - pumpkin::plugin::api::events::player::player_bed_enter::PlayerBedEnterEvent, - PatchBukkitEventHandler< - pumpkin::plugin::api::events::player::player_bed_enter::PlayerBedEnterEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + register_bridge_event!(pumpkin::plugin::api::events::player::player_bed_enter::PlayerBedEnterEvent); } "org.bukkit.event.player.PlayerBucketEmptyEvent" => { - context - .register_event::< - pumpkin::plugin::api::events::player::player_bucket_empty::PlayerBucketEmptyEvent, - PatchBukkitEventHandler< - pumpkin::plugin::api::events::player::player_bucket_empty::PlayerBucketEmptyEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + register_bridge_event!(pumpkin::plugin::api::events::player::player_bucket_empty::PlayerBucketEmptyEvent); } "org.bukkit.event.player.PlayerBucketFillEvent" => { - context - .register_event::< - pumpkin::plugin::api::events::player::player_bucket_fill::PlayerBucketFillEvent, - PatchBukkitEventHandler< - pumpkin::plugin::api::events::player::player_bucket_fill::PlayerBucketFillEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + register_bridge_event!(pumpkin::plugin::api::events::player::player_bucket_fill::PlayerBucketFillEvent); } "org.bukkit.event.player.PlayerDropItemEvent" => { - context - .register_event::< - pumpkin::plugin::api::events::player::player_drop_item::PlayerDropItemEvent, - PatchBukkitEventHandler< - pumpkin::plugin::api::events::player::player_drop_item::PlayerDropItemEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + register_bridge_event!(pumpkin::plugin::api::events::player::player_drop_item::PlayerDropItemEvent); } "org.bukkit.event.player.PlayerExpChangeEvent" => { - context - .register_event::< - pumpkin::plugin::api::events::player::player_exp_change::PlayerExpChangeEvent, - PatchBukkitEventHandler< - pumpkin::plugin::api::events::player::player_exp_change::PlayerExpChangeEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + register_bridge_event!(pumpkin::plugin::api::events::player::player_exp_change::PlayerExpChangeEvent); } "org.bukkit.event.player.PlayerItemBreakEvent" => { - context - .register_event::< - pumpkin::plugin::api::events::player::player_item_break::PlayerItemBreakEvent, - PatchBukkitEventHandler< - pumpkin::plugin::api::events::player::player_item_break::PlayerItemBreakEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + register_bridge_event!(pumpkin::plugin::api::events::player::player_item_break::PlayerItemBreakEvent); } "org.bukkit.event.player.PlayerItemConsumeEvent" => { - context - .register_event::< - pumpkin::plugin::api::events::player::player_item_consume::PlayerItemConsumeEvent, - PatchBukkitEventHandler< - pumpkin::plugin::api::events::player::player_item_consume::PlayerItemConsumeEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + register_bridge_event!(pumpkin::plugin::api::events::player::player_item_consume::PlayerItemConsumeEvent); } "org.bukkit.event.player.PlayerItemDamageEvent" => { - context - .register_event::< - pumpkin::plugin::api::events::player::player_item_damage::PlayerItemDamageEvent, - PatchBukkitEventHandler< - pumpkin::plugin::api::events::player::player_item_damage::PlayerItemDamageEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + register_bridge_event!(pumpkin::plugin::api::events::player::player_item_damage::PlayerItemDamageEvent); } "org.bukkit.event.player.PlayerItemHeldEvent" => { - context - .register_event::< - pumpkin::plugin::api::events::player::player_item_held::PlayerItemHeldEvent, - PatchBukkitEventHandler< - pumpkin::plugin::api::events::player::player_item_held::PlayerItemHeldEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + register_bridge_event!(pumpkin::plugin::api::events::player::player_item_held::PlayerItemHeldEvent); } "org.bukkit.event.player.PlayerItemMendEvent" => { - context - .register_event::< - pumpkin::plugin::api::events::player::player_item_mend::PlayerItemMendEvent, - PatchBukkitEventHandler< - pumpkin::plugin::api::events::player::player_item_mend::PlayerItemMendEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + register_bridge_event!(pumpkin::plugin::api::events::player::player_item_mend::PlayerItemMendEvent); } "org.bukkit.event.player.PlayerKickEvent" => { - context - .register_event::< - pumpkin::plugin::api::events::player::player_kick::PlayerKickEvent, - PatchBukkitEventHandler< - pumpkin::plugin::api::events::player::player_kick::PlayerKickEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + register_bridge_event!(pumpkin::plugin::api::events::player::player_kick::PlayerKickEvent); } "org.bukkit.event.player.PlayerLevelChangeEvent" => { - context - .register_event::< - pumpkin::plugin::api::events::player::player_level_change::PlayerLevelChangeEvent, - PatchBukkitEventHandler< - pumpkin::plugin::api::events::player::player_level_change::PlayerLevelChangeEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + register_bridge_event!(pumpkin::plugin::api::events::player::player_level_change::PlayerLevelChangeEvent); } "org.bukkit.event.player.PlayerToggleFlightEvent" => { - context - .register_event::< - pumpkin::plugin::api::events::player::player_toggle_flight::PlayerToggleFlightEvent, - PatchBukkitEventHandler< - pumpkin::plugin::api::events::player::player_toggle_flight::PlayerToggleFlightEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + register_bridge_event!(pumpkin::plugin::api::events::player::player_toggle_flight::PlayerToggleFlightEvent); } "org.bukkit.event.block.BlockDispenseEvent" => { - context - .register_event::< - pumpkin::plugin::api::events::block::block_dispense::BlockDispenseEvent, - PatchBukkitEventHandler< - pumpkin::plugin::api::events::block::block_dispense::BlockDispenseEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + register_bridge_event!(pumpkin::plugin::api::events::block::block_dispense::BlockDispenseEvent); } "org.bukkit.event.block.BlockFormEvent" => { - context - .register_event::< - pumpkin::plugin::api::events::block::block_form::BlockFormEvent, - PatchBukkitEventHandler< - pumpkin::plugin::api::events::block::block_form::BlockFormEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + register_bridge_event!(pumpkin::plugin::api::events::block::block_form::BlockFormEvent); } "org.bukkit.event.block.BlockIgniteEvent" => { - context - .register_event::< - pumpkin::plugin::api::events::block::block_ignite::BlockIgniteEvent, - PatchBukkitEventHandler< - pumpkin::plugin::api::events::block::block_ignite::BlockIgniteEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + register_bridge_event!(pumpkin::plugin::api::events::block::block_ignite::BlockIgniteEvent); } "org.bukkit.event.block.BlockMultiPlaceEvent" => { - context - .register_event::< - pumpkin::plugin::api::events::block::block_multi_place::BlockMultiPlaceEvent, - PatchBukkitEventHandler< - pumpkin::plugin::api::events::block::block_multi_place::BlockMultiPlaceEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + register_bridge_event!(pumpkin::plugin::api::events::block::block_multi_place::BlockMultiPlaceEvent); } "org.bukkit.event.block.BlockRedstoneEvent" => { - context - .register_event::< - pumpkin::plugin::api::events::block::block_redstone::BlockRedstoneEvent, - PatchBukkitEventHandler< - pumpkin::plugin::api::events::block::block_redstone::BlockRedstoneEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + register_bridge_event!(pumpkin::plugin::api::events::block::block_redstone::BlockRedstoneEvent); } "org.bukkit.event.block.MoistureChangeEvent" => { - context - .register_event::< - pumpkin::plugin::api::events::block::moisture_change::MoistureChangeEvent, - PatchBukkitEventHandler< - pumpkin::plugin::api::events::block::moisture_change::MoistureChangeEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + register_bridge_event!(pumpkin::plugin::api::events::block::moisture_change::MoistureChangeEvent); } "org.bukkit.event.block.NotePlayEvent" => { - context - .register_event::< - pumpkin::plugin::api::events::block::note_play::NotePlayEvent, - PatchBukkitEventHandler< - pumpkin::plugin::api::events::block::note_play::NotePlayEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + register_bridge_event!(pumpkin::plugin::api::events::block::note_play::NotePlayEvent); } "org.bukkit.event.block.SignChangeEvent" => { - context - .register_event::< - pumpkin::plugin::api::events::block::sign_change::SignChangeEvent, - PatchBukkitEventHandler< - pumpkin::plugin::api::events::block::sign_change::SignChangeEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; + register_bridge_event!(pumpkin::plugin::api::events::block::sign_change::SignChangeEvent); } "org.bukkit.event.block.TNTPrimeEvent" => { - context - .register_event::< - pumpkin::plugin::api::events::block::tnt_prime::TNTPrimeEvent, - PatchBukkitEventHandler< - pumpkin::plugin::api::events::block::tnt_prime::TNTPrimeEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } _ => { + register_bridge_event!(pumpkin::plugin::api::events::block::tnt_prime::TNTPrimeEvent); + } + _ => { log::warn!("Unsupported Bukkit event registration: {}", request.event_type); } } diff --git a/rust/src/java/native_callbacks/events_legacy.rs b/rust/src/java/native_callbacks/events_legacy.rs deleted file mode 100644 index 48f0963..0000000 --- a/rust/src/java/native_callbacks/events_legacy.rs +++ /dev/null @@ -1,3458 +0,0 @@ -use std::sync::Arc; - -use pumpkin::plugin::EventPriority; -use pumpkin::plugin::block::block_break::BlockBreakEvent; -use pumpkin::plugin::block::block_damage::BlockDamageEvent; -use pumpkin::plugin::block::block_damage_abort::BlockDamageAbortEvent; -use pumpkin::plugin::block::block_dispense::BlockDispenseEvent; -use pumpkin::plugin::block::block_drop_item::BlockDropItemEvent; -use pumpkin::plugin::block::block_explode::BlockExplodeEvent; -use pumpkin::plugin::block::block_fade::BlockFadeEvent; -use pumpkin::plugin::block::block_fertilize::BlockFertilizeEvent; -use pumpkin::plugin::block::block_form::BlockFormEvent; -use pumpkin::plugin::block::block_from_to::BlockFromToEvent; -use pumpkin::plugin::block::block_grow::BlockGrowEvent; -use pumpkin::plugin::block::block_piston_extend::BlockPistonExtendEvent; -use pumpkin::plugin::block::block_piston_retract::BlockPistonRetractEvent; -use pumpkin::plugin::block::block_redstone::BlockRedstoneEvent; -use pumpkin::plugin::block::block_multi_place::BlockMultiPlaceEvent; -use pumpkin::plugin::block::block_physics::BlockPhysicsEvent; -use pumpkin::plugin::block::block_place::BlockPlaceEvent; -use pumpkin::plugin::block::block_can_build::BlockCanBuildEvent; -use pumpkin::plugin::block::block_burn::BlockBurnEvent; -use pumpkin::plugin::block::block_ignite::BlockIgniteEvent; -use pumpkin::plugin::block::block_spread::BlockSpreadEvent; -use pumpkin::plugin::player::player_chat::PlayerChatEvent; -use pumpkin::plugin::player::player_command_preprocess::PlayerCommandPreprocessEvent; -use pumpkin::plugin::player::player_command_send::PlayerCommandSendEvent; -use pumpkin::plugin::player::player_drop_item::PlayerDropItemEvent; -use pumpkin::plugin::player::player_edit_book::PlayerEditBookEvent; -use pumpkin::plugin::player::player_egg_throw::PlayerEggThrowEvent; -use pumpkin::plugin::player::player_exp_change::PlayerExpChangeEvent; -use pumpkin::plugin::player::player_fish::PlayerFishEvent; -use pumpkin::plugin::player::player_interact_entity::PlayerInteractEntityEvent; -use pumpkin::plugin::player::player_interact_at_entity::PlayerInteractAtEntityEvent; -use pumpkin::plugin::player::player_item_held::PlayerItemHeldEvent; -use pumpkin::plugin::player::player_item_damage::PlayerItemDamageEvent; -use pumpkin::plugin::player::player_item_break::PlayerItemBreakEvent; -use pumpkin::plugin::player::player_item_consume::PlayerItemConsumeEvent; -use pumpkin::plugin::player::player_item_mend::PlayerItemMendEvent; -use pumpkin::plugin::player::player_level_change::PlayerLevelChangeEvent; -use pumpkin::plugin::player::player_kick::PlayerKickEvent; -use pumpkin::plugin::player::player_toggle_sneak::PlayerToggleSneakEvent; -use pumpkin::plugin::player::player_toggle_sprint::PlayerToggleSprintEvent; -use pumpkin::plugin::player::player_toggle_flight::PlayerToggleFlightEvent; -use pumpkin::plugin::player::player_swap_hand_items::PlayerSwapHandItemsEvent; -use pumpkin::plugin::player::player_resource_pack_status::PlayerResourcePackStatusEvent; -use pumpkin::plugin::player::player_respawn::PlayerRespawnEvent; -use pumpkin::plugin::player::player_pickup_arrow::PlayerPickupArrowEvent; -use pumpkin::plugin::player::player_portal::PlayerPortalEvent; -use pumpkin::plugin::player::player_recipe_discover::PlayerRecipeDiscoverEvent; -use pumpkin::plugin::player::player_riptide::PlayerRiptideEvent; -use pumpkin::plugin::player::player_shear_entity::PlayerShearEntityEvent; -use pumpkin::plugin::player::player_spawn_location::PlayerSpawnLocationEvent; -use pumpkin::plugin::player::player_statistic_increment::PlayerStatisticIncrementEvent; -use pumpkin::plugin::player::player_velocity::PlayerVelocityEvent; -use pumpkin::plugin::player::player_harvest_block::PlayerHarvestBlockEvent; -use pumpkin::plugin::player::player_interact_event::{InteractAction, PlayerInteractEvent}; -use pumpkin::plugin::player::player_join::PlayerJoinEvent; -use pumpkin::plugin::player::player_login::PlayerLoginEvent; -use pumpkin::plugin::player::player_pre_login::PlayerPreLoginEvent; -use pumpkin::plugin::player::player_advancement_done::PlayerAdvancementDoneEvent; -use pumpkin::plugin::player::player_animation::PlayerAnimationEvent; -use pumpkin::plugin::player::player_armor_stand_manipulate::PlayerArmorStandManipulateEvent; -use pumpkin::plugin::player::player_bed_enter::PlayerBedEnterEvent; -use pumpkin::plugin::player::player_bed_leave::PlayerBedLeaveEvent; -use pumpkin::plugin::player::player_bucket_empty::PlayerBucketEmptyEvent; -use pumpkin::plugin::player::player_bucket_fill::PlayerBucketFillEvent; -use pumpkin::plugin::player::player_bucket_entity::PlayerBucketEntityEvent; -use pumpkin::plugin::player::player_changed_main_hand::PlayerChangedMainHandEvent; -use pumpkin::plugin::player::player_register_channel::PlayerRegisterChannelEvent; -use pumpkin::plugin::player::player_unregister_channel::PlayerUnregisterChannelEvent; -use pumpkin::plugin::player::player_leave::PlayerLeaveEvent; -use pumpkin::plugin::player::player_move::PlayerMoveEvent; -use pumpkin::plugin::player::player_teleport::PlayerTeleportEvent; -use pumpkin::plugin::player::player_change_world::PlayerChangeWorldEvent; -use pumpkin::plugin::player::player_gamemode_change::PlayerGamemodeChangeEvent; -use pumpkin::plugin::server::server_broadcast::ServerBroadcastEvent; -use pumpkin::plugin::server::server_command::ServerCommandEvent; -use pumpkin_data::Block; -use pumpkin_data::BlockDirection; -use pumpkin_data::data_component_impl::EquipmentSlot; -use pumpkin_data::item::Item; -use pumpkin_world::item::ItemStack; -use pumpkin_util::math::vector3::Vector3; -use pumpkin_util::text::TextComponent; -use pumpkin_util::Hand; -use tokio::sync::Mutex; - -use crate::events::handler::PatchBukkitEventHandler; -use crate::java::native_callbacks::CALLBACK_CONTEXT; -use crate::proto::patchbukkit::events::event::Data; -use crate::proto::patchbukkit::events::{ - CallEventRequest, CallEventResponse, RegisterEventRequest, -}; - -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, - 3 => EventPriority::High, - _ => EventPriority::Highest, - }; - - log::info!( - "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(); - - tokio::task::block_in_place(|| { - ctx.runtime.block_on(async { - match request.event_type.as_str() { - "org.bukkit.event.player.PlayerJoinEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_join::PlayerJoinEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerLoginEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_login::PlayerLoginEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.AsyncPlayerPreLoginEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_pre_login::PlayerPreLoginEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerQuitEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_leave::PlayerLeaveEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerMoveEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_move::PlayerMoveEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerAdvancementDoneEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_advancement_done::PlayerAdvancementDoneEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_advancement_done::PlayerAdvancementDoneEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerAnimationEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_animation::PlayerAnimationEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_animation::PlayerAnimationEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerArmorStandManipulateEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_armor_stand_manipulate::PlayerArmorStandManipulateEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_armor_stand_manipulate::PlayerArmorStandManipulateEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerBedEnterEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_bed_enter::PlayerBedEnterEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_bed_enter::PlayerBedEnterEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerBedLeaveEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_bed_leave::PlayerBedLeaveEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_bed_leave::PlayerBedLeaveEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerBucketEmptyEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_bucket_empty::PlayerBucketEmptyEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_bucket_empty::PlayerBucketEmptyEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerBucketFillEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_bucket_fill::PlayerBucketFillEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_bucket_fill::PlayerBucketFillEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerBucketEntityEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_bucket_entity::PlayerBucketEntityEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_bucket_entity::PlayerBucketEntityEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerChangedMainHandEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_changed_main_hand::PlayerChangedMainHandEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_changed_main_hand::PlayerChangedMainHandEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerRegisterChannelEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_register_channel::PlayerRegisterChannelEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_register_channel::PlayerRegisterChannelEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerUnregisterChannelEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_unregister_channel::PlayerUnregisterChannelEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_unregister_channel::PlayerUnregisterChannelEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerTeleportEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_teleport::PlayerTeleportEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerChangedWorldEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_change_world::PlayerChangeWorldEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_change_world::PlayerChangeWorldEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerGameModeChangeEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_gamemode_change::PlayerGamemodeChangeEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_gamemode_change::PlayerGamemodeChangeEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.AsyncPlayerChatEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_chat::PlayerChatEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerCommandPreprocessEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_command_preprocess::PlayerCommandPreprocessEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_command_preprocess::PlayerCommandPreprocessEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerCommandSendEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_command_send::PlayerCommandSendEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_command_send::PlayerCommandSendEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerDropItemEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_drop_item::PlayerDropItemEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_drop_item::PlayerDropItemEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerEditBookEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_edit_book::PlayerEditBookEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_edit_book::PlayerEditBookEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerEggThrowEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_egg_throw::PlayerEggThrowEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_egg_throw::PlayerEggThrowEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerExpChangeEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_exp_change::PlayerExpChangeEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_exp_change::PlayerExpChangeEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerFishEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_fish::PlayerFishEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_fish::PlayerFishEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerInteractEntityEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_interact_entity::PlayerInteractEntityEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_interact_entity::PlayerInteractEntityEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerInteractAtEntityEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_interact_at_entity::PlayerInteractAtEntityEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_interact_at_entity::PlayerInteractAtEntityEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerItemHeldEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_item_held::PlayerItemHeldEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_item_held::PlayerItemHeldEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerItemDamageEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_item_damage::PlayerItemDamageEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_item_damage::PlayerItemDamageEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerItemBreakEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_item_break::PlayerItemBreakEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_item_break::PlayerItemBreakEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerItemConsumeEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_item_consume::PlayerItemConsumeEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_item_consume::PlayerItemConsumeEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerItemMendEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_item_mend::PlayerItemMendEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_item_mend::PlayerItemMendEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerLevelChangeEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_level_change::PlayerLevelChangeEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_level_change::PlayerLevelChangeEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerKickEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_kick::PlayerKickEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_kick::PlayerKickEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerToggleSneakEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_toggle_sneak::PlayerToggleSneakEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_toggle_sneak::PlayerToggleSneakEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerToggleSprintEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_toggle_sprint::PlayerToggleSprintEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_toggle_sprint::PlayerToggleSprintEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerToggleFlightEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_toggle_flight::PlayerToggleFlightEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_toggle_flight::PlayerToggleFlightEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerSwapHandItemsEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_swap_hand_items::PlayerSwapHandItemsEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_swap_hand_items::PlayerSwapHandItemsEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerResourcePackStatusEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_resource_pack_status::PlayerResourcePackStatusEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_resource_pack_status::PlayerResourcePackStatusEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerRespawnEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_respawn::PlayerRespawnEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_respawn::PlayerRespawnEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerPickupArrowEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_pickup_arrow::PlayerPickupArrowEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_pickup_arrow::PlayerPickupArrowEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerPortalEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_portal::PlayerPortalEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_portal::PlayerPortalEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerRecipeDiscoverEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_recipe_discover::PlayerRecipeDiscoverEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_recipe_discover::PlayerRecipeDiscoverEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerRiptideEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_riptide::PlayerRiptideEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_riptide::PlayerRiptideEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerShearEntityEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_shear_entity::PlayerShearEntityEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_shear_entity::PlayerShearEntityEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.spigotmc.event.player.PlayerSpawnLocationEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_spawn_location::PlayerSpawnLocationEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_spawn_location::PlayerSpawnLocationEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerStatisticIncrementEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_statistic_increment::PlayerStatisticIncrementEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_statistic_increment::PlayerStatisticIncrementEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerVelocityEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_velocity::PlayerVelocityEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_velocity::PlayerVelocityEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerHarvestBlockEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_harvest_block::PlayerHarvestBlockEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_harvest_block::PlayerHarvestBlockEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.player.PlayerInteractEvent" => { - context - .register_event::< - pumpkin::plugin::player::player_interact_event::PlayerInteractEvent, - PatchBukkitEventHandler< - pumpkin::plugin::player::player_interact_event::PlayerInteractEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockBreakEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_break::BlockBreakEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockDamageEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_damage::BlockDamageEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockDamageAbortEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_damage_abort::BlockDamageAbortEvent, - PatchBukkitEventHandler< - pumpkin::plugin::block::block_damage_abort::BlockDamageAbortEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockDispenseEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_dispense::BlockDispenseEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockDropItemEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_drop_item::BlockDropItemEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockExplodeEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_explode::BlockExplodeEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockFadeEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_fade::BlockFadeEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockFertilizeEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_fertilize::BlockFertilizeEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockFormEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_form::BlockFormEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockFromToEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_from_to::BlockFromToEvent, - PatchBukkitEventHandler< - pumpkin::plugin::block::block_from_to::BlockFromToEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockGrowEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_grow::BlockGrowEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockPistonExtendEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_piston_extend::BlockPistonExtendEvent, - PatchBukkitEventHandler< - pumpkin::plugin::block::block_piston_extend::BlockPistonExtendEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockPistonRetractEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_piston_retract::BlockPistonRetractEvent, - PatchBukkitEventHandler< - pumpkin::plugin::block::block_piston_retract::BlockPistonRetractEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockRedstoneEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_redstone::BlockRedstoneEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockMultiPlaceEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_multi_place::BlockMultiPlaceEvent, - PatchBukkitEventHandler< - pumpkin::plugin::block::block_multi_place::BlockMultiPlaceEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockPhysicsEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_physics::BlockPhysicsEvent, - PatchBukkitEventHandler< - pumpkin::plugin::block::block_physics::BlockPhysicsEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.NotePlayEvent" => { - context - .register_event::< - pumpkin::plugin::block::note_play::NotePlayEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.SignChangeEvent" => { - context - .register_event::< - pumpkin::plugin::block::sign_change::SignChangeEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.TNTPrimeEvent" => { - context - .register_event::< - pumpkin::plugin::block::tnt_prime::TNTPrimeEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.MoistureChangeEvent" => { - context - .register_event::< - pumpkin::plugin::block::moisture_change::MoistureChangeEvent, - PatchBukkitEventHandler< - pumpkin::plugin::block::moisture_change::MoistureChangeEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.SpongeAbsorbEvent" => { - context - .register_event::< - pumpkin::plugin::block::sponge_absorb::SpongeAbsorbEvent, - PatchBukkitEventHandler< - pumpkin::plugin::block::sponge_absorb::SpongeAbsorbEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.FluidLevelChangeEvent" => { - context - .register_event::< - pumpkin::plugin::block::fluid_level_change::FluidLevelChangeEvent, - PatchBukkitEventHandler< - pumpkin::plugin::block::fluid_level_change::FluidLevelChangeEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.world.SpawnChangeEvent" => { - context - .register_event::< - pumpkin::plugin::world::spawn_change::SpawnChangeEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.server.ServerListPingEvent" => { - context - .register_event::< - pumpkin::plugin::server::server_list_ping::ServerListPingEvent, - PatchBukkitEventHandler< - pumpkin::plugin::server::server_list_ping::ServerListPingEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.server.PluginEnableEvent" => { - context - .register_event::< - pumpkin::plugin::server::plugin_enable::PluginEnableEvent, - PatchBukkitEventHandler< - pumpkin::plugin::server::plugin_enable::PluginEnableEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.server.PluginDisableEvent" => { - context - .register_event::< - pumpkin::plugin::server::plugin_disable::PluginDisableEvent, - PatchBukkitEventHandler< - pumpkin::plugin::server::plugin_disable::PluginDisableEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.server.ServiceRegisterEvent" => { - context - .register_event::< - pumpkin::plugin::server::service_register::ServiceRegisterEvent, - PatchBukkitEventHandler< - pumpkin::plugin::server::service_register::ServiceRegisterEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.server.ServiceUnregisterEvent" => { - context - .register_event::< - pumpkin::plugin::server::service_unregister::ServiceUnregisterEvent, - PatchBukkitEventHandler< - pumpkin::plugin::server::service_unregister::ServiceUnregisterEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockCanBuildEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_can_build::BlockCanBuildEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockBurnEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_burn::BlockBurnEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockIgniteEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_ignite::BlockIgniteEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockSpreadEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_spread::BlockSpreadEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.block.BlockPlaceEvent" => { - context - .register_event::< - pumpkin::plugin::block::block_place::BlockPlaceEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.entity.EntitySpawnEvent" => { - context - .register_event::< - pumpkin::plugin::entity::entity_spawn::EntitySpawnEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.entity.EntityDamageEvent" => { - context - .register_event::< - pumpkin::plugin::entity::entity_damage::EntityDamageEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.entity.EntityDeathEvent" => { - context - .register_event::< - pumpkin::plugin::entity::entity_death::EntityDeathEvent, - PatchBukkitEventHandler, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.server.ServerCommandEvent" => { - context - .register_event::< - pumpkin::plugin::server::server_command::ServerCommandEvent, - PatchBukkitEventHandler< - pumpkin::plugin::server::server_command::ServerCommandEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - "org.bukkit.event.server.BroadcastMessageEvent" => { - context - .register_event::< - pumpkin::plugin::server::server_broadcast::ServerBroadcastEvent, - PatchBukkitEventHandler< - pumpkin::plugin::server::server_broadcast::ServerBroadcastEvent, - >, - >( - Arc::new(PatchBukkitEventHandler::new( - request.plugin_name.clone(), - command_tx.clone(), - )), - pumpkin_priority, - request.blocking, - ) - .await; - } - _ => { - log::warn!( - "Unsupported Bukkit event type '{}' from plugin '{}'", - request.event_type, request.plugin_name - ); - } - } - }); - }); - - Some(()) -} - -pub fn ffi_native_bridge_call_event_impl(request: CallEventRequest) -> Option { - let ctx = CALLBACK_CONTEXT.get()?; - let event = request.event?; - log::debug!("Java calling event {:?}", event); - - let context = ctx.plugin_context.clone(); - - let handled = tokio::task::block_in_place(|| { - ctx.runtime.block_on(async { - match event.data? { - Data::PlayerJoin(player_join_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_join_event_data.player_uuid?.value).ok()?; - let 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; - Some(true) - } - Data::PlayerLogin(player_login_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_login_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let pumpkin_event = PlayerLoginEvent::new( - player, - TextComponent::from_legacy_string(&player_login_event_data.kick_message), - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::AsyncPlayerPreLogin(player_pre_login_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_pre_login_event_data.player_uuid?.value).ok()?; - let pumpkin_event = PlayerPreLoginEvent::new( - player_pre_login_event_data.name, - uuid, - player_pre_login_event_data.address, - player_pre_login_event_data.result, - player_pre_login_event_data.kick_message, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerLeave(player_leave_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_leave_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let pumpkin_event = PlayerLeaveEvent::new( - player, - TextComponent::from_legacy_string(&player_leave_event_data.leave_message), - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerMove(player_move_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_move_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let from = player_move_event_data.from?.position?; - let to = player_move_event_data.to?.position?; - let pumpkin_event = PlayerMoveEvent::new( - player, - Vector3::new(from.x, from.y, from.z), - Vector3::new(to.x, to.y, to.z), - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerAdvancementDone(player_advancement_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_advancement_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let pumpkin_event = PlayerAdvancementDoneEvent::new( - player, - player_advancement_event_data.advancement_key, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerAnimation(player_animation_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_animation_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let pumpkin_event = PlayerAnimationEvent::new( - player, - player_animation_event_data.animation_type, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerArmorStandManipulate(player_armor_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_armor_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let armor_uuid = uuid::Uuid::parse_str( - &player_armor_event_data.armor_stand_uuid?.value, - ) - .ok()?; - let pumpkin_event = PlayerArmorStandManipulateEvent::new( - player, - armor_uuid, - player_armor_event_data.item_key, - player_armor_event_data.armor_stand_item_key, - player_armor_event_data.slot, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerBedEnter(player_bed_enter_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_bed_enter_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let position = player_bed_enter_event_data - .bed_location - .and_then(|loc| loc.position) - .map(|pos| Vector3::new(pos.x, pos.y, pos.z)) - .unwrap_or_else(|| player.position()); - let pumpkin_event = PlayerBedEnterEvent::new(player, position); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerBedLeave(player_bed_leave_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_bed_leave_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let position = player_bed_leave_event_data - .bed_location - .and_then(|loc| loc.position) - .map(|pos| Vector3::new(pos.x, pos.y, pos.z)) - .unwrap_or_else(|| player.position()); - let pumpkin_event = PlayerBedLeaveEvent::new(player, position); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerBucketEmpty(player_bucket_empty_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_bucket_empty_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let position = player_bucket_empty_event_data - .location - .and_then(|loc| loc.position) - .map(|pos| Vector3::new(pos.x, pos.y, pos.z)) - .unwrap_or_else(|| player.position()); - let face = bukkit_block_face_to_direction( - &player_bucket_empty_event_data.block_face, - ); - let pumpkin_event = PlayerBucketEmptyEvent::new( - player, - position, - player_bucket_empty_event_data.block_key, - face, - player_bucket_empty_event_data.bucket_item_key, - player_bucket_empty_event_data.hand, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerBucketFill(player_bucket_fill_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_bucket_fill_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let position = player_bucket_fill_event_data - .location - .and_then(|loc| loc.position) - .map(|pos| Vector3::new(pos.x, pos.y, pos.z)) - .unwrap_or_else(|| player.position()); - let face = bukkit_block_face_to_direction( - &player_bucket_fill_event_data.block_face, - ); - let pumpkin_event = PlayerBucketFillEvent::new( - player, - position, - player_bucket_fill_event_data.block_key, - face, - player_bucket_fill_event_data.bucket_item_key, - player_bucket_fill_event_data.hand, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerBucketEntity(player_bucket_entity_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_bucket_entity_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let entity_uuid = - uuid::Uuid::parse_str(&player_bucket_entity_event_data.entity_uuid?.value).ok()?; - let pumpkin_event = PlayerBucketEntityEvent::new( - player, - entity_uuid, - player_bucket_entity_event_data.entity_type, - player_bucket_entity_event_data.original_bucket_key, - player_bucket_entity_event_data.entity_bucket_key, - player_bucket_entity_event_data.hand, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerChangedMainHand(player_changed_main_hand_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_changed_main_hand_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let main_hand = main_hand_from_bukkit( - &player_changed_main_hand_event_data.main_hand, - ) - .unwrap_or(Hand::Right); - let pumpkin_event = PlayerChangedMainHandEvent::new(player, main_hand); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerRegisterChannel(player_register_channel_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_register_channel_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let pumpkin_event = PlayerRegisterChannelEvent::new( - player, - player_register_channel_event_data.channel, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerUnregisterChannel(player_unregister_channel_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_unregister_channel_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let pumpkin_event = PlayerUnregisterChannelEvent::new( - player, - player_unregister_channel_event_data.channel, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerTeleport(player_teleport_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_teleport_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let from = player_teleport_event_data.from?.position?; - let to = player_teleport_event_data.to?.position?; - let pumpkin_event = PlayerTeleportEvent::new( - player, - Vector3::new(from.x, from.y, from.z), - Vector3::new(to.x, to.y, to.z), - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerChangeWorld(player_change_world_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_change_world_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let prev_uuid = uuid::Uuid::parse_str( - &player_change_world_event_data.previous_world?.uuid?.value, - ) - .ok()?; - let new_uuid = uuid::Uuid::parse_str( - &player_change_world_event_data.new_world?.uuid?.value, - ) - .ok()?; - let prev_world = context - .server - .worlds - .load() - .iter() - .find(|world| world.uuid == prev_uuid)? - .clone(); - let new_world = context - .server - .worlds - .load() - .iter() - .find(|world| world.uuid == new_uuid)? - .clone(); - let position = player_change_world_event_data - .position - .and_then(|loc| loc.position) - .map(|pos| Vector3::new(pos.x, pos.y, pos.z)) - .unwrap_or_else(|| player.position()); - let pumpkin_event = PlayerChangeWorldEvent::new( - player, - prev_world, - new_world, - position, - player_change_world_event_data.yaw, - player_change_world_event_data.pitch, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerGamemodeChange(player_gamemode_change_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_gamemode_change_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let prev = gamemode_from_bukkit(&player_gamemode_change_event_data.previous_gamemode) - .unwrap_or(player.gamemode.load()); - let next = gamemode_from_bukkit(&player_gamemode_change_event_data.new_gamemode) - .unwrap_or(player.gamemode.load()); - let pumpkin_event = PlayerGamemodeChangeEvent::new(player, prev, next); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerChat(player_chat_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_chat_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let mut recipients = Vec::new(); - if player_chat_event_data.recipients.is_empty() { - recipients = context.server.get_all_players(); - } else { - for recipient in player_chat_event_data.recipients { - if let Ok(uuid) = uuid::Uuid::parse_str(&recipient.value) { - if let Some(recipient_player) = - context.server.get_player_by_uuid(uuid) - { - recipients.push(recipient_player); - } - } - } - } - - let pumpkin_event = PlayerChatEvent::new( - player, - player_chat_event_data.message, - recipients, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerCommand(player_command_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_command_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let pumpkin_event = - PlayerCommandPreprocessEvent::new(player, player_command_event_data.command); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerCommandSend(player_command_send_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_command_send_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let pumpkin_event = - PlayerCommandSendEvent::new(player, player_command_send_event_data.commands); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerDropItem(player_drop_item_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_drop_item_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let item_uuid = - uuid::Uuid::parse_str(&player_drop_item_event_data.item_uuid?.value).ok()?; - let item_stack = item_stack_from_key( - &player_drop_item_event_data.item_key, - player_drop_item_event_data.item_amount, - ); - let pumpkin_event = - PlayerDropItemEvent::new(player, item_uuid, item_stack); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerEditBook(player_edit_book_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_edit_book_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let title = if player_edit_book_event_data.title.is_empty() { - None - } else { - Some(player_edit_book_event_data.title) - }; - let pumpkin_event = PlayerEditBookEvent::new( - player, - player_edit_book_event_data.slot, - player_edit_book_event_data.pages, - title, - player_edit_book_event_data.is_signing, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerEggThrow(player_egg_throw_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_egg_throw_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let egg_uuid = - uuid::Uuid::parse_str(&player_egg_throw_event_data.egg_uuid?.value).ok()?; - let pumpkin_event = PlayerEggThrowEvent::new( - player, - egg_uuid, - player_egg_throw_event_data.hatching, - player_egg_throw_event_data.num_hatches.min(u8::MAX as i32) as u8, - player_egg_throw_event_data.hatching_type, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerExpChange(player_exp_change_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_exp_change_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let pumpkin_event = - PlayerExpChangeEvent::new(player, player_exp_change_event_data.amount); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerFish(player_fish_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_fish_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let caught_uuid = player_fish_event_data - .caught_uuid - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()); - let hook_uuid = - uuid::Uuid::parse_str(&player_fish_event_data.hook_uuid?.value).ok()?; - let pumpkin_event = PlayerFishEvent::new( - player, - caught_uuid, - hook_uuid, - player_fish_event_data.caught_type, - player_fish_event_data.state, - player_fish_event_data.hand, - player_fish_event_data.exp_to_drop, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerInteractEntity(player_interact_entity_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_interact_entity_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let entity_uuid = - uuid::Uuid::parse_str(&player_interact_entity_event_data.entity_uuid?.value).ok()?; - let pumpkin_event = PlayerInteractEntityEvent::new( - player, - entity_uuid, - player_interact_entity_event_data.entity_type, - player_interact_entity_event_data.hand, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerInteractAtEntity(player_interact_at_entity_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_interact_at_entity_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let entity_uuid = - uuid::Uuid::parse_str(&player_interact_at_entity_event_data.entity_uuid?.value).ok()?; - let position = player_interact_at_entity_event_data - .clicked_position - .map(|pos| Vector3::new(pos.x as f32, pos.y as f32, pos.z as f32)) - .unwrap_or_else(|| Vector3::new(0.0, 0.0, 0.0)); - let pumpkin_event = PlayerInteractAtEntityEvent::new( - player, - entity_uuid, - player_interact_at_entity_event_data.entity_type, - player_interact_at_entity_event_data.hand, - position, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerItemHeld(player_item_held_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_item_held_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let pumpkin_event = PlayerItemHeldEvent::new( - player, - player_item_held_event_data.previous_slot, - player_item_held_event_data.new_slot, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerItemDamage(player_item_damage_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_item_damage_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let key = if player_item_damage_event_data.item_key.is_empty() { - "minecraft:air" - } else { - player_item_damage_event_data.item_key.as_str() - }; - let item = item_stack_from_key(key, player_item_damage_event_data.item_amount); - let pumpkin_event = PlayerItemDamageEvent::new( - player, - item, - player_item_damage_event_data.damage, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerItemBreak(player_item_break_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_item_break_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let key = if player_item_break_event_data.item_key.is_empty() { - "minecraft:air" - } else { - player_item_break_event_data.item_key.as_str() - }; - let item = item_stack_from_key(key, player_item_break_event_data.item_amount); - let pumpkin_event = PlayerItemBreakEvent::new(player, item); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerItemConsume(player_item_consume_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_item_consume_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let key = if player_item_consume_event_data.item_key.is_empty() { - "minecraft:air" - } else { - player_item_consume_event_data.item_key.as_str() - }; - let item = item_stack_from_key(key, player_item_consume_event_data.item_amount); - let hand = if player_item_consume_event_data.hand == "OFF_HAND" { - Hand::Left - } else { - Hand::Right - }; - let pumpkin_event = PlayerItemConsumeEvent::new(player, item, hand); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerItemMend(player_item_mend_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_item_mend_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let key = if player_item_mend_event_data.item_key.is_empty() { - "minecraft:air" - } else { - player_item_mend_event_data.item_key.as_str() - }; - let item = item_stack_from_key(key, player_item_mend_event_data.item_amount); - let slot = equipment_slot_from_bukkit(&player_item_mend_event_data.slot) - .unwrap_or(EquipmentSlot::MAIN_HAND); - let orb_uuid = player_item_mend_event_data - .orb_uuid - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()); - let pumpkin_event = PlayerItemMendEvent::new( - player, - item, - slot, - player_item_mend_event_data.repair_amount, - orb_uuid, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerLevelChange(player_level_change_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_level_change_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let pumpkin_event = PlayerLevelChangeEvent::new( - player, - player_level_change_event_data.old_level, - player_level_change_event_data.new_level, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerKick(player_kick_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_kick_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let reason = serde_json::from_str(&player_kick_event_data.reason) - .unwrap_or_else(|_| TextComponent::text(&player_kick_event_data.reason)); - let leave_message = serde_json::from_str(&player_kick_event_data.leave_message) - .unwrap_or_else(|_| TextComponent::text(&player_kick_event_data.leave_message)); - let cause = if player_kick_event_data.cause.is_empty() { - "UNKNOWN".to_string() - } else { - player_kick_event_data.cause - }; - let pumpkin_event = - PlayerKickEvent::new(player, reason, leave_message, cause); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerToggleSneak(player_toggle_sneak_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_toggle_sneak_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let pumpkin_event = PlayerToggleSneakEvent::new( - player, - player_toggle_sneak_event_data.is_sneaking, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerToggleSprint(player_toggle_sprint_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_toggle_sprint_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let pumpkin_event = PlayerToggleSprintEvent::new( - player, - player_toggle_sprint_event_data.is_sprinting, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerToggleFlight(player_toggle_flight_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_toggle_flight_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let pumpkin_event = PlayerToggleFlightEvent::new( - player, - player_toggle_flight_event_data.is_flying, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerSwapHandItems(player_swap_hand_items_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_swap_hand_items_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let main_key = if player_swap_hand_items_event_data.main_hand_item_key.is_empty() { - "minecraft:air" - } else { - player_swap_hand_items_event_data.main_hand_item_key.as_str() - }; - let off_key = if player_swap_hand_items_event_data.off_hand_item_key.is_empty() { - "minecraft:air" - } else { - player_swap_hand_items_event_data.off_hand_item_key.as_str() - }; - let main_item = item_stack_from_key( - main_key, - player_swap_hand_items_event_data.main_hand_item_amount, - ); - let off_item = item_stack_from_key( - off_key, - player_swap_hand_items_event_data.off_hand_item_amount, - ); - let pumpkin_event = PlayerSwapHandItemsEvent::new(player, main_item, off_item); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerResourcePackStatus(player_resource_pack_status_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_resource_pack_status_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let pack_uuid = player_resource_pack_status_event_data - .pack_uuid - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) - .unwrap_or_else(uuid::Uuid::new_v4); - let pumpkin_event = PlayerResourcePackStatusEvent::new( - player, - pack_uuid, - player_resource_pack_status_event_data.hash, - player_resource_pack_status_event_data.status, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerRespawn(player_respawn_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_respawn_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let (world_uuid, pos) = if let Some(loc) = player_respawn_event_data.respawn_location { - let world_uuid = loc - .world - .and_then(|w| w.uuid) - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) - .unwrap_or_else(|| player.world().uuid); - let pos = location_to_vec3(loc).unwrap_or_else(|| player.position()); - (world_uuid, pos) - } else { - (player.world().uuid, player.position()) - }; - let pumpkin_event = PlayerRespawnEvent::new( - player, - pos, - world_uuid, - player_respawn_event_data.is_bed_spawn, - player_respawn_event_data.is_anchor_spawn, - player_respawn_event_data.is_missing_respawn_block, - player_respawn_event_data.respawn_reason, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerPickupArrow(player_pickup_arrow_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_pickup_arrow_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let arrow_uuid = player_pickup_arrow_event_data - .arrow_uuid - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) - .unwrap_or_else(uuid::Uuid::new_v4); - let item_uuid = player_pickup_arrow_event_data - .item_uuid - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) - .unwrap_or_else(uuid::Uuid::new_v4); - let key = if player_pickup_arrow_event_data.item_key.is_empty() { - "minecraft:air" - } else { - player_pickup_arrow_event_data.item_key.as_str() - }; - let item = item_stack_from_key(key, player_pickup_arrow_event_data.item_amount); - let pumpkin_event = PlayerPickupArrowEvent::new( - player, - arrow_uuid, - item_uuid, - item, - player_pickup_arrow_event_data.remaining, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerPortal(player_portal_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_portal_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let (from_world_uuid, from_pos) = if let Some(loc) = player_portal_event_data.from { - let world_uuid = loc - .world - .and_then(|w| w.uuid) - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) - .unwrap_or_else(|| player.world().uuid); - let pos = location_to_vec3(loc).unwrap_or_else(|| player.position()); - (world_uuid, pos) - } else { - (player.world().uuid, player.position()) - }; - let (to_world_uuid, to_pos) = if let Some(loc) = player_portal_event_data.to { - let world_uuid = loc - .world - .and_then(|w| w.uuid) - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) - .unwrap_or_else(|| player.world().uuid); - let pos = location_to_vec3(loc).unwrap_or_else(|| player.position()); - (world_uuid, pos) - } else { - (player.world().uuid, player.position()) - }; - let cause = if player_portal_event_data.cause.is_empty() { - "UNKNOWN".to_string() - } else { - player_portal_event_data.cause - }; - let pumpkin_event = PlayerPortalEvent::new( - player, - from_pos, - from_world_uuid, - to_pos, - to_world_uuid, - cause, - player_portal_event_data.search_radius, - player_portal_event_data.can_create_portal, - player_portal_event_data.creation_radius, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerRecipeDiscover(player_recipe_discover_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_recipe_discover_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let pumpkin_event = PlayerRecipeDiscoverEvent::new( - player, - player_recipe_discover_event_data.recipe_key, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerRiptide(player_riptide_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_riptide_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let key = if player_riptide_event_data.item_key.is_empty() { - "minecraft:air" - } else { - player_riptide_event_data.item_key.as_str() - }; - let item = item_stack_from_key(key, player_riptide_event_data.item_amount); - let velocity = player_riptide_event_data - .velocity - .map(|v| Vector3::new(v.x, v.y, v.z)) - .unwrap_or_else(Vector3::default); - let pumpkin_event = PlayerRiptideEvent::new(player, item, velocity); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerShearEntity(player_shear_entity_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_shear_entity_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let entity_uuid = player_shear_entity_event_data - .entity_uuid - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) - .unwrap_or_else(uuid::Uuid::new_v4); - let key = if player_shear_entity_event_data.item_key.is_empty() { - "minecraft:air" - } else { - player_shear_entity_event_data.item_key.as_str() - }; - let item = item_stack_from_key(key, player_shear_entity_event_data.item_amount); - let hand = if player_shear_entity_event_data.hand.is_empty() { - "HAND".to_string() - } else { - player_shear_entity_event_data.hand - }; - let entity_type = player_shear_entity_event_data.entity_type; - let pumpkin_event = PlayerShearEntityEvent::new( - player, - entity_uuid, - entity_type, - item, - hand, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerSpawnLocation(player_spawn_location_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_spawn_location_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let (world_uuid, pos) = if let Some(loc) = player_spawn_location_event_data.spawn_location { - let world_uuid = loc - .world - .and_then(|w| w.uuid) - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) - .unwrap_or_else(|| player.world().uuid); - let pos = location_to_vec3(loc).unwrap_or_else(|| player.position()); - (world_uuid, pos) - } else { - (player.world().uuid, player.position()) - }; - let pumpkin_event = PlayerSpawnLocationEvent::new(player, pos, world_uuid); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerStatisticIncrement(player_statistic_increment_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_statistic_increment_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let pumpkin_event = PlayerStatisticIncrementEvent::new( - player, - player_statistic_increment_event_data.statistic, - player_statistic_increment_event_data.initial_value, - player_statistic_increment_event_data.new_value, - player_statistic_increment_event_data.entity_type, - player_statistic_increment_event_data.material_key, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerVelocity(player_velocity_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_velocity_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let velocity = player_velocity_event_data - .velocity - .map(|v| Vector3::new(v.x, v.y, v.z)) - .unwrap_or_else(Vector3::default); - let pumpkin_event = PlayerVelocityEvent::new(player, velocity); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerHarvestBlock(player_harvest_block_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_harvest_block_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let (world_uuid, pos) = - if let Some(loc) = player_harvest_block_event_data.block_location { - let world_uuid = loc - .world - .and_then(|w| w.uuid) - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) - .unwrap_or_else(|| player.world().uuid); - let pos = location_to_vec3(loc).unwrap_or_else(|| player.position()); - (world_uuid, pos) - } else { - (player.world().uuid, player.position()) - }; - let block_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - let key = if player_harvest_block_event_data.item_key.is_empty() { - "minecraft:air" - } else { - player_harvest_block_event_data.item_key.as_str() - }; - let item = item_stack_from_key( - key, - player_harvest_block_event_data.item_amount, - ); - let block_key = if player_harvest_block_event_data.block_key.is_empty() { - "minecraft:air".to_string() - } else { - player_harvest_block_event_data.block_key - }; - let pumpkin_event = PlayerHarvestBlockEvent::new( - player, - block_pos, - block_key, - item, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::PlayerInteract(player_interact_event_data) => { - let uuid = - uuid::Uuid::parse_str(&player_interact_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let action = match player_interact_event_data.action.as_str() { - "LEFT_CLICK_BLOCK" => InteractAction::LeftClickBlock, - "LEFT_CLICK_AIR" => InteractAction::LeftClickAir, - "RIGHT_CLICK_BLOCK" => InteractAction::RightClickBlock, - "RIGHT_CLICK_AIR" => InteractAction::RightClickAir, - _ => InteractAction::RightClickAir, - }; - - let clicked_pos = player_interact_event_data - .clicked - .and_then(|loc| loc.position) - .map(|pos| { - pumpkin_util::math::position::BlockPos::new( - pos.x as i32, - pos.y as i32, - pos.z as i32, - ) - }); - - let block = block_from_key(&player_interact_event_data.block_key); - let item = Arc::new(Mutex::new(item_from_key( - &player_interact_event_data.item_key, - ))); - let face = bukkit_block_face_to_direction( - &player_interact_event_data.block_face, - ); - - let pumpkin_event = PlayerInteractEvent::new( - &player, - action, - &item, - player_interact_event_data.item_key, - block, - clicked_pos, - face, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::BlockBreak(block_break_event_data) => { - let uuid = uuid::Uuid::parse_str(&block_break_event_data.player_uuid?.value) - .ok()?; - let player = context.server.get_player_by_uuid(uuid); - let block = block_from_key(&block_break_event_data.block_key); - let position = block_break_event_data - .location - .and_then(|loc| loc.position) - .map(|pos| { - pumpkin_util::math::position::BlockPos::new( - pos.x as i32, - pos.y as i32, - pos.z as i32, - ) - }) - .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); - - let pumpkin_event = BlockBreakEvent::new( - player, - block, - position, - block_break_event_data.exp, - block_break_event_data.drop, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::BlockDamage(block_damage_event_data) => { - let uuid = uuid::Uuid::parse_str(&block_damage_event_data.player_uuid?.value) - .ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let block = block_from_key(&block_damage_event_data.block_key); - let position = block_damage_event_data - .location - .and_then(|loc| loc.position) - .map(|pos| { - pumpkin_util::math::position::BlockPos::new( - pos.x as i32, - pos.y as i32, - pos.z as i32, - ) - }) - .unwrap_or_else(|| player.position().to_block_pos()); - let key = if block_damage_event_data.item_key.is_empty() { - "minecraft:air" - } else { - block_damage_event_data.item_key.as_str() - }; - let item_stack = item_stack_from_key(key, 1); - let pumpkin_event = BlockDamageEvent::new( - player, - block, - position, - item_stack, - block_damage_event_data.insta_break, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::BlockDamageAbort(block_damage_abort_event_data) => { - let uuid = uuid::Uuid::parse_str(&block_damage_abort_event_data.player_uuid?.value) - .ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let block = block_from_key(&block_damage_abort_event_data.block_key); - let position = block_damage_abort_event_data - .location - .and_then(|loc| loc.position) - .map(|pos| { - pumpkin_util::math::position::BlockPos::new( - pos.x as i32, - pos.y as i32, - pos.z as i32, - ) - }) - .unwrap_or_else(|| player.position().to_block_pos()); - let key = if block_damage_abort_event_data.item_key.is_empty() { - "minecraft:air" - } else { - block_damage_abort_event_data.item_key.as_str() - }; - let item_stack = item_stack_from_key(key, 1); - let pumpkin_event = - BlockDamageAbortEvent::new(player, block, position, item_stack); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::BlockDispense(block_dispense_event_data) => { - let block = block_from_key(&block_dispense_event_data.block_key); - let position = block_dispense_event_data - .location - .and_then(|loc| loc.position) - .map(|pos| { - pumpkin_util::math::position::BlockPos::new( - pos.x as i32, - pos.y as i32, - pos.z as i32, - ) - }) - .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); - let key = if block_dispense_event_data.item_key.is_empty() { - "minecraft:air" - } else { - block_dispense_event_data.item_key.as_str() - }; - let item_stack = - item_stack_from_key(key, block_dispense_event_data.item_amount); - let velocity = block_dispense_event_data - .velocity - .map(|v| Vector3::new(v.x, v.y, v.z)) - .unwrap_or_else(|| Vector3::new(0.0, 0.0, 0.0)); - let pumpkin_event = - BlockDispenseEvent::new(block, position, item_stack, velocity); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::BlockDropItem(block_drop_item_event_data) => { - let uuid = uuid::Uuid::parse_str(&block_drop_item_event_data.player_uuid?.value) - .ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let block = block_from_key(&block_drop_item_event_data.block_key); - let position = block_drop_item_event_data - .location - .and_then(|loc| loc.position) - .map(|pos| { - pumpkin_util::math::position::BlockPos::new( - pos.x as i32, - pos.y as i32, - pos.z as i32, - ) - }) - .unwrap_or_else(|| player.position().to_block_pos()); - let mut items = Vec::new(); - for entry in block_drop_item_event_data.items { - if entry.item_key.is_empty() && entry.item_amount <= 0 { - continue; - } - let key = if entry.item_key.is_empty() { - "minecraft:air" - } else { - entry.item_key.as_str() - }; - let stack = item_stack_from_key(key, entry.item_amount); - if !stack.is_empty() { - items.push(stack); - } - } - let pumpkin_event = BlockDropItemEvent::new(player, block, position, items); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::BlockExplode(block_explode_event_data) => { - let block = block_from_key(&block_explode_event_data.block_key); - let position = block_explode_event_data - .location - .and_then(|loc| loc.position) - .map(|pos| { - pumpkin_util::math::position::BlockPos::new( - pos.x as i32, - pos.y as i32, - pos.z as i32, - ) - }) - .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); - let world_uuid = block_explode_event_data - .location - .and_then(|loc| loc.world) - .and_then(|w| w.uuid) - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) - .unwrap_or_else(|| { - context - .server - .worlds - .load() - .first() - .map(|world| world.uuid) - .unwrap_or_default() - }); - let mut blocks = Vec::new(); - for entry in block_explode_event_data.blocks { - if let Some(loc) = entry.location - && let Some(pos) = location_to_vec3(loc.clone()) - { - blocks.push(pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - )); - } - } - let pumpkin_event = BlockExplodeEvent::new( - block, - position, - world_uuid, - blocks, - block_explode_event_data.yield_, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::BlockFade(block_fade_event_data) => { - let block = block_from_key(&block_fade_event_data.block_key); - let new_block = block_from_key(&block_fade_event_data.new_block_key); - let position = block_fade_event_data - .location - .and_then(|loc| loc.position) - .map(|pos| { - pumpkin_util::math::position::BlockPos::new( - pos.x as i32, - pos.y as i32, - pos.z as i32, - ) - }) - .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); - let world_uuid = block_fade_event_data - .location - .and_then(|loc| loc.world) - .and_then(|w| w.uuid) - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) - .unwrap_or_else(|| { - context - .server - .worlds - .load() - .first() - .map(|world| world.uuid) - .unwrap_or_default() - }); - let pumpkin_event = BlockFadeEvent::new(block, new_block, position, world_uuid); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::BlockFertilize(block_fertilize_event_data) => { - let uuid = uuid::Uuid::parse_str(&block_fertilize_event_data.player_uuid?.value) - .ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let block = block_from_key(&block_fertilize_event_data.block_key); - let position = block_fertilize_event_data - .location - .and_then(|loc| loc.position) - .map(|pos| { - pumpkin_util::math::position::BlockPos::new( - pos.x as i32, - pos.y as i32, - pos.z as i32, - ) - }) - .unwrap_or_else(|| player.position().to_block_pos()); - let mut blocks = Vec::new(); - for entry in block_fertilize_event_data.blocks { - if let Some(loc) = entry.location - && let Some(pos) = location_to_vec3(loc.clone()) - { - blocks.push(pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - )); - } - } - let pumpkin_event = - BlockFertilizeEvent::new(player, block, position, blocks); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::BlockForm(block_form_event_data) => { - let old_block = block_from_key(&block_form_event_data.block_key); - let new_block = block_from_key(&block_form_event_data.new_block_key); - let position = block_form_event_data - .location - .and_then(|loc| loc.position) - .map(|pos| { - pumpkin_util::math::position::BlockPos::new( - pos.x as i32, - pos.y as i32, - pos.z as i32, - ) - }) - .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); - let world_uuid = block_form_event_data - .location - .and_then(|loc| loc.world) - .and_then(|w| w.uuid) - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) - .unwrap_or_else(|| { - context - .server - .worlds - .load() - .first() - .map(|world| world.uuid) - .unwrap_or_default() - }); - let pumpkin_event = BlockFormEvent::new(old_block, new_block, position, world_uuid); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::BlockFromTo(block_from_to_event_data) => { - let block = block_from_key(&block_from_to_event_data.block_key); - let to_block = block_from_key(&block_from_to_event_data.to_block_key); - let position = block_from_to_event_data - .location - .and_then(|loc| loc.position) - .map(|pos| { - pumpkin_util::math::position::BlockPos::new( - pos.x as i32, - pos.y as i32, - pos.z as i32, - ) - }) - .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); - let to_position = block_from_to_event_data - .to_location - .and_then(|loc| loc.position) - .map(|pos| { - pumpkin_util::math::position::BlockPos::new( - pos.x as i32, - pos.y as i32, - pos.z as i32, - ) - }) - .unwrap_or_else(|| position); - let world_uuid = block_from_to_event_data - .location - .and_then(|loc| loc.world) - .and_then(|w| w.uuid) - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) - .unwrap_or_else(|| { - context - .server - .worlds - .load() - .first() - .map(|world| world.uuid) - .unwrap_or_default() - }); - let face = - bukkit_block_face_to_direction(&block_from_to_event_data.face).unwrap_or( - BlockDirection::Down, - ); - let pumpkin_event = BlockFromToEvent::new( - block, - position, - to_block, - to_position, - face, - world_uuid, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::BlockGrow(block_grow_event_data) => { - let block = block_from_key(&block_grow_event_data.block_key); - let new_block = block_from_key(&block_grow_event_data.new_block_key); - let position = block_grow_event_data - .location - .and_then(|loc| loc.position) - .map(|pos| { - pumpkin_util::math::position::BlockPos::new( - pos.x as i32, - pos.y as i32, - pos.z as i32, - ) - }) - .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); - let world_uuid = block_grow_event_data - .location - .and_then(|loc| loc.world) - .and_then(|w| w.uuid) - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) - .unwrap_or_else(|| { - context - .server - .worlds - .load() - .first() - .map(|world| world.uuid) - .unwrap_or_default() - }); - let pumpkin_event = BlockGrowEvent::new(block, new_block, position, world_uuid); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::BlockPistonExtend(block_piston_extend_event_data) => { - let block = block_from_key(&block_piston_extend_event_data.block_key); - let position = block_piston_extend_event_data - .location - .and_then(|loc| loc.position) - .map(|pos| { - pumpkin_util::math::position::BlockPos::new( - pos.x as i32, - pos.y as i32, - pos.z as i32, - ) - }) - .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); - let world_uuid = block_piston_extend_event_data - .location - .and_then(|loc| loc.world) - .and_then(|w| w.uuid) - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) - .unwrap_or_else(|| { - context - .server - .worlds - .load() - .first() - .map(|world| world.uuid) - .unwrap_or_default() - }); - let face = - bukkit_block_face_to_direction(&block_piston_extend_event_data.direction) - .unwrap_or(BlockDirection::Down); - let mut blocks = Vec::new(); - for entry in block_piston_extend_event_data.blocks { - if let Some(loc) = entry.location - && let Some(pos) = location_to_vec3(loc.clone()) - { - blocks.push(pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - )); - } - } - let pumpkin_event = BlockPistonExtendEvent::new( - block, - position, - face, - block_piston_extend_event_data.length, - blocks, - world_uuid, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::BlockPistonRetract(block_piston_retract_event_data) => { - let block = block_from_key(&block_piston_retract_event_data.block_key); - let position = block_piston_retract_event_data - .location - .and_then(|loc| loc.position) - .map(|pos| { - pumpkin_util::math::position::BlockPos::new( - pos.x as i32, - pos.y as i32, - pos.z as i32, - ) - }) - .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); - let world_uuid = block_piston_retract_event_data - .location - .and_then(|loc| loc.world) - .and_then(|w| w.uuid) - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) - .unwrap_or_else(|| { - context - .server - .worlds - .load() - .first() - .map(|world| world.uuid) - .unwrap_or_default() - }); - let face = - bukkit_block_face_to_direction(&block_piston_retract_event_data.direction) - .unwrap_or(BlockDirection::Down); - let mut blocks = Vec::new(); - for entry in block_piston_retract_event_data.blocks { - if let Some(loc) = entry.location - && let Some(pos) = location_to_vec3(loc.clone()) - { - blocks.push(pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - )); - } - } - let pumpkin_event = BlockPistonRetractEvent::new( - block, - position, - face, - block_piston_retract_event_data.length, - blocks, - world_uuid, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::BlockRedstone(block_redstone_event_data) => { - let block = block_from_key(&block_redstone_event_data.block_key); - let position = block_redstone_event_data - .location - .and_then(|loc| loc.position) - .map(|pos| { - pumpkin_util::math::position::BlockPos::new( - pos.x as i32, - pos.y as i32, - pos.z as i32, - ) - }) - .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); - let pumpkin_event = BlockRedstoneEvent::new( - block, - position, - block_redstone_event_data.old_current, - block_redstone_event_data.new_current, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::BlockMultiPlace(block_multi_place_event_data) => { - let uuid = uuid::Uuid::parse_str(&block_multi_place_event_data.player_uuid?.value) - .ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let block = block_from_key(&block_multi_place_event_data.block_key); - let mut positions = Vec::new(); - for entry in block_multi_place_event_data.blocks { - if let Some(loc) = entry.location - && let Some(pos) = location_to_vec3(loc.clone()) - { - positions.push(pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - )); - } - } - let pumpkin_event = - BlockMultiPlaceEvent::new(player, block, positions); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::BlockPhysics(block_physics_event_data) => { - let block = block_from_key(&block_physics_event_data.block_key); - let source_block = block_from_key(&block_physics_event_data.source_block_key); - let position = block_physics_event_data - .location - .and_then(|loc| loc.position) - .map(|pos| { - pumpkin_util::math::position::BlockPos::new( - pos.x as i32, - pos.y as i32, - pos.z as i32, - ) - }) - .unwrap_or_else(|| pumpkin_util::math::position::BlockPos::new(0, 0, 0)); - let source_pos = block_physics_event_data - .source_location - .and_then(|loc| loc.position) - .map(|pos| { - pumpkin_util::math::position::BlockPos::new( - pos.x as i32, - pos.y as i32, - pos.z as i32, - ) - }) - .unwrap_or_else(|| position); - let world_uuid = block_physics_event_data - .location - .and_then(|loc| loc.world) - .and_then(|w| w.uuid) - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) - .unwrap_or_else(|| { - context - .server - .worlds - .load() - .first() - .map(|world| world.uuid) - .unwrap_or_default() - }); - let pumpkin_event = BlockPhysicsEvent::new( - block, - position, - source_block, - source_pos, - world_uuid, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::BlockPlace(block_place_event_data) => { - let uuid = uuid::Uuid::parse_str(&block_place_event_data.player_uuid?.value) - .ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let block = block_from_key(&block_place_event_data.block_key); - let against = block_from_key(&block_place_event_data.block_against_key); - let position = block_place_event_data - .location - .and_then(|loc| loc.position) - .map(|pos| { - pumpkin_util::math::position::BlockPos::new( - pos.x as i32, - pos.y as i32, - pos.z as i32, - ) - }) - .unwrap_or_else(|| player.position().to_block_pos()); - - let pumpkin_event = BlockPlaceEvent { - player, - block_placed: block, - block_placed_against: against, - position, - can_build: block_place_event_data.can_build, - cancelled: false, - }; - - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::BlockCanBuild(block_can_build_event_data) => { - let uuid = - uuid::Uuid::parse_str(&block_can_build_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let block_to_build = block_from_key(&block_can_build_event_data.block_key); - let block_against = block_from_key(&block_can_build_event_data.block_against_key); - let position = block_can_build_event_data - .location - .and_then(|loc| loc.position) - .map(|pos| { - pumpkin_util::math::position::BlockPos::new( - pos.x as i32, - pos.y as i32, - pos.z as i32, - ) - }) - .unwrap_or_else(|| player.position().to_block_pos()); - let pumpkin_event = BlockCanBuildEvent { - player, - block_to_build, - buildable: block_can_build_event_data.can_build, - block: block_against, - block_pos: position, - cancelled: false, - }; - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::BlockBurn(block_burn_event_data) => { - let block = block_from_key(&block_burn_event_data.block_key); - let igniting_block = - block_from_key(&block_burn_event_data.igniting_block_key); - let (world_uuid, pos) = if let Some(loc) = block_burn_event_data.location { - let world_uuid = loc - .world - .and_then(|w| w.uuid) - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) - .unwrap_or_else(|| { - context - .server - .worlds - .load() - .first() - .map(|w| w.uuid) - .unwrap_or_else(uuid::Uuid::new_v4) - }); - let pos = location_to_vec3(loc).unwrap_or_else(Vector3::default); - (world_uuid, pos) - } else { - ( - context - .server - .worlds - .load() - .first() - .map(|w| w.uuid) - .unwrap_or_else(uuid::Uuid::new_v4), - Vector3::default(), - ) - }; - let block_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - let pumpkin_event = BlockBurnEvent { - igniting_block, - block, - block_pos, - world_uuid, - cancelled: false, - }; - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::BlockIgnite(block_ignite_event_data) => { - let uuid = - uuid::Uuid::parse_str(&block_ignite_event_data.player_uuid?.value).ok()?; - let player = context.server.get_player_by_uuid(uuid)?; - let block = block_from_key(&block_ignite_event_data.block_key); - let igniting_block = - block_from_key(&block_ignite_event_data.igniting_block_key); - let (world_uuid, pos) = if let Some(loc) = block_ignite_event_data.location { - let world_uuid = loc - .world - .and_then(|w| w.uuid) - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) - .unwrap_or_else(|| player.world().uuid); - let pos = location_to_vec3(loc).unwrap_or_else(Vector3::default); - (world_uuid, pos) - } else { - (player.world().uuid, Vector3::default()) - }; - let block_pos = pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ); - let cause = if block_ignite_event_data.cause.is_empty() { - "UNKNOWN".to_string() - } else { - block_ignite_event_data.cause - }; - let pumpkin_event = BlockIgniteEvent { - player, - block, - igniting_block, - block_pos, - world_uuid, - cause, - cancelled: false, - }; - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::BlockSpread(block_spread_event_data) => { - let source_block = block_from_key(&block_spread_event_data.source_block_key); - let block = block_from_key(&block_spread_event_data.block_key); - let (world_uuid, source_pos) = - if let Some(loc) = block_spread_event_data.source_location { - let world_uuid = loc - .world - .and_then(|w| w.uuid) - .and_then(|uuid| uuid::Uuid::parse_str(&uuid.value).ok()) - .unwrap_or_else(|| { - context - .server - .worlds - .load() - .first() - .map(|w| w.uuid) - .unwrap_or_else(uuid::Uuid::new_v4) - }); - let pos = location_to_vec3(loc).unwrap_or_else(Vector3::default); - ( - world_uuid, - pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ), - ) - } else { - ( - context - .server - .worlds - .load() - .first() - .map(|w| w.uuid) - .unwrap_or_else(uuid::Uuid::new_v4), - pumpkin_util::math::position::BlockPos::new(0, 0, 0), - ) - }; - let block_pos = if let Some(loc) = block_spread_event_data.location { - let pos = location_to_vec3(loc).unwrap_or_else(Vector3::default); - pumpkin_util::math::position::BlockPos::new( - pos.x.floor() as i32, - pos.y.floor() as i32, - pos.z.floor() as i32, - ) - } else { - source_pos - }; - let pumpkin_event = BlockSpreadEvent { - source_block, - source_pos, - block, - block_pos, - world_uuid, - cancelled: false, - }; - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::EntitySpawn(entity_spawn_event_data) => { - let uuid = uuid::Uuid::parse_str(&entity_spawn_event_data.entity_uuid?.value) - .ok()?; - let pumpkin_event = - pumpkin::plugin::entity::entity_spawn::EntitySpawnEvent::new( - uuid, - &pumpkin_data::entity::EntityType::PLAYER, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::EntityDamage(entity_damage_event_data) => { - let uuid = uuid::Uuid::parse_str(&entity_damage_event_data.entity_uuid?.value) - .ok()?; - let pumpkin_event = - pumpkin::plugin::entity::entity_damage::EntityDamageEvent::new( - uuid, - entity_damage_event_data.damage, - pumpkin_data::damage::DamageType::GENERIC, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::EntityDeath(entity_death_event_data) => { - let uuid = uuid::Uuid::parse_str(&entity_death_event_data.entity_uuid?.value) - .ok()?; - let pumpkin_event = - pumpkin::plugin::entity::entity_death::EntityDeathEvent::new( - uuid, - pumpkin_data::damage::DamageType::GENERIC, - ); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::ServerCommand(server_command_event_data) => { - let pumpkin_event = - ServerCommandEvent::new(server_command_event_data.command); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - Data::ServerBroadcast(server_broadcast_event_data) => { - let message = serde_json::from_str(&server_broadcast_event_data.message) - .unwrap_or_else(|_| { - TextComponent::from_legacy_string(&server_broadcast_event_data.message) - }); - let sender = serde_json::from_str(&server_broadcast_event_data.sender) - .unwrap_or_else(|_| { - TextComponent::from_legacy_string(&server_broadcast_event_data.sender) - }); - let pumpkin_event = ServerBroadcastEvent::new(message, sender); - context.server.plugin_manager.fire(pumpkin_event).await; - Some(true) - } - } - }) - })?; - - Some(CallEventResponse { handled }) -} - -fn block_from_key(key: &str) -> &'static Block { - let trimmed = key.strip_prefix("minecraft:").unwrap_or(key); - Block::from_registry_key(trimmed).unwrap_or(&Block::AIR) -} - -fn item_from_key(key: &str) -> ItemStack { - let trimmed = key.strip_prefix("minecraft:").unwrap_or(key); - let item = Item::from_registry_key(trimmed).unwrap_or(&Item::AIR); - ItemStack::new(1, item) -} - -fn item_stack_from_key(key: &str, amount: i32) -> ItemStack { - let trimmed = key.strip_prefix("minecraft:").unwrap_or(key); - let item = Item::from_registry_key(trimmed).unwrap_or(&Item::AIR); - let count = amount.clamp(0, u8::MAX as i32) as u8; - ItemStack::new(count, item) -} - -fn equipment_slot_from_bukkit(slot: &str) -> Option { - match slot { - "HAND" => Some(EquipmentSlot::MAIN_HAND), - "OFF_HAND" => Some(EquipmentSlot::OFF_HAND), - "FEET" => Some(EquipmentSlot::FEET), - "LEGS" => Some(EquipmentSlot::LEGS), - "CHEST" => Some(EquipmentSlot::CHEST), - "HEAD" => Some(EquipmentSlot::HEAD), - "BODY" => Some(EquipmentSlot::BODY), - "SADDLE" => Some(EquipmentSlot::SADDLE), - _ => None, - } -} - -fn bukkit_block_face_to_direction(face: &str) -> Option { - match face { - "UP" => Some(BlockDirection::Up), - "DOWN" => Some(BlockDirection::Down), - "NORTH" => Some(BlockDirection::North), - "SOUTH" => Some(BlockDirection::South), - "WEST" => Some(BlockDirection::West), - "EAST" => Some(BlockDirection::East), - _ => None, - } -} - -fn gamemode_from_bukkit(mode: &str) -> Option { - match mode { - "SURVIVAL" => Some(pumpkin_util::GameMode::Survival), - "CREATIVE" => Some(pumpkin_util::GameMode::Creative), - "ADVENTURE" => Some(pumpkin_util::GameMode::Adventure), - "SPECTATOR" => Some(pumpkin_util::GameMode::Spectator), - _ => None, - } -} - -fn main_hand_from_bukkit(hand: &str) -> Option { - match hand { - "LEFT" => Some(Hand::Left), - "RIGHT" => Some(Hand::Right), - _ => None, - } -} diff --git a/rust/src/java/plugin/command_manager.rs b/rust/src/java/plugin/command_manager.rs index d96a8c5..bfa0100 100644 --- a/rust/src/java/plugin/command_manager.rs +++ b/rust/src/java/plugin/command_manager.rs @@ -217,7 +217,7 @@ impl CommandManager { jvm: &Jvm, full_command: String, sender: SimpleCommandSender, - ) -> Result<()> { + ) -> Result { let command_map = match self.command_map { Some(ref command_map) => command_map, None => match self.init(jvm) { @@ -239,11 +239,7 @@ impl CommandManager { let handled: bool = jvm.to_rust(dispatch_result)?; - if !handled { - //log::warn!("Command was not handled by any Java plugin: {}", cmd_name); - } - - Ok(()) + Ok(handled) } pub fn sender_to_jsender(jvm: &Jvm, sender: SimpleCommandSender) -> Result {