diff --git a/paper-server/patches/sources/net/minecraft/world/level/Level.java.patch b/paper-server/patches/sources/net/minecraft/world/level/Level.java.patch index 62c9a13d52..0a4453e024 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/Level.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/Level.java.patch @@ -303,7 +303,7 @@ + // Paper start - if loaded @Nullable -+ @Override + @Override + public final ChunkAccess getChunkIfLoadedImmediately(int x, int z) { + return ((ServerLevel)this).chunkSource.getChunkAtIfLoadedImmediately(x, z); + } @@ -356,7 +356,7 @@ + return getWorldBorder().isWithinBounds(blockposition) ? getBlockStateIfLoaded(blockposition) : null; + } + - @Override ++ @Override public ChunkAccess getChunk(int chunkX, int chunkZ, ChunkStatus leastStatus, boolean create) { + // Paper end ChunkAccess ichunkaccess = this.getChunkSource().getChunk(chunkX, chunkZ, leastStatus, create); @@ -523,7 +523,7 @@ public void onBlockStateChange(BlockPos pos, BlockState oldBlock, BlockState newBlock) {} @Override -@@ -270,9 +591,26 @@ +@@ -270,15 +591,33 @@ return false; } else { FluidState fluid = this.getFluidState(pos); @@ -552,7 +552,15 @@ } if (drop) { -@@ -340,10 +678,18 @@ + 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); // 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); +@@ -340,10 +679,18 @@ @Override public BlockState getBlockState(BlockPos pos) { @@ -572,7 +580,7 @@ return chunk.getBlockState(pos); } -@@ -446,34 +792,53 @@ +@@ -446,34 +793,53 @@ this.pendingBlockEntityTickers.clear(); } @@ -624,26 +632,26 @@ + entity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD); + // Paper end - Prevent block entity and entity crashes } -+ } + } + // Paper start - Option to prevent armor stands from doing entity lookups + @Override + public boolean noCollision(@Nullable Entity entity, AABB box) { + if (entity instanceof net.minecraft.world.entity.decoration.ArmorStand && !entity.level().paperConfig().entities.armorStands.doCollisionEntityLookups) return false; + return LevelAccessor.super.noCollision(entity, box); - } ++ } + // Paper end - Option to prevent armor stands from doing entity lookups public boolean shouldTickDeath(Entity entity) { return true; -@@ -510,13 +875,32 @@ +@@ -510,13 +876,32 @@ @Nullable @Override public BlockEntity getBlockEntity(BlockPos pos) { - return this.isOutsideBuildHeight(pos) ? null : (!this.isClientSide && Thread.currentThread() != this.thread ? null : this.getChunkAt(pos).getBlockEntity(pos, LevelChunk.EntityCreationType.IMMEDIATE)); + // CraftBukkit start + return this.getBlockEntity(pos, true); -+ } -+ + } + + @Nullable + public BlockEntity getBlockEntity(BlockPos blockposition, boolean validate) { + // Paper start - Perf: Optimize capturedTileEntities lookup @@ -654,8 +662,8 @@ + // Paper end - Perf: Optimize capturedTileEntities lookup + // CraftBukkit end + return this.isOutsideBuildHeight(blockposition) ? null : (!this.isClientSide && Thread.currentThread() != this.thread ? null : this.getChunkAt(blockposition).getBlockEntity(blockposition, LevelChunk.EntityCreationType.IMMEDIATE)); - } - ++ } ++ public void setBlockEntity(BlockEntity blockEntity) { BlockPos blockposition = blockEntity.getBlockPos(); @@ -669,7 +677,7 @@ this.getChunkAt(blockposition).addAndRegisterBlockEntity(blockEntity); } } -@@ -643,7 +1027,7 @@ +@@ -643,7 +1028,7 @@ for (int k = 0; k < j; ++k) { EnderDragonPart entitycomplexpart = aentitycomplexpart[k]; @@ -678,7 +686,7 @@ if (t0 != null && predicate.test(t0)) { result.add(t0); -@@ -912,7 +1296,7 @@ +@@ -912,7 +1297,7 @@ public static enum ExplosionInteraction implements StringRepresentable { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/Block.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/Block.java.patch index 18672557ed..8b81b9c548 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/Block.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/Block.java.patch @@ -1,8 +1,11 @@ --- a/net/minecraft/world/level/block/Block.java +++ b/net/minecraft/world/level/block/Block.java -@@ -295,6 +295,24 @@ - - } +@@ -292,15 +292,41 @@ + }); + state.spawnAfterBreak((ServerLevel) world, pos, ItemStack.EMPTY, true); + } ++ ++ } + // Paper start - Add BlockBreakBlockEvent + public static boolean dropResources(BlockState state, LevelAccessor levelAccessor, BlockPos pos, @Nullable BlockEntity blockEntity, BlockPos source) { @@ -11,21 +14,36 @@ + for (ItemStack drop : Block.getDrops(state, serverLevel, pos, blockEntity)) { + items.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(drop)); + } ++ 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(levelAccessor, pos), org.bukkit.craftbukkit.block.CraftBlock.at(levelAccessor, source), items); ++ event.setExpToDrop(block.getExpDrop(state, serverLevel, pos, net.minecraft.world.item.ItemStack.EMPTY, true)); // Paper - Properly handle xp dropping + event.callEvent(); + for (org.bukkit.inventory.ItemStack drop : event.getDrops()) { + popResource(serverLevel, pos, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(drop)); + } -+ state.spawnAfterBreak(serverLevel, pos, ItemStack.EMPTY, true); ++ state.spawnAfterBreak(serverLevel, pos, ItemStack.EMPTY, false); // Paper - Properly handle xp dropping ++ block.popExperience(serverLevel, pos, event.getExpToDrop()); // Paper - Properly handle xp dropping + } + return true; -+ } + } + // Paper end - Add BlockBreakBlockEvent -+ + public static void dropResources(BlockState state, Level world, BlockPos pos, @Nullable BlockEntity blockEntity, @Nullable Entity entity, ItemStack tool) { ++ // 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 - Properly handle xp dropping if (world instanceof ServerLevel) { Block.getDrops(state, (ServerLevel) world, pos, blockEntity, entity, tool).forEach((itemstack1) -> { -@@ -340,7 +358,13 @@ + Block.popResource(world, pos, itemstack1); + }); +- state.spawnAfterBreak((ServerLevel) world, pos, tool, true); ++ state.spawnAfterBreak((ServerLevel) world, pos, tool, dropExperience); // Paper - Properly handle xp dropping + } + + } +@@ -340,7 +366,13 @@ ItemEntity entityitem = (ItemEntity) itemEntitySupplier.get(); entityitem.setDefaultPickUpDelay(); @@ -40,7 +58,7 @@ return; } } -@@ -348,8 +372,13 @@ +@@ -348,8 +380,13 @@ } public void popExperience(ServerLevel world, BlockPos pos, int size) { @@ -55,7 +73,7 @@ } } -@@ -367,10 +396,18 @@ +@@ -367,10 +404,18 @@ return this.defaultBlockState(); } @@ -68,14 +86,15 @@ + // Paper end - fix drops not preventing stats/food exhaustion player.awardStat(Stats.BLOCK_MINED.get(this)); - player.causeFoodExhaustion(0.005F); +- Block.dropResources(state, world, pos, blockEntity, player, tool); + player.causeFoodExhaustion(0.005F, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.BLOCK_MINED); // CraftBukkit - EntityExhaustionEvent + if (includeDrops) { // Paper - fix drops not preventing stats/food exhaustion - Block.dropResources(state, world, pos, blockEntity, player, tool); ++ Block.dropResources(state, world, pos, blockEntity, player, tool, dropExp); // Paper - Properly handle xp dropping + } // Paper - fix drops not preventing stats/food exhaustion } public void setPlacedBy(Level world, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack itemStack) {} -@@ -490,15 +527,35 @@ +@@ -490,15 +535,35 @@ return this.builtInRegistryHolder; } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/state/BlockBehaviour.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/state/BlockBehaviour.java.patch index 0715e14829..f250348594 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/state/BlockBehaviour.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/state/BlockBehaviour.java.patch @@ -132,7 +132,15 @@ public void onRemove(Level world, BlockPos pos, BlockState state, boolean moved) { this.getBlock().onRemove(this.asState(), world, pos, state, moved); } -@@ -1250,11 +1280,11 @@ +@@ -1154,6 +1184,7 @@ + + 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 - Properly handle xp dropping + } + + public List<ItemStack> getDrops(LootParams.Builder builder) { +@@ -1250,11 +1281,11 @@ return this.getBlock().builtInRegistryHolder().is(key); } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java index 6dceb60825..5cb69d0b82 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java @@ -509,7 +509,7 @@ public class CraftBlock implements Block { // 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 - Properly handle xp dropping // Paper start - improve Block#breanNaturally if (triggerEffect) { if (iblockdata.getBlock() instanceof net.minecraft.world.level.block.BaseFireBlock) {