From 969e0a9bb7b7b170e3bb238b3140220ce92eb331 Mon Sep 17 00:00:00 2001 From: Jake Potrebic Date: Sat, 16 Sep 2023 16:53:21 -0700 Subject: [PATCH] Fix sapling observer detection and grow event (#9654) --- ...Fix-silent-equipment-change-for-mobs.patch | 16 +++ .../Only-capture-actual-tree-growth.patch | 135 ++++++++---------- 2 files changed, 72 insertions(+), 79 deletions(-) diff --git a/patches/server/Fix-silent-equipment-change-for-mobs.patch b/patches/server/Fix-silent-equipment-change-for-mobs.patch index a62cd59bab..6e194f7935 100644 --- a/patches/server/Fix-silent-equipment-change-for-mobs.patch +++ b/patches/server/Fix-silent-equipment-change-for-mobs.patch @@ -46,6 +46,22 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 if (!this.level().isClientSide) { 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/world/level/Level.java ++++ b/src/main/java/net/minecraft/world/level/Level.java +@@ -0,0 +0,0 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + + // Paper start + public void checkCapturedTreeStateForObserverNotify(final BlockPos pos, final CraftBlockState craftBlockState) { +- if (craftBlockState.getPosition().getY() == pos.getY() && this.getBlockState(craftBlockState.getPosition()) == craftBlockState.getHandle()) { // notify observers if the block state is the same and the Y level equals the original y level (for mega trees) ++ // notify observers if the block state is the same and the Y level equals the original y level (for mega trees) ++ // blocks at the same Y level with the same state can be assumed to be saplings which trigger observers regardless of if the ++ // tree grew or not ++ if (craftBlockState.getPosition().getY() == pos.getY() && this.getBlockState(craftBlockState.getPosition()) == craftBlockState.getHandle()) { + this.notifyAndUpdatePhysics(craftBlockState.getPosition(), null, craftBlockState.getHandle(), craftBlockState.getHandle(), craftBlockState.getHandle(), craftBlockState.getFlag(), 512); + } + } diff --git a/src/test/java/io/papermc/paper/entity/EntitySetItemSlotSilentOverrideTest.java b/src/test/java/io/papermc/paper/entity/EntitySetItemSlotSilentOverrideTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 diff --git a/patches/server/Only-capture-actual-tree-growth.patch b/patches/server/Only-capture-actual-tree-growth.patch index f2209340b3..bf4c9019a4 100644 --- a/patches/server/Only-capture-actual-tree-growth.patch +++ b/patches/server/Only-capture-actual-tree-growth.patch @@ -4,91 +4,68 @@ Date: Sat, 21 Aug 2021 18:53:03 -0700 Subject: [PATCH] Only capture actual tree growth -diff --git a/src/main/java/net/minecraft/world/level/block/grower/AbstractMegaTreeGrower.java b/src/main/java/net/minecraft/world/level/block/grower/AbstractMegaTreeGrower.java +diff --git a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/world/level/block/grower/AbstractMegaTreeGrower.java -+++ b/src/main/java/net/minecraft/world/level/block/grower/AbstractMegaTreeGrower.java -@@ -0,0 +0,0 @@ public abstract class AbstractMegaTreeGrower extends AbstractTreeGrower { - ConfiguredFeature worldgenfeatureconfigured = (ConfiguredFeature) holder.value(); - BlockState iblockdata1 = Blocks.AIR.defaultBlockState(); - -+ // Paper start -+ final CaptureState captureState = new CaptureState(world).recordAndSetToFalse(); -+ try (captureState) { -+ // Paper end - world.setBlock(pos.offset(x, 0, z), iblockdata1, 4); - world.setBlock(pos.offset(x + 1, 0, z), iblockdata1, 4); - world.setBlock(pos.offset(x, 0, z + 1), iblockdata1, 4); - world.setBlock(pos.offset(x + 1, 0, z + 1), iblockdata1, 4); -+ } // Paper - if (worldgenfeatureconfigured.place(world, chunkGenerator, random, pos.offset(x, 0, z))) { - return true; - } else { -+ captureState.recordAndSetToFalse(); // Paper -+ try (captureState) { // Paper - world.setBlock(pos.offset(x, 0, z), state, 4); - world.setBlock(pos.offset(x + 1, 0, z), state, 4); - world.setBlock(pos.offset(x, 0, z + 1), state, 4); - world.setBlock(pos.offset(x + 1, 0, z + 1), state, 4); -+ } // Paper - return false; +--- a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java ++++ b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java +@@ -0,0 +0,0 @@ public interface DispenseItemBehavior { + if (!fertilizeEvent.isCancelled()) { + for (org.bukkit.block.BlockState blockstate : blocks) { + blockstate.update(true); ++ worldserver.checkCapturedTreeStateForObserverNotify(blockposition, (org.bukkit.craftbukkit.block.CraftBlockState) blockstate); // Paper - notify observers even if grow failed + } + } } - } -diff --git a/src/main/java/net/minecraft/world/level/block/grower/AbstractTreeGrower.java b/src/main/java/net/minecraft/world/level/block/grower/AbstractTreeGrower.java +diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/world/level/block/grower/AbstractTreeGrower.java -+++ b/src/main/java/net/minecraft/world/level/block/grower/AbstractTreeGrower.java -@@ -0,0 +0,0 @@ public abstract class AbstractTreeGrower { - ConfiguredFeature worldgenfeatureconfigured = (ConfiguredFeature) holder.value(); - BlockState iblockdata1 = world.getFluidState(pos).createLegacyBlock(); - -+ // Paper start - don't capture the change to air for tree blocks -+ final CaptureState captureState = new CaptureState(world).recordAndSetToFalse(); -+ try (captureState) { -+ // Paper end - world.setBlock(pos, iblockdata1, 4); -+ } // Paper - if (worldgenfeatureconfigured.place(world, chunkGenerator, random, pos)) { - if (world.getBlockState(pos) == iblockdata1) { - world.sendBlockUpdated(pos, state, iblockdata1, 2); -@@ -0,0 +0,0 @@ public abstract class AbstractTreeGrower { - - return true; - } else { -+ captureState.recordAndSetToFalse(); // Paper - don't capture the change to air for tree blocks -+ try (captureState) { // Paper - world.setBlock(pos, state, 4); -+ } // Paper - return false; - } - } -@@ -0,0 +0,0 @@ public abstract class AbstractTreeGrower { - } +--- a/src/main/java/net/minecraft/world/item/ItemStack.java ++++ b/src/main/java/net/minecraft/world/item/ItemStack.java +@@ -0,0 +0,0 @@ public final class ItemStack { + } + for (CraftBlockState blockstate : blocks) { + world.setBlock(blockstate.getPosition(),blockstate.getHandle(), blockstate.getFlag()); // SPIGOT-7248 - manual update to avoid physics where appropriate ++ world.checkCapturedTreeStateForObserverNotify(blockposition, blockstate); // Paper - notify observers even if grow failed + if (blockstate instanceof org.bukkit.craftbukkit.block.CapturedBlockState capturedBlockState) capturedBlockState.checkTreeBlockHack(); // Paper + } + 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/world/level/Level.java ++++ b/src/main/java/net/minecraft/world/level/Level.java +@@ -0,0 +0,0 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + return null; } - // CraftBukkit end + // Paper end ++ + // Paper start -+ static class CaptureState implements AutoCloseable { -+ private final ServerLevel level; -+ private boolean previousCaptureTreeGeneration; -+ private boolean previousCaptureBlockStates; -+ -+ CaptureState(net.minecraft.server.level.ServerLevel level) { -+ this.level = level; -+ } -+ -+ CaptureState recordAndSetToFalse() { -+ this.previousCaptureTreeGeneration = this.level.captureTreeGeneration; -+ this.previousCaptureBlockStates = this.level.captureBlockStates; -+ this.level.captureTreeGeneration = false; -+ this.level.captureBlockStates = false; -+ return this; -+ } -+ -+ @Override -+ public void close() { -+ this.level.captureTreeGeneration = this.previousCaptureTreeGeneration; -+ this.level.captureBlockStates = this.previousCaptureBlockStates; ++ public void checkCapturedTreeStateForObserverNotify(final BlockPos pos, final CraftBlockState craftBlockState) { ++ if (craftBlockState.getPosition().getY() == pos.getY() && this.getBlockState(craftBlockState.getPosition()) == craftBlockState.getHandle()) { // notify observers if the block state is the same and the Y level equals the original y level (for mega trees) ++ this.notifyAndUpdatePhysics(craftBlockState.getPosition(), null, craftBlockState.getHandle(), craftBlockState.getHandle(), craftBlockState.getHandle(), craftBlockState.getFlag(), 512); + } + } + // Paper end } +diff --git a/src/main/java/net/minecraft/world/level/block/SaplingBlock.java b/src/main/java/net/minecraft/world/level/block/SaplingBlock.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/world/level/block/SaplingBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/SaplingBlock.java +@@ -0,0 +0,0 @@ public class SaplingBlock extends BushBlock implements BonemealableBlock { + if (event == null || !event.isCancelled()) { + for (BlockState blockstate : blocks) { + blockstate.update(true); ++ world.checkCapturedTreeStateForObserverNotify(pos, (org.bukkit.craftbukkit.block.CraftBlockState) blockstate); // Paper - notify observers even if grow failed + } + } + } +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java +@@ -0,0 +0,0 @@ public class CraftBlock implements Block { + if (!event.isCancelled()) { + for (BlockState blockstate : blocks) { + blockstate.update(true); ++ world.checkCapturedTreeStateForObserverNotify(this.position, (org.bukkit.craftbukkit.block.CraftBlockState) blockstate); // Paper - notify observers even if grow failed + } + } + }