diff --git a/patches/api/0004-Add-BlockDestroyedByNeighborEvent.patch b/patches/api/0004-Add-BlockDestroyedByNeighborEvent.patch new file mode 100644 index 000000000..5af46af19 --- /dev/null +++ b/patches/api/0004-Add-BlockDestroyedByNeighborEvent.patch @@ -0,0 +1,79 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Cryptite +Date: Sun, 26 Sep 2021 09:00:51 -0500 +Subject: [PATCH] Add BlockDestroyedByNeighborEvent + + +diff --git a/src/main/java/io/papermc/paper/event/block/BlockDestroyedByNeighborEvent.java b/src/main/java/io/papermc/paper/event/block/BlockDestroyedByNeighborEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..7db2789d54a609b023ea6deff87b45d717aabbf0 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/event/block/BlockDestroyedByNeighborEvent.java +@@ -0,0 +1,67 @@ ++package io.papermc.paper.event.block; ++ ++import org.bukkit.block.Block; ++import org.bukkit.entity.Player; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.block.BlockEvent; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++/** ++ * Called when a block is broken another block. This is generally the result of BlockPhysicsEvent propagation ++ */ ++public class BlockDestroyedByNeighborEvent extends BlockEvent implements Cancellable { ++ private static final HandlerList handlers = new HandlerList(); ++ private final Player player; ++ private final Block sourceBlock; ++ private boolean cancel; ++ ++ public BlockDestroyedByNeighborEvent(@NotNull final Block theBlock, @Nullable Player player, @NotNull final Block sourceBlock) { ++ super(theBlock); ++ ++ this.player = player; ++ this.sourceBlock = sourceBlock; ++ } ++ ++ /** ++ * Gets the Player that caused this ++ * ++ * @return The Player that is breaking the block involved in this event ++ */ ++ @Nullable ++ public Player getPlayer() { ++ return player; ++ } ++ ++ /** ++ * Gets the source block that caused this block break ++ * ++ * @return The Source Block which block is involved in this event ++ */ ++ @NotNull ++ public final Block getSourceBlock() { ++ return sourceBlock; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return cancel; ++ } ++ ++ @Override ++ public void setCancelled(boolean cancel) { ++ this.cancel = cancel; ++ } ++ ++ @Override ++ @NotNull ++ public HandlerList getHandlers() { ++ return handlers; ++ } ++ ++ @NotNull ++ public static HandlerList getHandlerList() { ++ return handlers; ++ } ++} diff --git a/patches/server/0006-Don-t-send-equipment-updates-if-only-durability-chan.patch b/patches/server/0005-Don-t-send-equipment-updates-if-only-durability-chan.patch similarity index 100% rename from patches/server/0006-Don-t-send-equipment-updates-if-only-durability-chan.patch rename to patches/server/0005-Don-t-send-equipment-updates-if-only-durability-chan.patch diff --git a/patches/server/0007-Allow-opening-covered-chests.patch b/patches/server/0006-Allow-opening-covered-chests.patch similarity index 100% rename from patches/server/0007-Allow-opening-covered-chests.patch rename to patches/server/0006-Allow-opening-covered-chests.patch diff --git a/patches/server/0008-Don-t-send-fire-packets-if-player-has-Fire-Resistanc.patch b/patches/server/0007-Don-t-send-fire-packets-if-player-has-Fire-Resistanc.patch similarity index 100% rename from patches/server/0008-Don-t-send-fire-packets-if-player-has-Fire-Resistanc.patch rename to patches/server/0007-Don-t-send-fire-packets-if-player-has-Fire-Resistanc.patch diff --git a/patches/server/0008-Track-Player-throughout-entire-block-destroy.patch b/patches/server/0008-Track-Player-throughout-entire-block-destroy.patch new file mode 100644 index 000000000..d8394b87b --- /dev/null +++ b/patches/server/0008-Track-Player-throughout-entire-block-destroy.patch @@ -0,0 +1,78 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Cryptite +Date: Sun, 26 Sep 2021 08:47:23 -0500 +Subject: [PATCH] Track Player throughout entire block destroy + + +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java +index 1c83fbc96a074c85a3e349e936ff1f3198596709..5857468333c17cf3056ad71490746afba4154452 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java +@@ -409,6 +409,7 @@ public class ServerPlayerGameMode { + org.bukkit.block.BlockState state = bblock.getState(); + level.captureDrops = new ArrayList<>(); + // CraftBukkit end ++ level.pendingPlayerBlockEvents.put(pos, new Level.PendingBlockEvent(pos, this.player)); // Paper + block.playerWillDestroy((Level) this.level, pos, iblockdata, (Player) this.player); + boolean flag = this.level.removeBlock(pos, false); + +@@ -433,6 +434,7 @@ public class ServerPlayerGameMode { + // CraftBukkit start + java.util.List itemsToDrop = level.captureDrops; // Paper - store current list + level.captureDrops = null; // Paper - Remove this earlier so that we can actually drop stuff ++ level.pendingPlayerBlockEvents.remove(pos); // Paper + if (event.isDropItems()) { + org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDropItemEvent(bblock, state, this.player, itemsToDrop); // Paper - use stored ref + } +diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java +index 3e5e358e24bd84a05785a9391526f316475e95ff..9914a92040a63b6102eb6171f058ea1c75394a84 100644 +--- a/src/main/java/net/minecraft/world/item/ItemStack.java ++++ b/src/main/java/net/minecraft/world/item/ItemStack.java +@@ -323,6 +323,7 @@ public final class ItemStack { + } + } + Item item = this.getItem(); ++ if (entityhuman != null) world.pendingPlayerBlockEvents.put(blockposition, new Level.PendingBlockEvent(blockposition, entityhuman)); // Paper + InteractionResult enuminteractionresult = item.useOn(itemactioncontext); + CompoundTag newData = this.getTagClone(); + int newCount = this.getCount(); +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 65a163d93a293e1e0a12a300d6335a700099cac2..b1b6072ffff0e1cc2e9e1a585ad882bc70697d92 100644 +--- a/src/main/java/net/minecraft/world/level/block/DoublePlantBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/DoublePlantBlock.java +@@ -104,6 +104,12 @@ public class DoublePlantBlock extends BushBlock { + BlockPos blockposition1 = pos.below(); + BlockState iblockdata1 = world.getBlockState(blockposition1); + ++ Level.PendingBlockEvent blockEvent = world.pendingPlayerBlockEvents.remove(pos); ++ if (blockEvent != null) { ++ //Would fire a future BlockDestroyedByNeighborEvent here, but must have this conditional block ++ //because it's important to remove from pendingPlayerBlockEvents ++ } ++ + if (iblockdata1.is(state.getBlock()) && iblockdata1.getValue(DoublePlantBlock.HALF) == DoubleBlockHalf.LOWER) { + BlockState iblockdata2 = iblockdata1.hasProperty(BlockStateProperties.WATERLOGGED) && (Boolean) iblockdata1.getValue(BlockStateProperties.WATERLOGGED) ? Blocks.WATER.defaultBlockState() : Blocks.AIR.defaultBlockState(); + +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 1179c62695da4dcf02590c97d8da3c6fcdbee9ef..836ecd7c8db42634c5293caafce4624d3a10f465 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 +@@ -869,6 +869,18 @@ public abstract class BlockBehaviour { + + blockposition_mutableblockposition.setWithOffset((Vec3i) pos, enumdirection); + BlockState iblockdata = world.getBlockState(blockposition_mutableblockposition); ++ ++ // Paper start - Propagate the PendingBlockEvent from the current blockPos to the next block ++ // if it will break (!canSurvive) ++ if (this.getMaterial() == Material.AIR && !iblockdata.canSurvive(world, blockposition_mutableblockposition)) { ++ Level.PendingBlockEvent blockEvent = ((Level) world).pendingPlayerBlockEvents.get(pos); ++ if (blockEvent != null) { ++ BlockPos blockPosCopy = blockposition_mutableblockposition.immutable(); ++ ((Level) world).pendingPlayerBlockEvents.put(blockPosCopy, new Level.PendingBlockEvent(blockPosCopy, blockEvent.player, pos)); ++ } ++ } ++ // Paper end ++ + BlockState iblockdata1 = iblockdata.updateShape(enumdirection.getOpposite(), this.asState(), world, blockposition_mutableblockposition, pos); + + Block.updateOrDestroy(iblockdata, iblockdata1, world, blockposition_mutableblockposition, flags, maxUpdateDepth); diff --git a/patches/server/0009-Add-BlockDestroyedByNeighborEvent.patch b/patches/server/0009-Add-BlockDestroyedByNeighborEvent.patch new file mode 100644 index 000000000..cb2c471da --- /dev/null +++ b/patches/server/0009-Add-BlockDestroyedByNeighborEvent.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Cryptite +Date: Sun, 26 Sep 2021 09:00:50 -0500 +Subject: [PATCH] Add BlockDestroyedByNeighborEvent + + +diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java +index cf1164a86eae26244e5f1655fd1cb308f8eac5db..dfbe135d819bcc13d40942454803126bddfbf27d 100644 +--- a/src/main/java/net/minecraft/world/level/Level.java ++++ b/src/main/java/net/minecraft/world/level/Level.java +@@ -608,6 +608,17 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + if (iblockdata.isAir()) { + return false; + } else { ++ // Paper start ++ PendingBlockEvent blockEvent = pendingPlayerBlockEvents.get(pos); ++ if (blockEvent != null && blockEvent.sourceBlock != null) { ++ io.papermc.paper.event.block.BlockDestroyedByNeighborEvent event = ++ new io.papermc.paper.event.block.BlockDestroyedByNeighborEvent(org.bukkit.craftbukkit.block.CraftBlock.at(this, pos), ++ (org.bukkit.entity.Player) blockEvent.player.getBukkitEntity(), ++ org.bukkit.craftbukkit.block.CraftBlock.at(this, blockEvent.sourceBlock)); ++ event.callEvent(); ++ } ++ // Paper end ++ + FluidState fluid = this.getFluidState(pos); + // Paper start - while the above setAir method is named same and looks very similar + // they are NOT used with same intent and the above should not fire this event. The above method is more of a BlockSetToAirEvent, +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 b1b6072ffff0e1cc2e9e1a585ad882bc70697d92..f2eb493d99c2eb826d8b85adbc3dc6799c575f31 100644 +--- a/src/main/java/net/minecraft/world/level/block/DoublePlantBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/DoublePlantBlock.java +@@ -106,8 +106,11 @@ public class DoublePlantBlock extends BushBlock { + + Level.PendingBlockEvent blockEvent = world.pendingPlayerBlockEvents.remove(pos); + if (blockEvent != null) { +- //Would fire a future BlockDestroyedByNeighborEvent here, but must have this conditional block +- //because it's important to remove from pendingPlayerBlockEvents ++ io.papermc.paper.event.block.BlockDestroyedByNeighborEvent event = ++ new io.papermc.paper.event.block.BlockDestroyedByNeighborEvent(org.bukkit.craftbukkit.block.CraftBlock.at(world, blockposition1), ++ (org.bukkit.entity.Player) blockEvent.player.getBukkitEntity(), ++ org.bukkit.craftbukkit.block.CraftBlock.at(world, pos)); ++ if (!event.callEvent()) return; + } + + if (iblockdata1.is(state.getBlock()) && iblockdata1.getValue(DoublePlantBlock.HALF) == DoubleBlockHalf.LOWER) {