diff --git a/paper-api/src/main/java/io/papermc/paper/event/player/PlayerPickItemEvent.java b/paper-api/src/main/java/io/papermc/paper/event/player/PlayerPickItemEvent.java
index 93c498d77240..592747372127 100644
--- a/paper-api/src/main/java/io/papermc/paper/event/player/PlayerPickItemEvent.java
+++ b/paper-api/src/main/java/io/papermc/paper/event/player/PlayerPickItemEvent.java
@@ -24,8 +24,7 @@ public abstract class PlayerPickItemEvent extends PlayerEvent implements Cancell
private static final HandlerList HANDLER_LIST = new HandlerList();
- private final boolean includeData;
-
+ private boolean includeData;
private int targetSlot;
private int sourceSlot;
@@ -48,6 +47,17 @@ public boolean isIncludeData() {
return includeData;
}
+ /**
+ * Sets whether block/entity data should be included.
+ *
+ * This does not bypass gamemode and permission checks.
+ *
+ * @param includeData whether to include blopck/entity data
+ */
+ public void setIncludeData(final boolean includeData) {
+ this.includeData = includeData;
+ }
+
/**
* Returns the slot the item that is being picked goes into.
*
diff --git a/paper-server/patches/features/0028-Optimise-collision-checking-in-player-move-packet-ha.patch b/paper-server/patches/features/0028-Optimise-collision-checking-in-player-move-packet-ha.patch
index c2fff76eb579..385914239372 100644
--- a/paper-server/patches/features/0028-Optimise-collision-checking-in-player-move-packet-ha.patch
+++ b/paper-server/patches/features/0028-Optimise-collision-checking-in-player-move-packet-ha.patch
@@ -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
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-index 92ce1962e9df66dbda6a3c0e25f6accdafbc4dc7..c6e5e45b1e97bbbfdae6804c313d499aaf3e6e50 100644
+index 5dfd13beabb7ece9043c8f90a9e61e6389c3460b..d0446e202dcc7a8b1223822199840644763319b7 100644
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -636,6 +636,7 @@ public class ServerGamePacketListenerImpl
@@ -72,7 +72,7 @@ index 92ce1962e9df66dbda6a3c0e25f6accdafbc4dc7..c6e5e45b1e97bbbfdae6804c313d499a
}
@Override
-@@ -1544,7 +1578,7 @@ public class ServerGamePacketListenerImpl
+@@ -1586,7 +1620,7 @@ public class ServerGamePacketListenerImpl
}
}
@@ -81,7 +81,7 @@ index 92ce1962e9df66dbda6a3c0e25f6accdafbc4dc7..c6e5e45b1e97bbbfdae6804c313d499a
xDist = targetX - this.lastGoodX; // Paper - diff on change, used for checking large move vectors above
yDist = targetY - this.lastGoodY; // Paper - diff on change, used for checking large move vectors above
zDist = targetZ - this.lastGoodZ; // Paper - diff on change, used for checking large move vectors above
-@@ -1570,6 +1604,7 @@ public class ServerGamePacketListenerImpl
+@@ -1612,6 +1646,7 @@ public class ServerGamePacketListenerImpl
boolean playerStandsOnSomething = this.player.verticalCollisionBelow;
this.player.move(MoverType.PLAYER, new Vec3(xDist, yDist, zDist));
this.player.onGround = packet.isOnGround(); // CraftBukkit - SPIGOT-5810, SPIGOT-5835, SPIGOT-6828: reset by this.player.move
@@ -89,7 +89,7 @@ index 92ce1962e9df66dbda6a3c0e25f6accdafbc4dc7..c6e5e45b1e97bbbfdae6804c313d499a
// Paper start - prevent position desync
if (this.awaitingPositionFromClient != null) {
return; // ... thanks Mojang for letting move calls teleport across dimensions.
-@@ -1603,7 +1638,17 @@ public class ServerGamePacketListenerImpl
+@@ -1645,7 +1680,17 @@ public class ServerGamePacketListenerImpl
}
// Paper start - Add fail move event
@@ -108,7 +108,7 @@ index 92ce1962e9df66dbda6a3c0e25f6accdafbc4dc7..c6e5e45b1e97bbbfdae6804c313d499a
if (!allowMovement) {
io.papermc.paper.event.player.PlayerFailMoveEvent event = fireFailMove(io.papermc.paper.event.player.PlayerFailMoveEvent.FailReason.CLIPPED_INTO_BLOCK,
targetX, targetY, targetZ, targetYRot, targetXRot, false);
-@@ -1730,7 +1775,7 @@ public class ServerGamePacketListenerImpl
+@@ -1772,7 +1817,7 @@ public class ServerGamePacketListenerImpl
private boolean updateAwaitingTeleport() {
if (this.awaitingPositionFromClient != null) {
@@ -117,7 +117,7 @@ index 92ce1962e9df66dbda6a3c0e25f6accdafbc4dc7..c6e5e45b1e97bbbfdae6804c313d499a
this.awaitingTeleportTime = this.tickCount;
this.teleport(
this.awaitingPositionFromClient.x,
-@@ -1749,6 +1794,34 @@ public class ServerGamePacketListenerImpl
+@@ -1791,6 +1836,34 @@ public class ServerGamePacketListenerImpl
}
}
diff --git a/paper-server/patches/features/0032-DataConverter-Moonrise-co-fixes.patch b/paper-server/patches/features/0032-DataConverter-Moonrise-co-fixes.patch
index 2c766efdd846..79b7a2e11dda 100644
--- a/paper-server/patches/features/0032-DataConverter-Moonrise-co-fixes.patch
+++ b/paper-server/patches/features/0032-DataConverter-Moonrise-co-fixes.patch
@@ -58,10 +58,10 @@ index 3b28b39ebf252d8de46f7d0ce27037cdb041f1b5..0b6d7f99edde802cb464baa5a4b2b4a4
return savedChunks;
}
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-index a61fb7d1c65b8b940d66f02e64c131b20a3ee610..b4434d534677403c68f1ff657c42736333e2e15e 100644
+index d0446e202dcc7a8b1223822199840644763319b7..cc7d66f9d7d9f206417dc080dda2a89e5c81dbe3 100644
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-@@ -1798,9 +1798,14 @@ public class ServerGamePacketListenerImpl
+@@ -1840,9 +1840,14 @@ public class ServerGamePacketListenerImpl
private boolean hasNewCollision(final ServerLevel level, final Entity entity, final AABB oldBox, final AABB newBox) {
final List collisionsBB = new java.util.ArrayList<>();
final List collisionsVoxel = new java.util.ArrayList<>();
diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch
index 706ddff5c781..c253b7f82b55 100644
--- a/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch
+++ b/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch
@@ -514,67 +514,120 @@
this.player.sendSystemMessage(Component.translatable("advMode.notAllowed"));
} else {
BaseCommandBlock commandBlock = packet.getCommandBlock(this.player.level());
-@@ -706,11 +_,11 @@
+@@ -704,14 +_,7 @@
+ if (level.isLoaded(pos)) {
+ BlockState blockState = level.getBlockState(pos);
boolean includeData = this.player.hasInfiniteMaterials() && packet.includeData();
- ItemStack itemStack = blockState.getCloneItemStack(level, pos, includeData);
- if (!itemStack.isEmpty()) {
+- ItemStack itemStack = blockState.getCloneItemStack(level, pos, includeData);
+- if (!itemStack.isEmpty()) {
- if (includeData) {
-+ if (includeData && this.player.getBukkitEntity().hasPermission("minecraft.nbt.copy")) { // Spigot
- addBlockDataToItem(blockState, level, pos, itemStack);
- }
-
+- addBlockDataToItem(blockState, level, pos, itemStack);
+- }
+-
- this.tryPickItem(itemStack);
-+ this.tryPickItem(itemStack, pos, null, packet.includeData()); // Paper - Extend PlayerPickItemEvent API
- }
+- }
++ tryPickItemFromBlock(level, pos, blockState, includeData); // Paper - Make includeData mutable for PlayerPickItemEvent
}
}
+ }
@@ -737,7 +_,7 @@
if (entity != null && this.player.isWithinEntityInteractionRange(entity, 3.0)) {
ItemStack itemStack = entity.getPickResult();
if (itemStack != null && !itemStack.isEmpty()) {
- this.tryPickItem(itemStack);
-+ this.tryPickItem(itemStack, null, entity, packet.includeData()); // Paper - Extend PlayerPickItemEvent API
++ this.tryPickItemFromEntity(entity, packet.includeData(), itemStack); // Paper - Make includeData mutable for PlayerPickItemEvent
}
if (packet.includeData() && this.player.canUseGameMasterBlocks() && entity instanceof Avatar avatar) {
-@@ -746,22 +_,35 @@
+@@ -746,22 +_,84 @@
}
}
- private void tryPickItem(final ItemStack itemStack) {
-+ private void tryPickItem(ItemStack itemStack, @Nullable BlockPos blockPos, @Nullable Entity entity, boolean includeData) { // Paper - Extend PlayerPickItemEvent API
- if (itemStack.isItemEnabled(this.player.level().enabledFeatures())) {
- Inventory inventory = this.player.getInventory();
- int slotWithExistingItem = inventory.findSlotMatchingItem(itemStack);
-+ // Paper start - Add PlayerPickItemEvent
-+ final int sourceSlot = slotWithExistingItem;
++ // Paper start - Make includeData mutable for PlayerPickItemEvent
++ private void tryPickItemFromBlock(
++ ServerLevel level, BlockPos pos, BlockState blockState, boolean initialIncludeData
++ ) {
++ ItemStack previewStack = blockState.getCloneItemStack(level, pos, initialIncludeData);
++ if (!previewStack.isEmpty()) {
++ if (initialIncludeData && this.player.getBukkitEntity().hasPermission("minecraft.nbt.copy")) {
++ addBlockDataToItem(blockState, level, pos, previewStack);
++ }
++
++ Inventory inventory = this.player.getInventory();
++ final int sourceSlot = inventory.findSlotMatchingItem(previewStack);
+ final int targetSlot = Inventory.isHotbarSlot(sourceSlot) ? sourceSlot : inventory.getSuitableHotbarSlot();
+ final org.bukkit.entity.Player bukkitPlayer = this.player.getBukkitEntity();
-+ 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);
++
++ io.papermc.paper.event.player.PlayerPickBlockEvent event = new io.papermc.paper.event.player.PlayerPickBlockEvent(
++ this.player.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), initialIncludeData, targetSlot, sourceSlot
++ );
++
+ if (!event.callEvent()) {
+ return;
+ }
-+ slotWithExistingItem = event.getSourceSlot();
-+ // Paper end - Add PlayerPickItemEvent
- if (slotWithExistingItem != Inventory.NOT_FOUND_INDEX) {
++
++ ItemStack stack;
++ if (initialIncludeData != event.isIncludeData()) {
++ stack = blockState.getCloneItemStack(level, pos, initialIncludeData);
++ if (event.isIncludeData() && this.player.getBukkitEntity().hasPermission("minecraft.nbt.copy")) {
++ addBlockDataToItem(blockState, level, pos, previewStack);
++ }
++ } else {
++ stack = previewStack;
++ }
++
++ this.tryPickItem(stack, event.getSourceSlot(), event.getTargetSlot());
++ }
++ }
++
++ private void tryPickItemFromEntity(
++ Entity entity, boolean initialIncludeData, ItemStack itemStack
++ ) {
++ Inventory inventory = this.player.getInventory();
++ final int sourceSlot = inventory.findSlotMatchingItem(itemStack);
++ final int targetSlot = Inventory.isHotbarSlot(sourceSlot) ? sourceSlot : inventory.getSuitableHotbarSlot();
++
++ io.papermc.paper.event.player.PlayerPickEntityEvent event = new io.papermc.paper.event.player.PlayerPickEntityEvent(
++ this.player.getBukkitEntity(), entity.getBukkitEntity(), initialIncludeData, targetSlot, sourceSlot
++ );
++
++ if (!event.callEvent()) {
++ return;
++ }
++
++ if (initialIncludeData != event.isIncludeData()) {
++ // This currently has no effect
++ }
++
++ this.tryPickItem(itemStack, event.getSourceSlot(), event.getTargetSlot());
++ }
++ // Paper end - Make includeData mutable for PlayerPickItemEvent
++
++ private void tryPickItem(ItemStack itemStack, int sourceSlot, int targetSlot) { // Paper - Make includeData mutable for PlayerPickItemEvent
+ if (itemStack.isItemEnabled(this.player.level().enabledFeatures())) {
+ Inventory inventory = this.player.getInventory();
+- int slotWithExistingItem = inventory.findSlotMatchingItem(itemStack);
+- if (slotWithExistingItem != Inventory.NOT_FOUND_INDEX) {
- if (Inventory.isHotbarSlot(slotWithExistingItem)) {
- inventory.setSelectedSlot(slotWithExistingItem);
-+ if (Inventory.isHotbarSlot(slotWithExistingItem) && Inventory.isHotbarSlot(event.getTargetSlot())) { // Paper - Add PlayerPickItemEvent
-+ inventory.setSelectedSlot(event.getTargetSlot()); // Paper - Add PlayerPickItemEvent
++
++ if (sourceSlot != Inventory.NOT_FOUND_INDEX) { // Paper - Make includeData mutable for PlayerPickItemEvent
++ if (Inventory.isHotbarSlot(sourceSlot) && Inventory.isHotbarSlot(targetSlot)) { // Paper - Make includeData mutable for PlayerPickItemEvent
++ inventory.setSelectedSlot(targetSlot); // Paper - Make includeData mutable for PlayerPickItemEvent
} else {
- inventory.pickSlot(slotWithExistingItem);
-+ inventory.pickSlot(slotWithExistingItem, event.getTargetSlot()); // Paper - Add PlayerPickItemEvent
++ inventory.pickSlot(sourceSlot, targetSlot); // Paper - Make includeData mutable for PlayerPickItemEvent
}
} else if (this.player.hasInfiniteMaterials()) {
- inventory.addAndPickItem(itemStack);
-+ inventory.addAndPickItem(itemStack, event.getTargetSlot()); // Paper - Add PlayerPickItemEvent
++ inventory.addAndPickItem(itemStack, targetSlot); // Paper - Make includeData mutable for PlayerPickItemEvent
}
this.send(new ClientboundSetHeldSlotPacket(inventory.getSelectedSlot()));
this.player.inventoryMenu.broadcastChanges();
-+ if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.updateEquipmentOnPlayerActions) this.player.detectEquipmentUpdates(); // Paper - Force update attributes.
++ if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.updateEquipmentOnPlayerActions)
++ this.player.detectEquipmentUpdates(); // Paper - Force update attributes.
}
}