1
0
mirror of https://github.com/PaperMC/Paper.git synced 2025-07-27 18:22:03 -07:00

Add PlayerPickBlockEvent and PlayerPickEntityEvent ()

Extensions of the existing PlayerPickItemEvent that allow more fine grained access to relevant context, like the picked block or the entity.
This commit is contained in:
David
2025-05-02 22:14:27 +02:00
committed by GitHub
parent 1074237311
commit 825685f82f
5 changed files with 112 additions and 13 deletions

@@ -0,0 +1,32 @@
package io.papermc.paper.event.player;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
/**
* Event that is fired when a player uses the pick item functionality on a block
* (middle-clicking a block to get the appropriate item).
* After the handling of this event, the contents of the source and the target slot will be swapped,
* and the currently selected hotbar slot of the player will be set to the target slot.
*/
@NullMarked
public class PlayerPickBlockEvent extends PlayerPickItemEvent {
private final Block block;
@ApiStatus.Internal
public PlayerPickBlockEvent(final Player player, final Block block, final boolean includeData, final int targetSlot, final int sourceSlot) {
super(player, includeData, targetSlot, sourceSlot);
this.block = block;
}
/**
* Retrieves the block associated with this event.
*
* @return the block involved in the event
*/
public Block getBlock() {
return this.block;
}
}

@@ -0,0 +1,32 @@
package io.papermc.paper.event.player;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
/**
* Event that is fired when a player uses the pick item functionality on an entity
* (middle-clicking an entity to get the appropriate item).
* After the handling of this event, the contents of the source and the target slot will be swapped,
* and the currently selected hotbar slot of the player will be set to the target slot.
*/
@NullMarked
public class PlayerPickEntityEvent extends PlayerPickItemEvent {
private final Entity entity;
@ApiStatus.Internal
public PlayerPickEntityEvent(final Player player, final Entity entity, final boolean includeData, final int targetSlot, final int sourceSlot) {
super(player, includeData, targetSlot, sourceSlot);
this.entity = entity;
}
/**
* Retrieves the entity associated with this event.
*
* @return the entity involved in the event
*/
public Entity getEntity() {
return this.entity;
}
}

@@ -10,27 +10,44 @@ import org.jetbrains.annotations.Range;
import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.NullMarked;
/** /**
* Event that is fired when a player uses the pick item functionality (middle-clicking a block or entity to get the * Event that is fired when a player uses the pick item functionality
* appropriate item). After the handling of this event, the contents of the source and the target slot will be swapped * (middle-clicking a {@link PlayerPickBlockEvent block}
* or {@link PlayerPickEntityEvent entity} to get the appropriate item).
* After the handling of this event, the contents of the source and the target slot will be swapped,
* and the currently selected hotbar slot of the player will be set to the target slot. * and the currently selected hotbar slot of the player will be set to the target slot.
*
* @see PlayerPickEntityEvent
* @see PlayerPickBlockEvent
*/ */
@NullMarked @NullMarked
public class PlayerPickItemEvent extends PlayerEvent implements Cancellable { public abstract class PlayerPickItemEvent extends PlayerEvent implements Cancellable {
private static final HandlerList HANDLER_LIST = new HandlerList(); private static final HandlerList HANDLER_LIST = new HandlerList();
private final boolean includeData;
private int targetSlot; private int targetSlot;
private int sourceSlot; private int sourceSlot;
private boolean cancelled; private boolean cancelled;
@ApiStatus.Internal @ApiStatus.Internal
public PlayerPickItemEvent(final Player player, final int targetSlot, final int sourceSlot) { protected PlayerPickItemEvent(final Player player, final boolean includeData, final int targetSlot, final int sourceSlot) {
super(player); super(player);
this.includeData = includeData;
this.targetSlot = targetSlot; this.targetSlot = targetSlot;
this.sourceSlot = sourceSlot; this.sourceSlot = sourceSlot;
} }
/**
* Checks whether the player wants block/entity data included.
*
* @return {@code true} if data is included, otherwise {@code false}.
*/
public boolean isIncludeData() {
return includeData;
}
/** /**
* Returns the slot the item that is being picked goes into. * Returns the slot the item that is being picked goes into.
* *

@@ -6,7 +6,7 @@ Subject: [PATCH] Optimise collision checking in player move packet handling
Move collision logic to just the hasNewCollision call instead of getCubes + hasNewCollision Move collision logic to just the hasNewCollision call instead of getCubes + hasNewCollision
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 5e921c490814be31fc2843327c0e2cc76bda6620..f49a2c18ec20a7181951389066b7d062b48d43fa 100644 index 0be741820fc7da2aac4f4aad85c4238ef49a0f57..337976c5c1ead87c36daa4e741b06e5a195b8302 100644
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java --- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -555,7 +555,7 @@ public class ServerGamePacketListenerImpl @@ -555,7 +555,7 @@ public class ServerGamePacketListenerImpl
@@ -88,7 +88,7 @@ index 5e921c490814be31fc2843327c0e2cc76bda6620..f49a2c18ec20a7181951389066b7d062
} }
@Override @Override
@@ -1430,7 +1462,7 @@ public class ServerGamePacketListenerImpl @@ -1432,7 +1464,7 @@ public class ServerGamePacketListenerImpl
} }
} }
@@ -97,7 +97,7 @@ index 5e921c490814be31fc2843327c0e2cc76bda6620..f49a2c18ec20a7181951389066b7d062
d3 = d - this.lastGoodX; // Paper - diff on change, used for checking large move vectors above d3 = d - this.lastGoodX; // Paper - diff on change, used for checking large move vectors above
d4 = d1 - this.lastGoodY; // Paper - diff on change, used for checking large move vectors above d4 = d1 - this.lastGoodY; // Paper - diff on change, used for checking large move vectors above
d5 = d2 - this.lastGoodZ; // Paper - diff on change, used for checking large move vectors above d5 = d2 - this.lastGoodZ; // Paper - diff on change, used for checking large move vectors above
@@ -1469,6 +1501,7 @@ public class ServerGamePacketListenerImpl @@ -1471,6 +1503,7 @@ public class ServerGamePacketListenerImpl
boolean flag1 = this.player.verticalCollisionBelow; boolean flag1 = this.player.verticalCollisionBelow;
this.player.move(MoverType.PLAYER, new Vec3(d3, d4, d5)); this.player.move(MoverType.PLAYER, new Vec3(d3, d4, d5));
this.player.onGround = packet.isOnGround(); // CraftBukkit - SPIGOT-5810, SPIGOT-5835, SPIGOT-6828: reset by this.player.move this.player.onGround = packet.isOnGround(); // CraftBukkit - SPIGOT-5810, SPIGOT-5835, SPIGOT-6828: reset by this.player.move
@@ -105,7 +105,7 @@ index 5e921c490814be31fc2843327c0e2cc76bda6620..f49a2c18ec20a7181951389066b7d062
// Paper start - prevent position desync // Paper start - prevent position desync
if (this.awaitingPositionFromClient != null) { if (this.awaitingPositionFromClient != null) {
return; // ... thanks Mojang for letting move calls teleport across dimensions. return; // ... thanks Mojang for letting move calls teleport across dimensions.
@@ -1501,7 +1534,17 @@ public class ServerGamePacketListenerImpl @@ -1503,7 +1536,17 @@ public class ServerGamePacketListenerImpl
} }
// Paper start - Add fail move event // Paper start - Add fail move event
@@ -124,7 +124,7 @@ index 5e921c490814be31fc2843327c0e2cc76bda6620..f49a2c18ec20a7181951389066b7d062
if (teleportBack) { if (teleportBack) {
io.papermc.paper.event.player.PlayerFailMoveEvent event = fireFailMove(io.papermc.paper.event.player.PlayerFailMoveEvent.FailReason.CLIPPED_INTO_BLOCK, io.papermc.paper.event.player.PlayerFailMoveEvent event = fireFailMove(io.papermc.paper.event.player.PlayerFailMoveEvent.FailReason.CLIPPED_INTO_BLOCK,
toX, toY, toZ, toYaw, toPitch, false); toX, toY, toZ, toYaw, toPitch, false);
@@ -1638,7 +1681,7 @@ public class ServerGamePacketListenerImpl @@ -1640,7 +1683,7 @@ public class ServerGamePacketListenerImpl
private boolean updateAwaitingTeleport() { private boolean updateAwaitingTeleport() {
if (this.awaitingPositionFromClient != null) { if (this.awaitingPositionFromClient != null) {
@@ -133,7 +133,7 @@ index 5e921c490814be31fc2843327c0e2cc76bda6620..f49a2c18ec20a7181951389066b7d062
this.awaitingTeleportTime = this.tickCount; this.awaitingTeleportTime = this.tickCount;
this.teleport( this.teleport(
this.awaitingPositionFromClient.x, this.awaitingPositionFromClient.x,
@@ -1657,6 +1700,33 @@ public class ServerGamePacketListenerImpl @@ -1659,6 +1702,33 @@ public class ServerGamePacketListenerImpl
} }
} }

@@ -523,7 +523,7 @@
this.player.sendSystemMessage(Component.translatable("advMode.notAllowed")); this.player.sendSystemMessage(Component.translatable("advMode.notAllowed"));
} else { } else {
BaseCommandBlock commandBlock = packet.getCommandBlock(this.player.level()); BaseCommandBlock commandBlock = packet.getCommandBlock(this.player.level());
@@ -661,7 +_,7 @@ @@ -661,11 +_,11 @@
boolean flag = this.player.hasInfiniteMaterials() && packet.includeData(); boolean flag = this.player.hasInfiniteMaterials() && packet.includeData();
ItemStack cloneItemStack = blockState.getCloneItemStack(serverLevel, blockPos, flag); ItemStack cloneItemStack = blockState.getCloneItemStack(serverLevel, blockPos, flag);
if (!cloneItemStack.isEmpty()) { if (!cloneItemStack.isEmpty()) {
@@ -532,7 +532,23 @@
addBlockDataToItem(blockState, serverLevel, blockPos, cloneItemStack); addBlockDataToItem(blockState, serverLevel, blockPos, cloneItemStack);
} }
@@ -698,18 +_,29 @@ - this.tryPickItem(cloneItemStack);
+ this.tryPickItem(cloneItemStack, blockPos, null, packet.includeData()); // Paper - Extend PlayerPickItemEvent API
}
}
}
@@ -689,27 +_,40 @@
if (entityOrPart != null && this.player.canInteractWithEntity(entityOrPart, 3.0)) {
ItemStack pickResult = entityOrPart.getPickResult();
if (pickResult != null && !pickResult.isEmpty()) {
- this.tryPickItem(pickResult);
+ this.tryPickItem(pickResult, null, entityOrPart, packet.includeData()); // Paper - Extend PlayerPickItemEvent API
}
}
}
- private void tryPickItem(ItemStack stack) {
+ private void tryPickItem(ItemStack stack, @Nullable BlockPos blockPos, @Nullable Entity entity, boolean includeData) { // Paper - Extend PlayerPickItemEvent API
if (stack.isItemEnabled(this.player.level().enabledFeatures())) { if (stack.isItemEnabled(this.player.level().enabledFeatures())) {
Inventory inventory = this.player.getInventory(); Inventory inventory = this.player.getInventory();
int i = inventory.findSlotMatchingItem(stack); int i = inventory.findSlotMatchingItem(stack);
@@ -540,7 +556,9 @@
+ final int sourceSlot = i; + final int sourceSlot = i;
+ final int targetSlot = Inventory.isHotbarSlot(sourceSlot) ? sourceSlot : inventory.getSuitableHotbarSlot(); + final int targetSlot = Inventory.isHotbarSlot(sourceSlot) ? sourceSlot : inventory.getSuitableHotbarSlot();
+ final org.bukkit.entity.Player bukkitPlayer = this.player.getBukkitEntity(); + final org.bukkit.entity.Player bukkitPlayer = this.player.getBukkitEntity();
+ final io.papermc.paper.event.player.PlayerPickItemEvent event = new io.papermc.paper.event.player.PlayerPickItemEvent(bukkitPlayer, targetSlot, sourceSlot); + final io.papermc.paper.event.player.PlayerPickItemEvent event = entity != null
+ ? new io.papermc.paper.event.player.PlayerPickEntityEvent(bukkitPlayer, entity.getBukkitEntity(), includeData, targetSlot, sourceSlot)
+ : new io.papermc.paper.event.player.PlayerPickBlockEvent(bukkitPlayer, org.bukkit.craftbukkit.block.CraftBlock.at(this.player.level(), blockPos), includeData, targetSlot, sourceSlot);
+ if (!event.callEvent()) { + if (!event.callEvent()) {
+ return; + return;
+ } + }