diff --git a/patches/server/Add-PlayerShieldDisableEvent.patch b/patches/server/Add-PlayerShieldDisableEvent.patch index 7109c61000..ab943067a4 100644 --- a/patches/server/Add-PlayerShieldDisableEvent.patch +++ b/patches/server/Add-PlayerShieldDisableEvent.patch @@ -24,11 +24,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (this.random.nextFloat() < f) { - player.getCooldowns().addCooldown(Items.SHIELD, 100); -+ // Paper start ++ // Paper start - Add PlayerShieldDisableEvent + final io.papermc.paper.event.player.PlayerShieldDisableEvent shieldDisableEvent = new io.papermc.paper.event.player.PlayerShieldDisableEvent((org.bukkit.entity.Player) player.getBukkitEntity(), getBukkitEntity(), 100); + if (!shieldDisableEvent.callEvent()) return; + player.getCooldowns().addCooldown(Items.SHIELD, shieldDisableEvent.getCooldown()); -+ // Paper end ++ // Paper end - Add PlayerShieldDisableEvent this.level().broadcastEntityEvent(player, (byte) 30); } } @@ -41,7 +41,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 super.blockUsingShield(attacker); if (attacker.canDisableShield()) { - this.disableShield(true); -+ this.disableShield(true, attacker); // Paper ++ this.disableShield(true, attacker); // Paper - Add PlayerShieldDisableEvent } } @@ -49,14 +49,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.attack(target); } -+ @io.papermc.paper.annotation.DoNotUse // Paper - add player shield disable event ++ @io.papermc.paper.annotation.DoNotUse // Paper - Add PlayerShieldDisableEvent public void disableShield(boolean sprinting) { -+ // Paper start - add player shield disable event ++ // Paper start - Add PlayerShieldDisableEvent + disableShield(sprinting, null); + } + + public void disableShield(boolean sprinting, @Nullable LivingEntity attacker) { -+ // Paper end - add player shield disable event ++ // Paper end - Add PlayerShieldDisableEvent float f = 0.25F + (float) EnchantmentHelper.getBlockEfficiency(this) * 0.05F; if (sprinting) { @@ -65,7 +65,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (this.random.nextFloat() < f) { - this.getCooldowns().addCooldown(Items.SHIELD, 100); -+ // Paper start - add player shield disable event ++ // Paper start - Add PlayerShieldDisableEvent + final org.bukkit.entity.Entity finalAttacker = attacker != null ? attacker.getBukkitEntity() : null; + if (finalAttacker != null) { + final io.papermc.paper.event.player.PlayerShieldDisableEvent shieldDisableEvent = new io.papermc.paper.event.player.PlayerShieldDisableEvent((org.bukkit.entity.Player) getBukkitEntity(), finalAttacker, 100); @@ -74,7 +74,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } else { + this.getCooldowns().addCooldown(Items.SHIELD, 100); + } -+ // Paper end - add player shield disable event ++ // Paper end - Add PlayerShieldDisableEvent this.stopUsingItem(); this.level().broadcastEntityEvent(this, (byte) 30); } diff --git a/patches/server/Add-drops-to-shear-events.patch b/patches/server/Add-drops-to-shear-events.patch index df5fdec999..274d7656ab 100644 --- a/patches/server/Add-drops-to-shear-events.patch +++ b/patches/server/Add-drops-to-shear-events.patch @@ -13,15 +13,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (ishearable.readyForShearing()) { // CraftBukkit start - if (CraftEventFactory.callBlockShearEntityEvent(entityliving, bukkitBlock, craftItem).isCancelled()) { -+ // Paper start ++ // Paper start - Add drops to shear events + org.bukkit.event.block.BlockShearEntityEvent event = CraftEventFactory.callBlockShearEntityEvent(entityliving, bukkitBlock, craftItem, ishearable.generateDefaultDrops()); + if (event.isCancelled()) { -+ // Paper end ++ // Paper end - Add drops to shear events continue; } // CraftBukkit end - ishearable.shear(SoundSource.BLOCKS); -+ ishearable.shear(SoundSource.BLOCKS, CraftItemStack.asNMSCopy(event.getDrops())); // Paper ++ ishearable.shear(SoundSource.BLOCKS, CraftItemStack.asNMSCopy(event.getDrops())); // Paper - Add drops to shear events worldserver.gameEvent((Entity) null, GameEvent.SHEAR, blockposition); return true; } @@ -33,15 +33,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 import net.minecraft.sounds.SoundSource; public interface Shearable { -+ default void shear(SoundSource soundCategory, java.util.List drops) { this.shear(soundCategory); } // Paper ++ default void shear(SoundSource soundCategory, java.util.List drops) { this.shear(soundCategory); } // Paper - Add drops to shear events void shear(SoundSource shearedSoundCategory); boolean readyForShearing(); -+ // Paper start - ensure all implementing entities override this ++ // Paper start - custom shear drops; ensure all implementing entities override this + default java.util.List generateDefaultDrops() { + return java.util.Collections.emptyList(); + } -+ // Paper end ++ // Paper end - custom shear drops } diff --git a/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java b/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 @@ -65,7 +65,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper end - custom shear drops // CraftBukkit end - this.shear(SoundSource.PLAYERS); -+ this.shear(SoundSource.PLAYERS, drops); // Paper ++ this.shear(SoundSource.PLAYERS, drops); // Paper - custom shear drops this.gameEvent(GameEvent.SHEAR, player); if (!this.level().isClientSide) { itemstack.hurtAndBreak(1, player, (entityhuman1) -> { @@ -106,7 +106,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - } - this.level().addFreshEntity(entityitem); - // CraftBukkit end -+ // Paper start - custom shear drops (moved drop generation to separate method) ++ // Paper start - custom shear drops; moved drop generation to separate method + for (final ItemStack drop : drops) { + ItemEntity entityitem = new ItemEntity(this.level(), this.getX(), this.getY(1.0D), this.getZ(), drop); + this.spawnAtLocation(entityitem); diff --git a/patches/server/Add-experience-points-API.patch b/patches/server/Add-experience-points-API.patch index 01f11a1cdf..548916b614 100644 --- a/patches/server/Add-experience-points-API.patch +++ b/patches/server/Add-experience-points-API.patch @@ -13,7 +13,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public int getXpNeededForNextLevel() { - return this.experienceLevel >= 30 ? 112 + (this.experienceLevel - 30) * 9 : (this.experienceLevel >= 15 ? 37 + (this.experienceLevel - 15) * 5 : 7 + this.experienceLevel * 2); -+ return this.experienceLevel >= 30 ? 112 + (this.experienceLevel - 30) * 9 : (this.experienceLevel >= 15 ? 37 + (this.experienceLevel - 15) * 5 : 7 + this.experienceLevel * 2); // Paper - diff on change ++ return this.experienceLevel >= 30 ? 112 + (this.experienceLevel - 30) * 9 : (this.experienceLevel >= 15 ? 37 + (this.experienceLevel - 15) * 5 : 7 + this.experienceLevel * 2); // Paper - diff on change; calculateTotalExperiencePoints } // Paper start - send SoundEffect to everyone who can see fromEntity private static void sendSoundEffect(Player fromEntity, double x, double y, double z, SoundEvent soundEffect, SoundSource soundCategory, float volume, float pitch) { diff --git a/patches/server/Correctly-check-if-bucket-dispenses-will-succeed-for.patch b/patches/server/Correctly-check-if-bucket-dispenses-will-succeed-for.patch index 0fefd12969..8768319c41 100644 --- a/patches/server/Correctly-check-if-bucket-dispenses-will-succeed-for.patch +++ b/patches/server/Correctly-check-if-bucket-dispenses-will-succeed-for.patch @@ -19,7 +19,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper start - correctly check if the bucket place will succeed + /* Taken from SolidBucketItem#emptyContents */ + boolean willEmptyContentsSolidBucketItem = dispensiblecontaineritem instanceof net.minecraft.world.item.SolidBucketItem && worldserver.isInWorldBounds(blockposition) && iblockdata.isAir(); -+ /* Take from BucketItem#emptyContents */ ++ /* Taken from BucketItem#emptyContents */ + boolean willEmptyBucketItem = dispensiblecontaineritem instanceof final BucketItem bucketItem && bucketItem.content instanceof net.minecraft.world.level.material.FlowingFluid && (iblockdata.isAir() || iblockdata.canBeReplaced(bucketItem.content) || (iblockdata.getBlock() instanceof LiquidBlockContainer liquidBlockContainer && liquidBlockContainer.canPlaceLiquid(null, worldserver, blockposition, iblockdata, bucketItem.content))); + if (willEmptyContentsSolidBucketItem || willEmptyBucketItem) { + // Paper end - correctly check if the bucket place will succeed diff --git a/patches/server/Dont-resend-blocks-on-interactions.patch b/patches/server/Dont-resend-blocks-on-interactions.patch index 5e604b24e4..503a6c2767 100644 --- a/patches/server/Dont-resend-blocks-on-interactions.patch +++ b/patches/server/Dont-resend-blocks-on-interactions.patch @@ -52,7 +52,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + //} else if (data.getBlock() instanceof TrapDoorBlock) { + // this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); + //} -+ // Paper end ++ // Paper end - Don't resync blocks } else if (!iblockdata.isAir()) { iblockdata.attack(this.level, pos, this.player); f = iblockdata.getDestroyProgress(this.player, this.player.level(), pos); @@ -87,7 +87,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (isSwordNoBreak) { return false; } -+ // Paper start - Dont resync blocks ++ // Paper start - Don't resync blocks // Let the client know the block still exists - this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); + //this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); @@ -99,7 +99,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + //for (Direction dir : Direction.values()) { + // this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos.relative(dir))); + //} -+ // Paper end ++ // Paper end - Don't resync blocks // Update any tile entity data for this block if (!captureSentBlockEntities) { // Paper - Toggle this location for capturing as this is used for api @@ -112,17 +112,17 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper start - Don't resync blocks + // boolean bottom = iblockdata.getValue(DoorBlock.HALF) == DoubleBlockHalf.LOWER; + // player.connection.send(new ClientboundBlockUpdatePacket(world, bottom ? blockposition.above() : blockposition.below())); -+ // Paper end ++ // Paper end - Don't resync blocks } else if (iblockdata.getBlock() instanceof CakeBlock) { player.getBukkitEntity().sendHealthUpdate(); // SPIGOT-1341 - reset health for cake } else if (this.interactItemStack.getItem() instanceof DoubleHighBlockItem) { // send a correcting update to the client, as it already placed the upper half of the bisected item - player.connection.send(new ClientboundBlockUpdatePacket(world, blockposition.relative(hitResult.getDirection()).above())); -+ //player.connection.send(new ClientboundBlockUpdatePacket(world, blockposition.relative(hitResult.getDirection()).above())); // Paper - don't resync blocks ++ //player.connection.send(new ClientboundBlockUpdatePacket(world, blockposition.relative(hitResult.getDirection()).above())); // Paper - Don't resync blocks // send a correcting update to the client for the block above as well, this because of replaceable blocks (such as grass, sea grass etc) - player.connection.send(new ClientboundBlockUpdatePacket(world, blockposition.above())); -+ //player.connection.send(new ClientboundBlockUpdatePacket(world, blockposition.above())); // Paper - don't resync blocks ++ //player.connection.send(new ClientboundBlockUpdatePacket(world, blockposition.above())); // Paper - Don't resync blocks // Paper start - extend Player Interact cancellation // TODO: consider merging this into the extracted method } else if (iblockdata.getBlock() instanceof net.minecraft.world.level.block.StructureBlock) { player.connection.send(new net.minecraft.network.protocol.game.ClientboundContainerClosePacket(this.player.containerMenu.containerId)); @@ -160,12 +160,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - for (Direction dir : Direction.values()) { - ((ServerPlayer) entityhuman).connection.send(new ClientboundBlockUpdatePacket(world, placedPos.relative(dir))); - } -+ // Paper start - don't resync blocks ++ // Paper start - Don't resync blocks + // BlockPos placedPos = ((CraftBlock) placeEvent.getBlock()).getPosition(); + // for (Direction dir : Direction.values()) { + // ((ServerPlayer) entityhuman).connection.send(new ClientboundBlockUpdatePacket(world, placedPos.relative(dir))); + // } -+ // Paper end ++ // Paper end - Don't resync blocks SignItem.openSign = null; // SPIGOT-6758 - Reset on early return } else { // Change the stack to its new contents if it hasn't been tampered with. diff --git a/patches/server/Properly-handle-experience-dropping-on-block-break.patch b/patches/server/Properly-handle-experience-dropping-on-block-break.patch index a4bea4b784..bda0098818 100644 --- a/patches/server/Properly-handle-experience-dropping-on-block-break.patch +++ b/patches/server/Properly-handle-experience-dropping-on-block-break.patch @@ -15,8 +15,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 BlockEntity tileentity = iblockdata.hasBlockEntity() ? this.getBlockEntity(pos) : null; - Block.dropResources(iblockdata, this, pos, tileentity, breakingEntity, ItemStack.EMPTY); -+ Block.dropResources(iblockdata, this, pos, tileentity, breakingEntity, ItemStack.EMPTY, false); // Don't drop xp -+ iblockdata.getBlock().popExperience((ServerLevel) this, pos, xp, breakingEntity); // Paper - handle drop experience logic, custom amount ++ Block.dropResources(iblockdata, this, pos, tileentity, breakingEntity, ItemStack.EMPTY, false); // Paper - Properly handle xp dropping ++ iblockdata.getBlock().popExperience((ServerLevel) this, pos, xp, breakingEntity); // Paper - Properly handle xp dropping; custom amount } boolean flag1 = this.setBlock(pos, fluid.createLegacyBlock(), 3, maxUpdateDepth); @@ -28,33 +28,33 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 for (net.minecraft.world.item.ItemStack drop : net.minecraft.world.level.block.Block.getDrops(state, world.getMinecraftWorld(), pos, blockEntity)) { items.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(drop)); } -+ Block block = state.getBlock(); ++ Block block = state.getBlock(); // Paper - Properly handle xp dropping io.papermc.paper.event.block.BlockBreakBlockEvent event = new io.papermc.paper.event.block.BlockBreakBlockEvent(org.bukkit.craftbukkit.block.CraftBlock.at(world, pos), org.bukkit.craftbukkit.block.CraftBlock.at(world, source), items); -+ event.setExpToDrop(block.getExpDrop(state, (ServerLevel) world, pos, net.minecraft.world.item.ItemStack.EMPTY, true)); ++ event.setExpToDrop(block.getExpDrop(state, (ServerLevel) world, pos, net.minecraft.world.item.ItemStack.EMPTY, true)); // Paper - Properly handle xp dropping event.callEvent(); for (var drop : event.getDrops()) { popResource(world.getMinecraftWorld(), pos, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(drop)); } - state.spawnAfterBreak(world.getMinecraftWorld(), pos, ItemStack.EMPTY, true); -+ state.spawnAfterBreak(world.getMinecraftWorld(), pos, ItemStack.EMPTY, false); -+ block.popExperience((ServerLevel) world, pos, event.getExpToDrop()); ++ state.spawnAfterBreak(world.getMinecraftWorld(), pos, ItemStack.EMPTY, false); // Paper - Properly handle xp dropping ++ block.popExperience((ServerLevel) world, pos, event.getExpToDrop()); // Paper - Properly handle xp dropping } return true; } // Paper end public static void dropResources(BlockState state, Level world, BlockPos pos, @Nullable BlockEntity blockEntity, @Nullable Entity entity, ItemStack tool) { -+ // Paper start ++ // Paper start - Properly handle xp dropping + dropResources(state, world, pos, blockEntity, entity, tool, true); + } + public static void dropResources(BlockState state, Level world, BlockPos pos, @Nullable BlockEntity blockEntity, @Nullable Entity entity, ItemStack tool, boolean dropExperience) { -+ // Paper end ++ // Paper end - Properly handle xp dropping if (world instanceof ServerLevel) { Block.getDrops(state, (ServerLevel) world, pos, blockEntity, entity, tool).forEach((itemstack1) -> { Block.popResource(world, pos, itemstack1); }); - state.spawnAfterBreak((ServerLevel) world, pos, tool, true); -+ state.spawnAfterBreak((ServerLevel) world, pos, tool, dropExperience); // Paper ++ state.spawnAfterBreak((ServerLevel) world, pos, tool, dropExperience); // Paper - Properly handle xp dropping } } @@ -63,7 +63,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 player.causeFoodExhaustion(0.005F, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.BLOCK_MINED); // CraftBukkit - EntityExhaustionEvent if (includeDrops) { // Paper - Block.dropResources(state, world, pos, blockEntity, player, tool); -+ Block.dropResources(state, world, pos, blockEntity, player, tool, dropExp); // Paper ++ Block.dropResources(state, world, pos, blockEntity, player, tool, dropExp); // Paper - Properly handle xp dropping } // Paper } @@ -75,7 +75,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public void spawnAfterBreak(ServerLevel world, BlockPos pos, ItemStack tool, boolean dropExperience) { this.getBlock().spawnAfterBreak(this.asState(), world, pos, tool, dropExperience); -+ if (dropExperience) {getBlock().popExperience(world, pos, this.getBlock().getExpDrop(asState(), world, pos, tool, true));} // Paper - spawn experience ++ if (dropExperience) {getBlock().popExperience(world, pos, this.getBlock().getExpDrop(asState(), world, pos, tool, true));} // Paper - Properly handle xp dropping } public List getDrops(LootParams.Builder builder) { @@ -88,7 +88,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // Modelled off EntityHuman#hasBlock if (block != Blocks.AIR && (item == null || !iblockdata.requiresCorrectToolForDrops() || nmsItem.isCorrectToolForDrops(iblockdata))) { - net.minecraft.world.level.block.Block.dropResources(iblockdata, this.world.getMinecraftWorld(), this.position, this.world.getBlockEntity(this.position), null, nmsItem); -+ net.minecraft.world.level.block.Block.dropResources(iblockdata, this.world.getMinecraftWorld(), this.position, this.world.getBlockEntity(this.position), null, nmsItem, false); // Paper ++ net.minecraft.world.level.block.Block.dropResources(iblockdata, this.world.getMinecraftWorld(), this.position, this.world.getBlockEntity(this.position), null, nmsItem, false); // Paper - Properly handle xp dropping // Paper start - improve Block#breanNaturally if (triggerEffect) { if (iblockdata.getBlock() instanceof net.minecraft.world.level.block.BaseFireBlock) { diff --git a/patches/server/Restore-vanilla-entity-drops-behavior.patch b/patches/server/Restore-vanilla-entity-drops-behavior.patch index ae80dabb8a..2f1f3b5c7e 100644 --- a/patches/server/Restore-vanilla-entity-drops-behavior.patch +++ b/patches/server/Restore-vanilla-entity-drops-behavior.patch @@ -17,14 +17,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 return; } - java.util.List loot = new java.util.ArrayList(this.getInventory().getContainerSize()); -+ List loot = new java.util.ArrayList<>(this.getInventory().getContainerSize()); // Paper ++ List loot = new java.util.ArrayList<>(this.getInventory().getContainerSize()); // Paper - Restore vanilla drops behavior boolean keepInventory = this.level().getGameRules().getBoolean(GameRules.RULE_KEEPINVENTORY) || this.isSpectator(); if (!keepInventory) { for (ItemStack item : this.getInventory().getContents()) { if (!item.isEmpty() && !EnchantmentHelper.hasVanishingCurse(item)) { - loot.add(CraftItemStack.asCraftMirror(item)); -+ loot.add(new DefaultDrop(item, stack -> this.drop(stack, true, false, false))); // Paper - drop function taken from Inventory#dropAll (don't fire drop event) ++ loot.add(new DefaultDrop(item, stack -> this.drop(stack, true, false, false))); // Paper - Restore vanilla drops behavior; drop function taken from Inventory#dropAll (don't fire drop event) } } } @@ -44,8 +44,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Override - public ItemEntity drop(ItemStack stack, boolean throwRandomly, boolean retainOwnership) { - ItemEntity entityitem = super.drop(stack, throwRandomly, retainOwnership); -+ public ItemEntity drop(ItemStack stack, boolean throwRandomly, boolean retainOwnership, boolean callDropEvent) { // Paper - override method with most params -+ ItemEntity entityitem = super.drop(stack, throwRandomly, retainOwnership, callDropEvent); // Paper - override method with most params ++ public ItemEntity drop(ItemStack stack, boolean throwRandomly, boolean retainOwnership, boolean callDropEvent) { // Paper - Restore vanilla drops behavior; override method with most params ++ ItemEntity entityitem = super.drop(stack, throwRandomly, retainOwnership, callDropEvent); // Paper - Restore vanilla drops behavior; override method with most params if (entityitem == null) { return null; @@ -57,7 +57,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Nullable public ItemEntity spawnAtLocation(ItemStack stack, float yOffset) { -+ // Paper start ++ // Paper start - Restore vanilla drops behavior + return this.spawnAtLocation(stack, yOffset, null); + } + public record DefaultDrop(Item item, org.bukkit.inventory.ItemStack stack, @Nullable java.util.function.Consumer dropConsumer) { @@ -75,7 +75,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + @Nullable + public ItemEntity spawnAtLocation(ItemStack stack, float yOffset, @Nullable java.util.function.Consumer delayedAddConsumer) { -+ // Paper end ++ // Paper end - Restore vanilla drops behavior if (stack.isEmpty()) { return null; } else if (this.level().isClientSide) { @@ -84,14 +84,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // CraftBukkit start - Capture drops for death event if (this instanceof net.minecraft.world.entity.LivingEntity && !((net.minecraft.world.entity.LivingEntity) this).forceDrops) { - ((net.minecraft.world.entity.LivingEntity) this).drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack)); // Paper - mirror so we can destroy it later -+ // Paper start ++ // Paper start - Restore vanilla drops behavior + ((net.minecraft.world.entity.LivingEntity) this).drops.add(new net.minecraft.world.entity.Entity.DefaultDrop(stack, itemStack -> { + ItemEntity itemEntity = new ItemEntity(this.level, this.getX(), this.getY() + (double) yOffset, this.getZ(), itemStack); // stack is copied before consumer + itemEntity.setDefaultPickUpDelay(); + this.level.addFreshEntity(itemEntity); + if (delayedAddConsumer != null) delayedAddConsumer.accept(itemEntity); + })); -+ // Paper end ++ // Paper end - Restore vanilla drops behavior return null; } // CraftBukkit end @@ -112,7 +112,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public int expToDrop; public boolean forceDrops; - public ArrayList drops = new ArrayList(); -+ public ArrayList drops = new ArrayList<>(); // Paper ++ public ArrayList drops = new ArrayList<>(); // Paper - Restore vanilla drops behavior public final org.bukkit.craftbukkit.attribute.CraftAttributeMap craftAttributes; public boolean collides = true; public Set collidableExemptions = new HashSet<>(); @@ -125,7 +125,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 protected void dropCustomDeathLoot(DamageSource source, int lootingMultiplier, boolean allowDrops) { super.dropCustomDeathLoot(source, lootingMultiplier, allowDrops); - ItemEntity entityitem = this.spawnAtLocation((ItemLike) Items.NETHER_STAR); -+ ItemEntity entityitem = this.spawnAtLocation(new net.minecraft.world.item.ItemStack(Items.NETHER_STAR), 0, ItemEntity::setExtendedLifetime); // Paper - spawnAtLocation returns null so modify the item entity with a consumer ++ ItemEntity entityitem = this.spawnAtLocation(new net.minecraft.world.item.ItemStack(Items.NETHER_STAR), 0, ItemEntity::setExtendedLifetime); // Paper - Restore vanilla drops behavior; spawnAtLocation returns null so modify the item entity with a consumer if (entityitem != null) { - entityitem.setExtendedLifetime(); @@ -142,7 +142,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } - this.drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(itemstack)); // CraftBukkit - add to drops -+ this.drops.add(new DefaultDrop(itemstack, stack -> Block.popResource(this.level(), this.blockPosition(), stack))); // CraftBukkit - add to drops // Paper - spawn drops correctly ++ this.drops.add(new DefaultDrop(itemstack, stack -> Block.popResource(this.level(), this.blockPosition(), stack))); // CraftBukkit - add to drops // Paper - Restore vanilla drops behavior return this.brokenByAnything(damageSource); // Paper } @@ -151,7 +151,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 itemstack = (ItemStack) this.handItems.get(i); if (!itemstack.isEmpty()) { - this.drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack)); // CraftBukkit - add to drops // Paper - mirror so we can destroy it later - though this call site was safe -+ this.drops.add(new DefaultDrop(itemstack, stack -> Block.popResource(this.level(), this.blockPosition().above(), stack))); // CraftBukkit - add to drops // Paper - mirror so we can destroy it later - though this call site was safe & spawn drops correctly ++ this.drops.add(new DefaultDrop(itemstack, stack -> Block.popResource(this.level(), this.blockPosition().above(), stack))); // CraftBukkit - add to drops // Paper - Restore vanilla drops behavior; mirror so we can destroy it later - though this call site was safe & spawn drops correctly this.handItems.set(i, ItemStack.EMPTY); } } @@ -160,7 +160,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 itemstack = (ItemStack) this.armorItems.get(i); if (!itemstack.isEmpty()) { - this.drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack)); // CraftBukkit - add to drops // Paper - mirror so we can destroy it later - though this call site was safe -+ this.drops.add(new DefaultDrop(itemstack, stack -> Block.popResource(this.level(), this.blockPosition().above(), stack))); // CraftBukkit - add to drops // Paper - mirror so we can destroy it later - though this call site was safe & spawn drops correctly ++ this.drops.add(new DefaultDrop(itemstack, stack -> Block.popResource(this.level(), this.blockPosition().above(), stack))); // CraftBukkit - add to drops // Paper - Restore vanilla drops behavior; mirror so we can destroy it later - though this call site was safe & spawn drops correctly this.armorItems.set(i, ItemStack.EMPTY); } } @@ -173,11 +173,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public static EntityDeathEvent callEntityDeathEvent(net.minecraft.world.entity.LivingEntity victim) { - return CraftEventFactory.callEntityDeathEvent(victim, new ArrayList(0)); -+ return CraftEventFactory.callEntityDeathEvent(victim, new ArrayList<>(0)); // Paper ++ return CraftEventFactory.callEntityDeathEvent(victim, new ArrayList<>(0)); // Paper - Restore vanilla drops behavior } - public static EntityDeathEvent callEntityDeathEvent(net.minecraft.world.entity.LivingEntity victim, List drops) { -+ public static EntityDeathEvent callEntityDeathEvent(net.minecraft.world.entity.LivingEntity victim, List drops) { // Paper ++ public static EntityDeathEvent callEntityDeathEvent(net.minecraft.world.entity.LivingEntity victim, List drops) { // Paper - Restore vanilla drops behavior // Paper start return CraftEventFactory.callEntityDeathEvent(victim, drops, com.google.common.util.concurrent.Runnables.doNothing()); } @@ -190,7 +190,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // Paper end CraftLivingEntity entity = (CraftLivingEntity) victim.getBukkitEntity(); - EntityDeathEvent event = new EntityDeathEvent(entity, drops, victim.getExpReward()); -+ EntityDeathEvent event = new EntityDeathEvent(entity, new io.papermc.paper.util.TransformingRandomAccessList<>(drops, Entity.DefaultDrop::stack, FROM_FUNCTION), victim.getExpReward()); // Paper ++ EntityDeathEvent event = new EntityDeathEvent(entity, new io.papermc.paper.util.TransformingRandomAccessList<>(drops, Entity.DefaultDrop::stack, FROM_FUNCTION), victim.getExpReward()); // Paper - Restore vanilla drops behavior populateFields(victim, event); // Paper - make cancellable CraftWorld world = (CraftWorld) entity.getWorld(); Bukkit.getServer().getPluginManager().callEvent(event); @@ -199,15 +199,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 lootCheck.run(); // Paper - advancement triggers before destroying items - for (org.bukkit.inventory.ItemStack stack : event.getDrops()) { -+ // Paper start ++ // Paper start - Restore vanilla drops behavior + for (Entity.DefaultDrop drop : drops) { + if (drop == null) continue;; + final org.bukkit.inventory.ItemStack stack = drop.stack(); -+ // Paper end ++ // Paper end - Restore vanilla drops behavior if (stack == null || stack.getType() == Material.AIR || stack.getAmount() == 0) continue; - world.dropItem(entity.getLocation(), stack); // Paper - note: dropItem already clones due to this being bukkit -> NMS -+ drop.runConsumer(world, entity.getLocation()); // Paper ++ drop.runConsumer(world, entity.getLocation()); // Paper - Restore vanilla drops behavior if (stack instanceof CraftItemStack) stack.setAmount(0); // Paper - destroy this item - if this ever leaks due to game bugs, ensure it doesn't dupe, but don't nuke bukkit stacks of manually added items } @@ -215,10 +215,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } - public static PlayerDeathEvent callPlayerDeathEvent(ServerPlayer victim, List drops, net.kyori.adventure.text.Component deathMessage, boolean keepInventory) { // Paper - Adventure -+ public static PlayerDeathEvent callPlayerDeathEvent(ServerPlayer victim, List drops, net.kyori.adventure.text.Component deathMessage, boolean keepInventory) { // Paper - Adventure & improve drops ++ public static PlayerDeathEvent callPlayerDeathEvent(ServerPlayer victim, List drops, net.kyori.adventure.text.Component deathMessage, boolean keepInventory) { // Paper - Adventure & Restore vanilla drops behavior CraftPlayer entity = victim.getBukkitEntity(); - PlayerDeathEvent event = new PlayerDeathEvent(entity, drops, victim.getExpReward(), 0, deathMessage); -+ PlayerDeathEvent event = new PlayerDeathEvent(entity, new io.papermc.paper.util.TransformingRandomAccessList<>(drops, Entity.DefaultDrop::stack, FROM_FUNCTION), victim.getExpReward(), 0, deathMessage); // Paper - improve drops ++ PlayerDeathEvent event = new PlayerDeathEvent(entity, new io.papermc.paper.util.TransformingRandomAccessList<>(drops, Entity.DefaultDrop::stack, FROM_FUNCTION), victim.getExpReward(), 0, deathMessage); // Paper - Restore vanilla drops behavior event.setKeepInventory(keepInventory); event.setKeepLevel(victim.keepLevel); // SPIGOT-2222: pre-set keepLevel populateFields(victim, event); // Paper - make cancellable @@ -227,15 +227,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 victim.newExp = event.getNewExp(); - for (org.bukkit.inventory.ItemStack stack : event.getDrops()) { -+ // Paper start ++ // Paper start - Restore vanilla drops behavior + for (Entity.DefaultDrop drop : drops) { + if (drop == null) continue; + final org.bukkit.inventory.ItemStack stack = drop.stack(); -+ // Paper end ++ // Paper end - Restore vanilla drops behavior if (stack == null || stack.getType() == Material.AIR) continue; - world.dropItem(entity.getLocation(), stack); -+ drop.runConsumer(world, entity.getLocation()); // Paper ++ drop.runConsumer(world, entity.getLocation()); // Paper - Restore vanilla drops behavior } return event; diff --git a/patches/server/Validate-ResourceLocation-in-NBT-reading.patch b/patches/server/Validate-ResourceLocation-in-NBT-reading.patch index 2350d97074..07d80420e1 100644 --- a/patches/server/Validate-ResourceLocation-in-NBT-reading.patch +++ b/patches/server/Validate-ResourceLocation-in-NBT-reading.patch @@ -17,7 +17,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper start - Validate resource location + ResourceLocation resourceLocation = ResourceLocation.tryParse(nbt.getString("Name")); + Optional> optional = resourceLocation != null ? blockLookup.get(ResourceKey.create(Registries.BLOCK, resourceLocation)) : Optional.empty(); -+ // Paper end ++ // Paper end - Validate resource location if (optional.isEmpty()) { return Blocks.AIR.defaultBlockState(); } else {