From 19a620213f0a11e9f749530f0d03c5b5584664e9 Mon Sep 17 00:00:00 2001
From: Owen <23108066+Owen1212055@users.noreply.github.com>
Date: Thu, 4 Jan 2024 15:18:59 -0500
Subject: [PATCH] Fix experience & improvements to block events (#8067)
This is a lot but basically adds a method to disable the dropping of experience and drops experience by default.
This way things that require XP to be dropped manually (via modification), they can drop XP themselves when needed but without touching anywhere else that may drop xp.
It should be noted this causes breakNaturally() to now drop experience.
---
patches/api/0168-BlockDestroyEvent.patch | 30 +++++-
.../api/0310-Add-BlockBreakBlockEvent.patch | 9 +-
...PI-for-Reason-Source-Triggering-play.patch | 10 +-
patches/server/0288-BlockDestroyEvent.patch | 14 ++-
...-Optimize-Captured-TileEntity-Lookup.patch | 4 +-
.../0365-Improved-Watchdog-Support.patch | 6 +-
.../0678-Execute-chunk-tasks-mid-tick.patch | 6 +-
.../0681-Optimise-random-block-ticking.patch | 2 +-
.../server/0717-Collision-optimisations.patch | 10 +-
...nate-Current-redstone-implementation.patch | 4 +-
...0967-Only-capture-actual-tree-growth.patch | 4 +-
...y-handle-BlockBreakEvent-isDropItems.patch | 34 +++----
...Fix-silent-equipment-change-for-mobs.patch | 4 +-
...e-experience-dropping-on-block-break.patch | 94 +++++++++++++++++++
14 files changed, 177 insertions(+), 54 deletions(-)
create mode 100644 patches/server/1061-Properly-handle-experience-dropping-on-block-break.patch
diff --git a/patches/api/0168-BlockDestroyEvent.patch b/patches/api/0168-BlockDestroyEvent.patch
index c414a4253..5046b085e 100644
--- a/patches/api/0168-BlockDestroyEvent.patch
+++ b/patches/api/0168-BlockDestroyEvent.patch
@@ -12,10 +12,10 @@ This can replace many uses of BlockPhysicsEvent
diff --git a/src/main/java/com/destroystokyo/paper/event/block/BlockDestroyEvent.java b/src/main/java/com/destroystokyo/paper/event/block/BlockDestroyEvent.java
new file mode 100644
-index 0000000000000000000000000000000000000000..051b2ef76a914228338fa28553ad739bd2a0278c
+index 0000000000000000000000000000000000000000..5465f0dc890ad8825b910c2a77fd9c0868115ebe
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/event/block/BlockDestroyEvent.java
-@@ -0,0 +1,99 @@
+@@ -0,0 +1,121 @@
+package com.destroystokyo.paper.event.block;
+
+import org.bukkit.block.Block;
@@ -23,6 +23,7 @@ index 0000000000000000000000000000000000000000..051b2ef76a914228338fa28553ad739b
+import org.bukkit.event.Cancellable;
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.block.BlockEvent;
++import org.bukkit.event.block.BlockExpEvent;
+import org.jetbrains.annotations.NotNull;
+
+/**
@@ -36,23 +37,44 @@ index 0000000000000000000000000000000000000000..051b2ef76a914228338fa28553ad739b
+ * Events such as leaves decaying, pistons retracting (where the block is moving), does NOT fire this event.
+ *
+ */
-+public class BlockDestroyEvent extends BlockEvent implements Cancellable {
++public class BlockDestroyEvent extends BlockExpEvent implements Cancellable {
+
+ private static final HandlerList handlers = new HandlerList();
+
+ @NotNull private final BlockData newState;
+ private boolean willDrop;
+ private boolean playEffect = true;
++ private BlockData effectBlock;
+
+ private boolean cancelled = false;
+
+ public BlockDestroyEvent(@NotNull Block block, @NotNull BlockData newState, boolean willDrop) {
-+ super(block);
++ super(block, 0);
+ this.newState = newState;
+ this.willDrop = willDrop;
+ }
+
+ /**
++ * Get the effect that will be played when the block is broken.
++ * @return block break effect
++ */
++ @NotNull
++ public BlockData getEffectBlock() {
++ return this.effectBlock;
++ }
++
++ /**
++ * Sets the effect that will be played when the block is broken.
++ * Note: {@link BlockDestroyEvent#playEffect()} must be true in order for this effect to be
++ * played.
++ *
++ * @param effectBlock block effect
++ */
++ public void setEffectBlock(@NotNull BlockData effectBlock) {
++ this.effectBlock = effectBlock;
++ }
++
++ /**
+ * @return The new state of this block (Air, or a Fluid type)
+ */
+ @NotNull
diff --git a/patches/api/0310-Add-BlockBreakBlockEvent.patch b/patches/api/0310-Add-BlockBreakBlockEvent.patch
index dfd13b135..3ef95aee5 100644
--- a/patches/api/0310-Add-BlockBreakBlockEvent.patch
+++ b/patches/api/0310-Add-BlockBreakBlockEvent.patch
@@ -6,15 +6,16 @@ Subject: [PATCH] Add BlockBreakBlockEvent
diff --git a/src/main/java/io/papermc/paper/event/block/BlockBreakBlockEvent.java b/src/main/java/io/papermc/paper/event/block/BlockBreakBlockEvent.java
new file mode 100644
-index 0000000000000000000000000000000000000000..ac7a60403a9e51fc194f2cc92b0bd60d8879a661
+index 0000000000000000000000000000000000000000..51129c5c90dafdba08b7f533a71448ace56381d5
--- /dev/null
+++ b/src/main/java/io/papermc/paper/event/block/BlockBreakBlockEvent.java
-@@ -0,0 +1,59 @@
+@@ -0,0 +1,60 @@
+package io.papermc.paper.event.block;
+
+import org.bukkit.block.Block;
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.block.BlockEvent;
++import org.bukkit.event.block.BlockExpEvent;
+import org.bukkit.inventory.ItemStack;
+import org.jetbrains.annotations.NotNull;
+
@@ -25,7 +26,7 @@ index 0000000000000000000000000000000000000000..ac7a60403a9e51fc194f2cc92b0bd60d
+ *
+ * Currently called for piston's and liquid flows.
+ */
-+public class BlockBreakBlockEvent extends BlockEvent {
++public class BlockBreakBlockEvent extends BlockExpEvent {
+
+ private static final HandlerList HANDLER_LIST = new HandlerList();
+
@@ -33,7 +34,7 @@ index 0000000000000000000000000000000000000000..ac7a60403a9e51fc194f2cc92b0bd60d
+ private final Block source;
+
+ public BlockBreakBlockEvent(@NotNull Block block, @NotNull Block source, @NotNull List drops) {
-+ super(block);
++ super(block, 0);
+ this.source = source;
+ this.drops = drops;
+ }
diff --git a/patches/server/0126-ExperienceOrbs-API-for-Reason-Source-Triggering-play.patch b/patches/server/0126-ExperienceOrbs-API-for-Reason-Source-Triggering-play.patch
index e0ceff545..a32b063cb 100644
--- a/patches/server/0126-ExperienceOrbs-API-for-Reason-Source-Triggering-play.patch
+++ b/patches/server/0126-ExperienceOrbs-API-for-Reason-Source-Triggering-play.patch
@@ -292,21 +292,21 @@ index 8d09c134058e55a23df4e23d965a7a783aed701e..45242f0ed5a0f98953df5f27fb76874d
world.levelEvent(1042, blockposition, 0);
diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java
-index 756a8ae14ffc46d6ebe0a858a03fb2e89b8e118a..bdf5443d5974d316b9b216291fadae4346a3123f 100644
+index 756a8ae14ffc46d6ebe0a858a03fb2e89b8e118a..89a62fbeeb78c864938a1cea84178478c6dc1b34 100644
--- a/src/main/java/net/minecraft/world/level/block/Block.java
+++ b/src/main/java/net/minecraft/world/level/block/Block.java
@@ -369,8 +369,13 @@ public class Block extends BlockBehaviour implements ItemLike {
}
public void popExperience(ServerLevel world, BlockPos pos, int size) {
-+ // Paper start - add player parameter
++ // Paper start - add entity parameter
+ popExperience(world, pos, size, null);
+ }
-+ public void popExperience(ServerLevel world, BlockPos pos, int size, net.minecraft.server.level.ServerPlayer player) {
-+ // Paper end - add player parameter
++ public void popExperience(ServerLevel world, BlockPos pos, int size, net.minecraft.world.entity.Entity entity) {
++ // Paper end - add entity parameter
if (world.getGameRules().getBoolean(GameRules.RULE_DOBLOCKDROPS)) {
- ExperienceOrb.award(world, Vec3.atCenterOf(pos), size);
-+ ExperienceOrb.award(world, Vec3.atCenterOf(pos), size, org.bukkit.entity.ExperienceOrb.SpawnReason.BLOCK_BREAK, player); // Paper
++ ExperienceOrb.award(world, Vec3.atCenterOf(pos), size, org.bukkit.entity.ExperienceOrb.SpawnReason.BLOCK_BREAK, entity); // Paper
}
}
diff --git a/patches/server/0288-BlockDestroyEvent.patch b/patches/server/0288-BlockDestroyEvent.patch
index 6b5aa51c8..65f26283b 100644
--- a/patches/server/0288-BlockDestroyEvent.patch
+++ b/patches/server/0288-BlockDestroyEvent.patch
@@ -11,7 +11,7 @@ floating in the air.
This can replace many uses of BlockPhysicsEvent
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
-index 178509c545f2872174af501bdcec3314f703739c..d315a31f6b489ee88f81eb3d1b358c92e1e1619c 100644
+index b4f7e73fa673006ad0f8ea5a8de5a825aa75e41c..3ee67624e163a8c42cc8dab70aa05021baa2574b 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -31,6 +31,7 @@ import net.minecraft.nbt.CompoundTag;
@@ -22,7 +22,7 @@ index 178509c545f2872174af501bdcec3314f703739c..d315a31f6b489ee88f81eb3d1b358c92
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.FullChunkStatus;
import net.minecraft.server.level.ServerLevel;
-@@ -669,8 +670,21 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
+@@ -669,9 +670,26 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
return false;
} else {
FluidState fluid = this.getFluidState(pos);
@@ -30,18 +30,24 @@ index 178509c545f2872174af501bdcec3314f703739c..d315a31f6b489ee88f81eb3d1b358c92
+ // they are NOT used with same intent and the above should not fire this event. The above method is more of a BlockSetToAirEvent,
+ // it doesn't imply destruction of a block that plays a sound effect / drops an item.
+ boolean playEffect = true;
++ BlockState effectType = iblockdata;
++ int xp = iblockdata.getBlock().getExpDrop(iblockdata, (ServerLevel) this, pos, ItemStack.EMPTY, true);
+ if (com.destroystokyo.paper.event.block.BlockDestroyEvent.getHandlerList().getRegisteredListeners().length > 0) {
+ com.destroystokyo.paper.event.block.BlockDestroyEvent event = new com.destroystokyo.paper.event.block.BlockDestroyEvent(MCUtil.toBukkitBlock(this, pos), fluid.createLegacyBlock().createCraftBlockData(), drop);
+ if (!event.callEvent()) {
+ return false;
+ }
++ effectType = ((CraftBlockData) event.getEffectBlock()).getState();
+ playEffect = event.playEffect();
+ drop = event.willDrop();
++ xp = event.getExpToDrop();
+ }
+ // Paper end
- if (!(iblockdata.getBlock() instanceof BaseFireBlock)) {
-+ if (playEffect && !(iblockdata.getBlock() instanceof BaseFireBlock)) { // Paper
- this.levelEvent(2001, pos, Block.getId(iblockdata));
+- this.levelEvent(2001, pos, Block.getId(iblockdata));
++ if (playEffect && !(effectType.getBlock() instanceof BaseFireBlock)) { // Paper
++ this.levelEvent(2001, pos, Block.getId(effectType)); // Paper
}
+ if (drop) {
diff --git a/patches/server/0302-Optimize-Captured-TileEntity-Lookup.patch b/patches/server/0302-Optimize-Captured-TileEntity-Lookup.patch
index d79b7937e..8f55396c3 100644
--- a/patches/server/0302-Optimize-Captured-TileEntity-Lookup.patch
+++ b/patches/server/0302-Optimize-Captured-TileEntity-Lookup.patch
@@ -10,10 +10,10 @@ Optimize to check if the captured list even has values in it, and also to
just do a get call since the value can never be null.
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
-index 041984d629b7ddd2d2a856483fd69a2ab49c804e..8e5726194870f614b1522703f42fb11861bd7b9d 100644
+index be016a6fb0fcf1dfbce3fe6aca1085fbe883abdb..fdcc6666aa9100ddcf0d23a19bcd1dda29510d3e 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
-@@ -994,9 +994,12 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
+@@ -998,9 +998,12 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
@Nullable
public BlockEntity getBlockEntity(BlockPos blockposition, boolean validate) {
diff --git a/patches/server/0365-Improved-Watchdog-Support.patch b/patches/server/0365-Improved-Watchdog-Support.patch
index f8b403470..7f3215ce5 100644
--- a/patches/server/0365-Improved-Watchdog-Support.patch
+++ b/patches/server/0365-Improved-Watchdog-Support.patch
@@ -271,7 +271,7 @@ index 109c7ff78d4c1f5496d294f52ecfd9df2070db1e..fe47a38137f7b7fa94c507e790eec4fb
}
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
-index 9036d9941b1597e14d3b25a5143d914248338800..f644c8b89e96d35fb9f2ac7941dcfcf9e8b66451 100644
+index c8a977f6dce36a254f729e97759c14e234ef6674..6d6cac755c45247e1d07e52550f6f4644536f220 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -532,7 +532,7 @@ public abstract class PlayerList {
@@ -296,10 +296,10 @@ index f5829ae484d93b547a5437b85a9621346384a11b..83701fbfaa56a232593ee8f11a3afb89
}
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
-index 934a0de16e61de967d15b001bda45a97501dc658..4a097c3cf168005e2bae3ae484bc7ebd7a19a2d2 100644
+index 571019880cd9f22f347ac8fca663728b6706912d..7d213ebc6a3d9dc15468a6cfb472306121c3ca15 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
-@@ -909,6 +909,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
+@@ -913,6 +913,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
try {
tickConsumer.accept(entity);
} catch (Throwable throwable) {
diff --git a/patches/server/0678-Execute-chunk-tasks-mid-tick.patch b/patches/server/0678-Execute-chunk-tasks-mid-tick.patch
index d42293cee..d11ebf316 100644
--- a/patches/server/0678-Execute-chunk-tasks-mid-tick.patch
+++ b/patches/server/0678-Execute-chunk-tasks-mid-tick.patch
@@ -151,10 +151,10 @@ index a885b90a44066103133af953d56bb3dbb9b899be..2c759854ed9f78c48c4e9ed2dc72e5a5
}
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
-index e939b572c4e9bb316b342cdadf116942f04f53b2..17b7f100979042ef33e18ab930a0935e4cfaa674 100644
+index 73d3eff15c3faea7716beb5b53d66af434005d0f..cddac4571578ac8d647f3f4b20fb6f7b773aabe3 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
-@@ -923,6 +923,11 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
+@@ -927,6 +927,11 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
// Spigot end
} else if (flag && this.shouldTickBlocksAt(tickingblockentity.getPos())) {
tickingblockentity.tick();
@@ -166,7 +166,7 @@ index e939b572c4e9bb316b342cdadf116942f04f53b2..17b7f100979042ef33e18ab930a0935e
}
}
this.blockEntityTickers.removeAll(toRemove);
-@@ -937,6 +942,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
+@@ -941,6 +946,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
public void guardEntityTick(Consumer tickConsumer, T entity) {
try {
tickConsumer.accept(entity);
diff --git a/patches/server/0681-Optimise-random-block-ticking.patch b/patches/server/0681-Optimise-random-block-ticking.patch
index 695231a1d..112c88e4d 100644
--- a/patches/server/0681-Optimise-random-block-ticking.patch
+++ b/patches/server/0681-Optimise-random-block-ticking.patch
@@ -327,7 +327,7 @@ diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/
index 17b7f100979042ef33e18ab930a0935e4cfaa674..c438c75b8edfbb8d728b01a96882e6cd802a3bea 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
-@@ -1394,10 +1394,18 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
+@@ -1398,10 +1398,18 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
public abstract RecipeManager getRecipeManager();
public BlockPos getBlockRandomPos(int x, int y, int z, int l) {
diff --git a/patches/server/0717-Collision-optimisations.patch b/patches/server/0717-Collision-optimisations.patch
index 5b51e21cb..380f7a085 100644
--- a/patches/server/0717-Collision-optimisations.patch
+++ b/patches/server/0717-Collision-optimisations.patch
@@ -2179,7 +2179,7 @@ index d0a8092bf57a29ab7c00ec0ddf52a9fdb2a33267..392406722b0a040c1d41fdc1154d75d3
private Direction(int id, int idOpposite, int idHorizontal, String name, Direction.AxisDirection direction, Direction.Axis axis, Vec3i vector) {
this.data3d = id;
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
-index 45f2a81cd59434956cc33e489af6032e6ef9947d..29da0b80aa0a4e6ebf1f0e30c26a6b85f034e8e4 100644
+index 60164d8ff63bf536ddf46605a9dc7931ebc5b82a..7c8f5ae6bd83bd08403738dcd364b0af06fb1a9b 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -469,7 +469,7 @@ public class ServerPlayer extends Player {
@@ -2201,7 +2201,7 @@ index 45f2a81cd59434956cc33e489af6032e6ef9947d..29da0b80aa0a4e6ebf1f0e30c26a6b85
}
}
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
-index 53dbfb828f4d6f47b87e7ff6829a8dbc3de2f0fd..30ad9f878d0b76c6bef594448c3122d614a7aa8c 100644
+index 159932e2807c8d51fbf141c2145a138a39ea8abe..41a5d509a398972db910d32babb70e9bd5fa41da 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -911,7 +911,7 @@ public abstract class PlayerList {
@@ -2600,7 +2600,7 @@ index a25497eec004add7408a63b1a0f09e3fa443b324..9f892de55ab03367daed4c30cc44c9dd
// Paper start
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
-index 0bf3bfd0a44fe7219e6ed451eb85c25e87a31aac..3dfc42dfed0429ea46238ede127b86a0c7756659 100644
+index 126d37e14ff785c17e45d4601131156593f5ace5..096cd97827f4912fc5b538e01d29257195270055 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -300,6 +300,10 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
@@ -2985,7 +2985,7 @@ index 0bf3bfd0a44fe7219e6ed451eb85c25e87a31aac..3dfc42dfed0429ea46238ede127b86a0
@Override
public boolean isClientSide() {
return this.isClientSide;
-@@ -957,7 +1325,17 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
+@@ -961,7 +1329,17 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
@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;
@@ -3005,7 +3005,7 @@ index 0bf3bfd0a44fe7219e6ed451eb85c25e87a31aac..3dfc42dfed0429ea46238ede127b86a0
// Paper end
diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java
-index f0a85f1b48a911ffd8740df5ebe869e8f0371a58..7ac98b4e8b6dcc23777732d377ee73ae5671ebef 100644
+index 49aa9020290e4466eb386400b4a6e5284cfe355b..5343a0c20cf87067ba307f001a28b0b18fae2c34 100644
--- a/src/main/java/net/minecraft/world/level/block/Block.java
+++ b/src/main/java/net/minecraft/world/level/block/Block.java
@@ -284,7 +284,7 @@ public class Block extends BlockBehaviour implements ItemLike {
diff --git a/patches/server/0806-Add-Alternate-Current-redstone-implementation.patch b/patches/server/0806-Add-Alternate-Current-redstone-implementation.patch
index 51458c3c4..cb2ce69dc 100644
--- a/patches/server/0806-Add-Alternate-Current-redstone-implementation.patch
+++ b/patches/server/0806-Add-Alternate-Current-redstone-implementation.patch
@@ -2034,10 +2034,10 @@ index 9e0fb3a13cd4ae0142e3e63995b7eac61e48eea6..8587f35706daf5a317035d0f7acee0b3
EntityCallbacks() {}
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
-index b4c4e90994f8872c2f648389c7de0dd31a874085..cdd8cedc524ddbd0332b7198c78f65dff59423bc 100644
+index 096cd97827f4912fc5b538e01d29257195270055..6ad9e4da7fd9d8b4e482928295b51e13170ed6b9 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
-@@ -1881,4 +1881,15 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
+@@ -1885,4 +1885,15 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
return range <= 0 ? 64.0 * 64.0 : range * range; // 64 is taken from default in ServerLevel#levelEvent
}
// Paper end - respect global sound events gamerule
diff --git a/patches/server/0967-Only-capture-actual-tree-growth.patch b/patches/server/0967-Only-capture-actual-tree-growth.patch
index bd43e01cd..df56cb240 100644
--- a/patches/server/0967-Only-capture-actual-tree-growth.patch
+++ b/patches/server/0967-Only-capture-actual-tree-growth.patch
@@ -29,10 +29,10 @@ index db523ded8132f2010391c9f909319d0ae042a741..852727221d5cb8bcc14c57664622c13d
}
entityhuman.awardStat(Stats.ITEM_USED.get(item)); // SPIGOT-7236 - award stat
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
-index 013a6c551958af4c41814f66948998aff4842d52..1d8ad95f4fbf77b1c94be9bbe5aeb18601156765 100644
+index 9bcbc7ca5da57aa80dacaa89c1af51fab3548152..6e46124d67b6c25155a9942b04c09f3dc946a249 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
-@@ -1894,4 +1894,11 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
+@@ -1898,4 +1898,11 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
return null;
}
// Paper end - optimize redstone (Alternate Current)
diff --git a/patches/server/0980-Properly-handle-BlockBreakEvent-isDropItems.patch b/patches/server/0980-Properly-handle-BlockBreakEvent-isDropItems.patch
index 8808e90bd..f180ec4e5 100644
--- a/patches/server/0980-Properly-handle-BlockBreakEvent-isDropItems.patch
+++ b/patches/server/0980-Properly-handle-BlockBreakEvent-isDropItems.patch
@@ -9,7 +9,7 @@ food consumption, turtle egg count decreases, ice to water
conversions and beehive releases
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
-index 82f26186156a487f29ad3abff3f68852e5b8a1f9..511221a686c1d2cad3b4abf79ee32b26058dad27 100644
+index 82f26186156a487f29ad3abff3f68852e5b8a1f9..e2764751aaa862e3e0c21cf9a8ab66ed921c65e5 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
@@ -433,8 +433,8 @@ public class ServerPlayerGameMode {
@@ -19,12 +19,12 @@ index 82f26186156a487f29ad3abff3f68852e5b8a1f9..511221a686c1d2cad3b4abf79ee32b26
- if (flag && flag1 && event.isDropItems()) { // CraftBukkit - Check if block should drop items
- block.playerDestroy(this.level, this.player, pos, iblockdata1, tileentity, itemstack1);
+ if (flag && flag1 && event.isDropItems()/* && event.isDropItems() */) { // CraftBukkit - Check if block should drop items // Paper - fix drops not preventing stats/food exhaustion
-+ block.playerDestroy(this.level, this.player, pos, iblockdata1, tileentity, itemstack1, event.isDropItems()); // Paper
++ block.playerDestroy(this.level, this.player, pos, iblockdata1, tileentity, itemstack1, event.isDropItems(), false); // Paper
}
// return true; // CraftBukkit
diff --git a/src/main/java/net/minecraft/world/level/block/BeehiveBlock.java b/src/main/java/net/minecraft/world/level/block/BeehiveBlock.java
-index 6e7a9f68aa3a5084c8eea9fd8721272260734289..7d1f3c367efcf8def56b961993136e02e05ba59c 100644
+index 6e7a9f68aa3a5084c8eea9fd8721272260734289..2594c8e233114b21e5b00acb5ad7012b004a0ef2 100644
--- a/src/main/java/net/minecraft/world/level/block/BeehiveBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/BeehiveBlock.java
@@ -84,8 +84,8 @@ public class BeehiveBlock extends BaseEntityBlock {
@@ -33,13 +33,13 @@ index 6e7a9f68aa3a5084c8eea9fd8721272260734289..7d1f3c367efcf8def56b961993136e02
@Override
- public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool) {
- super.playerDestroy(world, player, pos, state, blockEntity, tool);
-+ public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool, boolean includeDrops) { // Paper
-+ super.playerDestroy(world, player, pos, state, blockEntity, tool, includeDrops); // Paper
++ public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool, boolean includeDrops, boolean dropExp) { // Paper
++ super.playerDestroy(world, player, pos, state, blockEntity, tool, includeDrops, dropExp); // Paper
if (!world.isClientSide && blockEntity instanceof BeehiveBlockEntity) {
BeehiveBlockEntity tileentitybeehive = (BeehiveBlockEntity) blockEntity;
diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java
-index 7ac98b4e8b6dcc23777732d377ee73ae5671ebef..4d50dd92a7f3187ee1d8edb926e7c273c8156549 100644
+index 5343a0c20cf87067ba307f001a28b0b18fae2c34..0011bbb22fcfba267818c55b03042db5e67be562 100644
--- a/src/main/java/net/minecraft/world/level/block/Block.java
+++ b/src/main/java/net/minecraft/world/level/block/Block.java
@@ -423,10 +423,18 @@ public class Block extends BlockBehaviour implements ItemLike {
@@ -49,9 +49,9 @@ index 7ac98b4e8b6dcc23777732d377ee73ae5671ebef..4d50dd92a7f3187ee1d8edb926e7c273
+ @io.papermc.paper.annotation.DoNotUse // Paper - method below allows better control of item drops
public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool) {
+ // Paper start
-+ this.playerDestroy(world, player, pos, state, blockEntity, tool, true);
++ this.playerDestroy(world, player, pos, state, blockEntity, tool, true, true);
+ }
-+ public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool, boolean includeDrops) {
++ public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool, boolean includeDrops, boolean dropExp) {
+ // Paper end
player.awardStat(Stats.BLOCK_MINED.get(this));
player.causeFoodExhaustion(0.005F, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.BLOCK_MINED); // CraftBukkit - EntityExhaustionEvent
@@ -62,7 +62,7 @@ index 7ac98b4e8b6dcc23777732d377ee73ae5671ebef..4d50dd92a7f3187ee1d8edb926e7c273
public void setPlacedBy(Level world, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack itemStack) {}
diff --git a/src/main/java/net/minecraft/world/level/block/DoublePlantBlock.java b/src/main/java/net/minecraft/world/level/block/DoublePlantBlock.java
-index 0f0750f8c790d0db72a0e6b277449a1461674890..81d2140351775ad55546af52eb635ccdc8509d89 100644
+index 0f0750f8c790d0db72a0e6b277449a1461674890..a6a257027d60bfda8cb975eca7f255fb1bd1e8d5 100644
--- a/src/main/java/net/minecraft/world/level/block/DoublePlantBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/DoublePlantBlock.java
@@ -96,8 +96,8 @@ public class DoublePlantBlock extends BushBlock {
@@ -71,13 +71,13 @@ index 0f0750f8c790d0db72a0e6b277449a1461674890..81d2140351775ad55546af52eb635ccd
@Override
- public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool) {
- super.playerDestroy(world, player, pos, Blocks.AIR.defaultBlockState(), blockEntity, tool);
-+ public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool, boolean includeDrops) { // Paper
-+ super.playerDestroy(world, player, pos, Blocks.AIR.defaultBlockState(), blockEntity, tool, includeDrops); // Paper
++ public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool, boolean includeDrops, boolean dropExp) { // Paper
++ super.playerDestroy(world, player, pos, Blocks.AIR.defaultBlockState(), blockEntity, tool, includeDrops, dropExp); // Paper
}
protected static void preventDropFromBottomPart(Level world, BlockPos pos, BlockState state, Player player) {
diff --git a/src/main/java/net/minecraft/world/level/block/IceBlock.java b/src/main/java/net/minecraft/world/level/block/IceBlock.java
-index f05998e0af1e844f19bf86b74f652a9901088c37..4ab6997dad5b112f5105f786a6cee78c6c5667e8 100644
+index f05998e0af1e844f19bf86b74f652a9901088c37..9ebe74e235d425fde985a6180857dc4039ecfedf 100644
--- a/src/main/java/net/minecraft/world/level/block/IceBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/IceBlock.java
@@ -33,8 +33,8 @@ public class IceBlock extends HalfTransparentBlock {
@@ -86,13 +86,13 @@ index f05998e0af1e844f19bf86b74f652a9901088c37..4ab6997dad5b112f5105f786a6cee78c
@Override
- public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool) {
- super.playerDestroy(world, player, pos, state, blockEntity, tool);
-+ public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool, boolean includeDrops) { // Paper
-+ super.playerDestroy(world, player, pos, state, blockEntity, tool, includeDrops); // Paper
++ public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool, boolean includeDrops, boolean dropExp) { // Paper
++ super.playerDestroy(world, player, pos, state, blockEntity, tool, includeDrops, dropExp); // Paper
// Paper start
this.afterDestroy(world, pos, tool);
}
diff --git a/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java b/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java
-index c79f3a8885a5ffc9ebac51992e63df14929d9f24..b0199e071cba4c7ad51799132d00b22b616953fc 100644
+index c79f3a8885a5ffc9ebac51992e63df14929d9f24..5c0127ecbbafd406f450f8707c4563bfea7a0214 100644
--- a/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/TurtleEggBlock.java
@@ -173,8 +173,8 @@ public class TurtleEggBlock extends Block {
@@ -101,8 +101,8 @@ index c79f3a8885a5ffc9ebac51992e63df14929d9f24..b0199e071cba4c7ad51799132d00b22b
@Override
- public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool) {
- super.playerDestroy(world, player, pos, state, blockEntity, tool);
-+ public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool, boolean includeDrops) { // Paper
-+ super.playerDestroy(world, player, pos, state, blockEntity, tool, includeDrops); // Paper
++ public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool, boolean includeDrops, boolean dropExp) { // Paper
++ super.playerDestroy(world, player, pos, state, blockEntity, tool, includeDrops, dropExp); // Paper
this.decreaseEggs(world, pos, state);
}
diff --git a/patches/server/1004-Fix-silent-equipment-change-for-mobs.patch b/patches/server/1004-Fix-silent-equipment-change-for-mobs.patch
index 2812d9c2d..2b994e5be 100644
--- a/patches/server/1004-Fix-silent-equipment-change-for-mobs.patch
+++ b/patches/server/1004-Fix-silent-equipment-change-for-mobs.patch
@@ -47,10 +47,10 @@ index 8e9469fec42f7b6a132cf173f6f5a95777a29b3b..b319021b22c5dceba6199ed27814b2dc
this.reassessWeaponGoal();
}
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
-index 1d8ad95f4fbf77b1c94be9bbe5aeb18601156765..8848eeda7a89d445e370626182f9bb4710e5edd4 100644
+index 6e46124d67b6c25155a9942b04c09f3dc946a249..cdd03a1602cef13d2e62e6a6655ec2929e0d590f 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
-@@ -1896,7 +1896,10 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
+@@ -1900,7 +1900,10 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
// Paper end - optimize redstone (Alternate Current)
// Paper start - notify observers even if grow failed
public void checkCapturedTreeStateForObserverNotify(final BlockPos pos, final CraftBlockState craftBlockState) {
diff --git a/patches/server/1061-Properly-handle-experience-dropping-on-block-break.patch b/patches/server/1061-Properly-handle-experience-dropping-on-block-break.patch
new file mode 100644
index 000000000..24147f07c
--- /dev/null
+++ b/patches/server/1061-Properly-handle-experience-dropping-on-block-break.patch
@@ -0,0 +1,94 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
+Date: Sat, 30 Dec 2023 15:00:06 -0500
+Subject: [PATCH] Properly handle experience dropping on block break
+
+This causes spawnAfterBreak to spawn xp by default, removing the need to manually add xp wherever this method is used.
+For classes that use custom xp amounts, they can drop the resources with disabling
+
+diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
+index 380b6bc69429ec8bd92f0adf90b02028fec23d52..c7021d31fe392536efdfbf08b7e7df834d3d8a98 100644
+--- a/src/main/java/net/minecraft/world/level/Level.java
++++ b/src/main/java/net/minecraft/world/level/Level.java
+@@ -1103,7 +1103,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
+ if (drop) {
+ 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
+ }
+
+ boolean flag1 = this.setBlock(pos, fluid.createLegacyBlock(), 3, maxUpdateDepth);
+diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java
+index 0011bbb22fcfba267818c55b03042db5e67be562..c390fe88a6756e6759050d88e3c6df2b0e0efaed 100644
+--- a/src/main/java/net/minecraft/world/level/block/Block.java
++++ b/src/main/java/net/minecraft/world/level/block/Block.java
+@@ -333,23 +333,31 @@ public class Block extends BlockBehaviour implements ItemLike {
+ 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();
+ 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.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());
+ }
+ return true;
+ }
+ // Paper end
+
+ public static void dropResources(BlockState state, Level world, BlockPos pos, @Nullable BlockEntity blockEntity, @Nullable Entity entity, ItemStack tool) {
++ // Paper start
++ 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
+ 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
+ }
+
+ }
+@@ -433,7 +441,7 @@ public class Block extends BlockBehaviour implements ItemLike {
+ player.awardStat(Stats.BLOCK_MINED.get(this));
+ 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
+ } // Paper
+ }
+
+diff --git a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java
+index 3ab8b99837b1d1faea722c598b0228b2780be8b1..401f1b418a4f57059e991cc958ebadb31239a581 100644
+--- a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java
++++ b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java
+@@ -1286,6 +1286,7 @@ public abstract class BlockBehaviour implements FeatureElement {
+
+ 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
+ }
+
+ public List getDrops(LootParams.Builder builder) {
+diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
+index e5506a7d074a9f89d41f4d5d7549a458779bef20..520b53bc604e6755251f0b14e91dce56bc5501ce 100644
+--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
+@@ -503,7 +503,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
+ // Paper start - improve Block#breanNaturally
+ if (triggerEffect) {
+ if (iblockdata.getBlock() instanceof net.minecraft.world.level.block.BaseFireBlock) {