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. } }