diff --git a/leaves-api/src/main/java/org/leavesmc/leaves/event/player/UpdateSuppressionEvent.java b/leaves-api/src/main/java/org/leavesmc/leaves/event/player/UpdateSuppressionEvent.java new file mode 100644 index 00000000..61215a7d --- /dev/null +++ b/leaves-api/src/main/java/org/leavesmc/leaves/event/player/UpdateSuppressionEvent.java @@ -0,0 +1,46 @@ +package org.leavesmc.leaves.event.player; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class UpdateSuppressionEvent extends Event { + private static final HandlerList handlers = new HandlerList(); + + private final @Nullable Player player; + private final @Nullable Location position; + private final @Nullable Material material; + private final @NotNull Throwable throwable; + + public UpdateSuppressionEvent(@Nullable Player player, @Nullable Location position, @Nullable Material material, @NotNull Throwable throwable) { + this.player = player; + this.position = position; + this.material = material; + this.throwable = throwable; + } + + @Override + public @NotNull HandlerList getHandlers() { + return handlers; + } + + public @Nullable Player getPlayer() { + return player; + } + + public @NotNull Throwable getThrowable() { + return throwable; + } + + public @Nullable Location getPosition() { + return position; + } + + public @Nullable Material getMaterial() { + return material; + } +} diff --git a/leaves-server/minecraft-patches/features/0038-Catch-update-suppression-crash.patch b/leaves-server/minecraft-patches/features/0038-Catch-update-suppression-crash.patch index e5014c6b..99dfdc90 100644 --- a/leaves-server/minecraft-patches/features/0038-Catch-update-suppression-crash.patch +++ b/leaves-server/minecraft-patches/features/0038-Catch-update-suppression-crash.patch @@ -5,85 +5,111 @@ Subject: [PATCH] Catch update suppression crash diff --git a/net/minecraft/network/protocol/PacketUtils.java b/net/minecraft/network/protocol/PacketUtils.java -index 4535858701b2bb232b9d2feb2af6551526232ddc..2a51acd97afc525170e8001b76f57ad13853aab0 100644 +index 4535858701b2bb232b9d2feb2af6551526232ddc..03e70445dfe14c119284f7c301127075c009e915 100644 --- a/net/minecraft/network/protocol/PacketUtils.java +++ b/net/minecraft/network/protocol/PacketUtils.java -@@ -27,6 +27,10 @@ public class PacketUtils { +@@ -27,7 +27,20 @@ public class PacketUtils { if (processor.shouldHandleMessage(packet)) { try { packet.handle(processor); + // Leaves start - update suppression crash fix + } catch (org.leavesmc.leaves.util.UpdateSuppressionException exception) { -+ org.leavesmc.leaves.LeavesLogger.LOGGER.info(exception.getMessage()); -+ // Leaves start - update suppression crash fix ++ if (processor instanceof net.minecraft.server.network.ServerGamePacketListenerImpl gamePacketListener) { ++ exception.providePlayer(gamePacketListener.player); ++ } ++ exception.consume(); } catch (Exception var4) { ++ if (var4.getCause() instanceof org.leavesmc.leaves.util.UpdateSuppressionException exception) { ++ if (processor instanceof net.minecraft.server.network.ServerGamePacketListenerImpl gamePacketListener) { ++ exception.providePlayer(gamePacketListener.player); ++ } ++ exception.consume(); ++ } ++ // Leaves end - update suppression crash fix if (var4 instanceof ReportedException reportedException && reportedException.getCause() instanceof OutOfMemoryError) { throw makeReportedException(var4, packet, processor); + } diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index 3aa719636ea2b68463a7f412a9cbd5bf3a7925a7..0e89e9232ae3cc27e80620bbcc509d48f7efe056 100644 +index 3aa719636ea2b68463a7f412a9cbd5bf3a7925a7..498102c2553f12badff29bed98ce30528162e536 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java -@@ -1725,6 +1725,10 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop implements ca.spottedleaf.moonrise.patch +@@ -104,7 +104,16 @@ public abstract class StateHolder implements ca.spottedleaf.moonrise.patch if (ret != null) { return ret; } -+ if (org.leavesmc.leaves.LeavesConfig.modify.updateSuppressionCrashFix) throw new org.leavesmc.leaves.util.UpdateSuppressionException(null, null); // Leaves - fix update suppression crash - throw new IllegalArgumentException("Cannot get property " + property + " as it does not exist in " + this.owner); +- throw new IllegalArgumentException("Cannot get property " + property + " as it does not exist in " + this.owner); ++ // Leaves start - update suppression crash fix ++ IllegalArgumentException iae = new IllegalArgumentException("Cannot get property " + property + " as it does not exist in " + this.owner); ++ if (org.leavesmc.leaves.LeavesConfig.modify.updateSuppressionCrashFix) { ++ org.leavesmc.leaves.util.UpdateSuppressionException exception = new org.leavesmc.leaves.util.UpdateSuppressionException(null, null, null, null, iae); ++ if (exception.getStackTrace()[1].getClassName().startsWith("net.minecraft")) { ++ throw exception; ++ } ++ } ++ throw iae; ++ // Leaves end - update suppression crash fix // Paper end - optimise blockstate property access } + diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java -index f24db919989bc2e5768e18b4fda68c38d6cde7e0..2cdca2917ce6a4912b57594697bf5543801eb868 100644 +index f24db919989bc2e5768e18b4fda68c38d6cde7e0..0e22116fefcbdbf2049b7ec285b35fd03c723dc5 100644 --- a/net/minecraft/world/level/chunk/LevelChunk.java +++ b/net/minecraft/world/level/chunk/LevelChunk.java @@ -373,7 +373,7 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p @@ -126,7 +162,7 @@ index f24db919989bc2e5768e18b4fda68c38d6cde7e0..2cdca2917ce6a4912b57594697bf5543 return null; } else { - Block block = state.getBlock(); -+ Block block = state.getBlock(); try { // Leaves start - fix update suppression crash ++ Block block = state.getBlock(); try { // Leaves start - update suppression crash fix this.heightmaps.get(Heightmap.Types.MOTION_BLOCKING).update(i, y, i2, state); this.heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(i, y, i2, state); this.heightmaps.get(Heightmap.Types.OCEAN_FLOOR).update(i, y, i2, state); @@ -134,29 +170,34 @@ index f24db919989bc2e5768e18b4fda68c38d6cde7e0..2cdca2917ce6a4912b57594697bf5543 this.markUnsaved(); return blockState; } -+ } catch (org.leavesmc.leaves.util.UpdateSuppressionException e) {throw new org.leavesmc.leaves.util.UpdateSuppressionException(pos, block);} // Leaves end - fix update suppression crash ++ } catch (org.leavesmc.leaves.util.UpdateSuppressionException e) { e.provideBlock(level, pos, block); throw e; } // Leaves - update suppression crash fix } } } diff --git a/net/minecraft/world/level/redstone/NeighborUpdater.java b/net/minecraft/world/level/redstone/NeighborUpdater.java -index 332b33a004ab11150cca0cc2cefc26d0286648f5..263bf2b795057c2d5218bf9cfb684e526601aa77 100644 +index 332b33a004ab11150cca0cc2cefc26d0286648f5..8942aa2ca4796c7c36c0955141627ea905e0ec64 100644 --- a/net/minecraft/world/level/redstone/NeighborUpdater.java +++ b/net/minecraft/world/level/redstone/NeighborUpdater.java -@@ -60,9 +60,17 @@ public interface NeighborUpdater { +@@ -60,9 +60,22 @@ public interface NeighborUpdater { state.handleNeighborChanged(level, pos, neighborBlock, orientation, movedByPiston); // Spigot start } catch (StackOverflowError ex) { -+ // Leaves start - fix update suppression crash ++ // Leaves start - update suppression crash fix + if (org.leavesmc.leaves.LeavesConfig.modify.updateSuppressionCrashFix) { -+ throw new org.leavesmc.leaves.util.UpdateSuppressionException(pos, neighborBlock); ++ throw new org.leavesmc.leaves.util.UpdateSuppressionException(pos, level, neighborBlock, null, ex); + } level.lastPhysicsProblem = pos.immutable(); // Spigot end } catch (Throwable var9) { + if (org.leavesmc.leaves.LeavesConfig.modify.updateSuppressionCrashFix) { -+ throw new org.leavesmc.leaves.util.UpdateSuppressionException(pos, neighborBlock); ++ if (var9 instanceof org.leavesmc.leaves.util.UpdateSuppressionException ue) { ++ ue.provideBlock(level, pos, neighborBlock); ++ throw ue; ++ } else { ++ throw new org.leavesmc.leaves.util.UpdateSuppressionException(pos, level, neighborBlock, null, var9); ++ } + } -+ // Leaves end - fix update suppression crash ++ // Leaves end - update suppression crash fix CrashReport crashReport = CrashReport.forThrowable(var9, "Exception while updating neighbours"); CrashReportCategory crashReportCategory = crashReport.addCategory("Block being updated"); crashReportCategory.setDetail( diff --git a/leaves-server/minecraft-patches/features/0039-Bedrock-break-list.patch b/leaves-server/minecraft-patches/features/0039-Bedrock-break-list.patch index 301189fe..2d96b753 100644 --- a/leaves-server/minecraft-patches/features/0039-Bedrock-break-list.patch +++ b/leaves-server/minecraft-patches/features/0039-Bedrock-break-list.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Bedrock break list diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index 4a427b80ad9bc387bd774e33c844b4d67836737c..952275263fca69dc55266348ead59dc3ca2b1520 100644 +index 498102c2553f12badff29bed98ce30528162e536..5e1a8ce2e772427fd8fc2b6794575e36d5c7d655 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java -@@ -1752,6 +1752,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 1.0E-7) { -@@ -2131,6 +2137,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -2137,6 +2143,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess this.yo = y; this.zo = d1; this.setPos(d, y, d1); @@ -89,7 +89,7 @@ index 7a82ab3b1a4a4cc7708cbec5d424b3bfcede87a9..6b3fcd3e02755ab187d075d868e93767 } diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java -index bc19f0bf079d6a7fa2fc8aaed6477da5e57d32da..1f0042d24a11c709f291a03e1699fcaf0d6571c6 100644 +index fbf884201442c6e75b5ab4533517a10e78f02f94..841dc41e455da73ff1bfdb8feaf231ade29d1e41 100644 --- a/net/minecraft/world/entity/LivingEntity.java +++ b/net/minecraft/world/entity/LivingEntity.java @@ -3328,6 +3328,11 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin @@ -105,7 +105,7 @@ index bc19f0bf079d6a7fa2fc8aaed6477da5e57d32da..1f0042d24a11c709f291a03e1699fcaf if (this.isSleeping()) { diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java -index 0d046133ea2b6d47e089cb792cf3bc3abace70ba..0abdf0e520d1a0672917d60b79f467df4399e256 100644 +index 61baebc707cb6afcaf8c7f56fd906813d309a2cf..eca523fe027d3570eb549756d825678e17e74152 100644 --- a/net/minecraft/world/entity/player/Player.java +++ b/net/minecraft/world/entity/player/Player.java @@ -219,6 +219,7 @@ public abstract class Player extends LivingEntity { diff --git a/leaves-server/minecraft-patches/features/0063-Optimize-sun-burn-tick.patch b/leaves-server/minecraft-patches/features/0063-Optimize-sun-burn-tick.patch index 24025fde..8e4caef4 100644 --- a/leaves-server/minecraft-patches/features/0063-Optimize-sun-burn-tick.patch +++ b/leaves-server/minecraft-patches/features/0063-Optimize-sun-burn-tick.patch @@ -6,10 +6,10 @@ Subject: [PATCH] Optimize sun burn tick This patch is Powered by Gale(https://github.com/GaleMC/Gale) diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index 7f0e8f88fbdef1283a23dbbfa4f3892677c597c0..4b65cc9ccd6cb2c336c0e76ee075397228f34e59 100644 +index 81cf649fd4690fe5061c88e99db3d01d7faf67bf..2170020f55abc47d489838f98a7d67bcef2a33a0 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java -@@ -2112,9 +2112,20 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -2118,9 +2118,20 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess @Deprecated public float getLightLevelDependentMagicValue() { @@ -33,7 +33,7 @@ index 7f0e8f88fbdef1283a23dbbfa4f3892677c597c0..4b65cc9ccd6cb2c336c0e76ee0753972 } public void absSnapTo(double x, double y, double z, float yRot, float xRot) { -@@ -2129,6 +2140,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -2135,6 +2146,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess this.xRotO = this.getXRot(); this.setYHeadRot(yRot); // Paper - Update head rotation } diff --git a/leaves-server/minecraft-patches/features/0068-Skip-entity-move-if-movement-is-zero.patch b/leaves-server/minecraft-patches/features/0068-Skip-entity-move-if-movement-is-zero.patch index 3453da40..c8f0aeaa 100644 --- a/leaves-server/minecraft-patches/features/0068-Skip-entity-move-if-movement-is-zero.patch +++ b/leaves-server/minecraft-patches/features/0068-Skip-entity-move-if-movement-is-zero.patch @@ -6,7 +6,7 @@ Subject: [PATCH] Skip entity move if movement is zero This patch is Powered by Gale(https://github.com/GaleMC/Gale) diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index d293d79db9f58c78b32818834d2636d9f52486ca..39c80b858b6bb94949fb7d2fb8347a7a628cb65f 100644 +index 2170020f55abc47d489838f98a7d67bcef2a33a0..6cf6e63d5c298b61d6cbb03c085530ca290ca57e 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java @@ -262,6 +262,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess @@ -31,7 +31,7 @@ index d293d79db9f58c78b32818834d2636d9f52486ca..39c80b858b6bb94949fb7d2fb8347a7a final Vec3 originalMovement = movement; // Paper - Expose pre-collision velocity // Paper start - detailed watchdog information ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread("Cannot move an entity off-main"); -@@ -4415,6 +4423,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -4421,6 +4429,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } public final void setBoundingBox(AABB bb) { diff --git a/leaves-server/minecraft-patches/features/0073-Replay-Mod-API.patch b/leaves-server/minecraft-patches/features/0073-Replay-Mod-API.patch index dcc2c5ea..d0ef7acf 100644 --- a/leaves-server/minecraft-patches/features/0073-Replay-Mod-API.patch +++ b/leaves-server/minecraft-patches/features/0073-Replay-Mod-API.patch @@ -80,7 +80,7 @@ index 514f8fbdeb776087608665c35de95294aadf5cf0..b75772897cabc3e7c59301d451685378 players.add(serverPlayer1); if (players.size() >= resultLimit) { diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index 39898e5e2bd75eced05f0b90b3881270d144fd93..2b29a8cdf8956e13143a59c16fcee2f5c9b49086 100644 +index 5e1a8ce2e772427fd8fc2b6794575e36d5c7d655..1241b008d66bacd8640302a6dbf52a2e592b29b9 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java @@ -1638,7 +1638,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0) { this.invulnerableTime--; } -@@ -1203,6 +1205,13 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc +@@ -1205,6 +1207,13 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc if (this.isInvulnerableTo(level, damageSource)) { return false; } else { diff --git a/leaves-server/minecraft-patches/features/0123-Sound-update-suppression.patch b/leaves-server/minecraft-patches/features/0123-Sound-update-suppression.patch index 89776e10..901d816a 100644 --- a/leaves-server/minecraft-patches/features/0123-Sound-update-suppression.patch +++ b/leaves-server/minecraft-patches/features/0123-Sound-update-suppression.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Sound update suppression diff --git a/net/minecraft/world/level/block/SculkSensorBlock.java b/net/minecraft/world/level/block/SculkSensorBlock.java -index fa9cb4c40a41eea7fd63a4513d0b0f39067de9ba..331276f4464d78dc86f35fe7d9c42864d7e73a6c 100644 +index fa9cb4c40a41eea7fd63a4513d0b0f39067de9ba..a8375b6544a004c96e2b3c7c088831def855febe 100644 --- a/net/minecraft/world/level/block/SculkSensorBlock.java +++ b/net/minecraft/world/level/block/SculkSensorBlock.java @@ -97,7 +97,7 @@ public class SculkSensorBlock extends BaseEntityBlock implements SimpleWaterlogg @@ -17,13 +17,15 @@ index fa9cb4c40a41eea7fd63a4513d0b0f39067de9ba..331276f4464d78dc86f35fe7d9c42864 && entity.getType() != EntityType.WARDEN && level.getBlockEntity(pos) instanceof SculkSensorBlockEntity sculkSensorBlockEntity && level instanceof ServerLevel serverLevel -@@ -214,6 +214,13 @@ public class SculkSensorBlock extends BaseEntityBlock implements SimpleWaterlogg +@@ -214,6 +214,15 @@ public class SculkSensorBlock extends BaseEntityBlock implements SimpleWaterlogg return state.getValue(PHASE); } + // Leaves start - Sound update suppression + public static boolean canActivate(BlockState state, BlockPos pos) { -+ if (org.leavesmc.leaves.LeavesConfig.modify.oldMC.updater.soundUpdateSuppression && !(state.getBlock() instanceof SculkSensorBlock)) throw new org.leavesmc.leaves.util.UpdateSuppressionException(pos, state.getBlock()); ++ if (org.leavesmc.leaves.LeavesConfig.modify.oldMC.updater.soundUpdateSuppression && !(state.getBlock() instanceof SculkSensorBlock)) { ++ throw new org.leavesmc.leaves.util.UpdateSuppressionException(pos, null, state.getBlock(), null, new IllegalArgumentException()); ++ } + return canActivate(state); + } + // Leaves end - Sound update suppression diff --git a/leaves-server/minecraft-patches/features/0126-Vanilla-Fluid-Pushing.patch b/leaves-server/minecraft-patches/features/0126-Vanilla-Fluid-Pushing.patch index 01e27d90..2b46cac1 100644 --- a/leaves-server/minecraft-patches/features/0126-Vanilla-Fluid-Pushing.patch +++ b/leaves-server/minecraft-patches/features/0126-Vanilla-Fluid-Pushing.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Vanilla Fluid Pushing diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index fadce8b3073dc67534a4830b40fc2e84fdbd687b..e5f1939c9f998e56a5b99ab8319315e3645535ea 100644 +index c011fd65f5814c88cb3f6a4f62283efb9b6188ec..bea4089920191b5e3231e9792a078747923d0c14 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java -@@ -4729,8 +4729,82 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -4735,8 +4735,82 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess return Mth.lerp(partialTick, this.yRotO, this.yRot); } diff --git a/leaves-server/minecraft-patches/features/0132-Prevent-loss-of-item-drops-due-to-update-suppression.patch b/leaves-server/minecraft-patches/features/0132-Prevent-loss-of-item-drops-due-to-update-suppression.patch index 3ea85f05..bb8e2049 100644 --- a/leaves-server/minecraft-patches/features/0132-Prevent-loss-of-item-drops-due-to-update-suppression.patch +++ b/leaves-server/minecraft-patches/features/0132-Prevent-loss-of-item-drops-due-to-update-suppression.patch @@ -6,31 +6,34 @@ Subject: [PATCH] Prevent loss of item drops due to update suppression when diff --git a/net/minecraft/server/level/ServerPlayerGameMode.java b/net/minecraft/server/level/ServerPlayerGameMode.java -index f258bc30014f94243ad832b33dcb6c9acd1f2f08..a3934a0edd210af1ca4749ea64d050871cbfc96d 100644 +index f258bc30014f94243ad832b33dcb6c9acd1f2f08..9a4eb1f8e01517707befa30b3ccacc7c84c0abe9 100644 --- a/net/minecraft/server/level/ServerPlayerGameMode.java +++ b/net/minecraft/server/level/ServerPlayerGameMode.java -@@ -382,7 +382,14 @@ public class ServerPlayerGameMode { +@@ -382,7 +382,18 @@ public class ServerPlayerGameMode { this.level.captureDrops = new java.util.ArrayList<>(); // CraftBukkit end BlockState blockState1 = org.leavesmc.leaves.command.subcommands.BlockUpdateCommand.isNoBlockUpdate() ? blockState : block.playerWillDestroy(this.level, pos, blockState, this.player); // Leaves - no block update - boolean flag = this.level.removeBlock(pos, false); -+ boolean flag; // Leaves start - Prevent loss of item drops due to update suppression when breaking blocks ++ // Leaves start - Prevent loss of item drops due to update suppression when breaking blocks ++ boolean flag; + org.leavesmc.leaves.util.UpdateSuppressionException ex = null; + try { + flag = this.level.removeBlock(pos, false); + } catch (org.leavesmc.leaves.util.UpdateSuppressionException e) { + ex = e; ++ ex.provideBlock(level, pos, block); ++ ex.providePlayer(this.player); + flag = false; + } ++ // Leaves end - Prevent loss of item drops due to update suppression when breaking blocks if (flag) { block.destroy(this.level, pos, blockState1); } -@@ -410,6 +417,8 @@ public class ServerPlayerGameMode { +@@ -410,6 +421,7 @@ public class ServerPlayerGameMode { if (event.isDropItems()) { org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDropItemEvent(bblock, state, this.player, itemsToDrop); // Paper - capture all item additions to the world } -+ if (ex != null) throw ex; -+ // Leaves end - Prevent loss of item drops due to update suppression when breaking blocks ++ if (ex != null) throw ex; // Leaves - Prevent loss of item drops due to update suppression when breaking blocks // Drop event experience if (flag) { diff --git a/leaves-server/minecraft-patches/features/0133-Fix-block-place-desync-due-to-update-suppression.patch b/leaves-server/minecraft-patches/features/0133-Fix-block-place-desync-due-to-update-suppression.patch index 751c0bb8..45b4ea3a 100644 --- a/leaves-server/minecraft-patches/features/0133-Fix-block-place-desync-due-to-update-suppression.patch +++ b/leaves-server/minecraft-patches/features/0133-Fix-block-place-desync-due-to-update-suppression.patch @@ -5,27 +5,33 @@ Subject: [PATCH] Fix block place desync due to update suppression diff --git a/net/minecraft/world/item/ItemStack.java b/net/minecraft/world/item/ItemStack.java -index e59b8d42d602bbdae1071f2a5be1180420c4efb7..5dadbdb4bb4c0d3a2dcc33120ac725bfe3e6f65c 100644 +index e59b8d42d602bbdae1071f2a5be1180420c4efb7..a63330b232dc41f0a5bb36bb94dfb84f01504699 100644 --- a/net/minecraft/world/item/ItemStack.java +++ b/net/minecraft/world/item/ItemStack.java -@@ -389,8 +389,12 @@ public final class ItemStack implements DataComponentHolder { +@@ -389,8 +389,18 @@ public final class ItemStack implements DataComponentHolder { } } InteractionResult interactionResult; -+ org.leavesmc.leaves.util.UpdateSuppressionException ue = null; // Leaves start - fix block place desync due to update suppression ++ // Leaves start - fix block place desync due to update suppression ++ org.leavesmc.leaves.util.UpdateSuppressionException ue = null; try { interactionResult = item.useOn(context); -+ } catch (org.leavesmc.leaves.util.UpdateSuppressionException te) { ++ } catch (org.leavesmc.leaves.util.UpdateSuppressionException ex) { + interactionResult = net.minecraft.world.InteractionResult.SUCCESS.configurePaper(e -> e.placedBlockAt(clickedPos.immutable())); -+ ue = te; // Leaves end - fix block place desync due to update suppression ++ ue = ex; ++ ue.provideBlock(context.getLevel(), context.getClickedPos(), serverLevel.getBlockState(context.getClickedPos()).getBlock()); ++ if (player != null) { ++ ue.providePlayer((net.minecraft.server.level.ServerPlayer) player); ++ } ++ // Leaves end - fix block place desync due to update suppression } finally { serverLevel.captureBlockStates = false; } -@@ -537,6 +541,7 @@ public final class ItemStack implements DataComponentHolder { +@@ -537,6 +547,7 @@ public final class ItemStack implements DataComponentHolder { serverLevel.capturedBlockStates.clear(); // CraftBukkit end -+ if (ue != null) throw ue; ++ if (ue != null) throw ue; // Leaves - fix block place desync due to update suppression return interactionResult; } } diff --git a/leaves-server/minecraft-patches/features/0135-Old-ender-dragon-part-can-use-end-portal.patch b/leaves-server/minecraft-patches/features/0135-Old-ender-dragon-part-can-use-end-portal.patch index 93cd6436..b9ebd4a5 100644 --- a/leaves-server/minecraft-patches/features/0135-Old-ender-dragon-part-can-use-end-portal.patch +++ b/leaves-server/minecraft-patches/features/0135-Old-ender-dragon-part-can-use-end-portal.patch @@ -26,7 +26,7 @@ This patch is Powered by CrystalCarpetAddition(https://github.com/Crystal0404/Cr */ diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index e5f1939c9f998e56a5b99ab8319315e3645535ea..0190dd033bd60ad03c025150ece23fbf2a86f954 100644 +index bea4089920191b5e3231e9792a078747923d0c14..e89b6c6de030f1298f3d9919a8b066ed7467ce69 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java @@ -185,7 +185,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess @@ -38,7 +38,7 @@ index e5f1939c9f998e56a5b99ab8319315e3645535ea..0190dd033bd60ad03c025150ece23fbf public boolean collisionLoadChunks = false; // Paper public org.bukkit.craftbukkit.entity.CraftEntity getBukkitEntity() { -@@ -3955,7 +3955,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -3961,7 +3961,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess @Nullable public Entity teleport(TeleportTransition teleportTransition) { // Paper start - Fix item duplication and teleport issues @@ -47,7 +47,7 @@ index e5f1939c9f998e56a5b99ab8319315e3645535ea..0190dd033bd60ad03c025150ece23fbf LOGGER.warn("Illegal Entity Teleport {} to {}:{}", this, teleportTransition.newLevel(), teleportTransition.position(), new Throwable()); return null; } -@@ -4071,7 +4071,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -4077,7 +4077,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess entityx.restoreFrom(this); this.removeAfterChangingDimensions(); entityx.teleportSetPosition(PositionMoveRotation.of(teleportTransition), teleportTransition.relatives()); @@ -56,7 +56,7 @@ index e5f1939c9f998e56a5b99ab8319315e3645535ea..0190dd033bd60ad03c025150ece23fbf for (Entity entity2 : list) { entity2.startRiding(entityx, true); -@@ -4206,6 +4206,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -4212,6 +4212,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } public boolean canTeleport(Level fromLevel, Level toLevel) { diff --git a/leaves-server/minecraft-patches/features/0138-Lithium-Sleeping-Block-Entity.patch b/leaves-server/minecraft-patches/features/0138-Lithium-Sleeping-Block-Entity.patch index 0e972846..f57a4304 100644 --- a/leaves-server/minecraft-patches/features/0138-Lithium-Sleeping-Block-Entity.patch +++ b/leaves-server/minecraft-patches/features/0138-Lithium-Sleeping-Block-Entity.patch @@ -86,10 +86,10 @@ index 3092454bf7071deca75fecfc203072593fe5c7e7..c20e12726a020429f36b9fbe0d6da2af } } diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index f78c4f3f2047564730050f16693c00aa2c29a4e0..15a7da64e6ff4d62a76b4b3c113eb3563f621feb 100644 +index dcb1f6975b1cb18f38e0cf8a43d551f07836b12f..69dffeecbf0faa789bde3a93a44ff5e75db6f6b2 100644 --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java -@@ -2402,6 +2402,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -2404,6 +2404,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe for (TickingBlockEntity tickingBlockEntity : this.blockEntityTickers) { BlockPos pos = tickingBlockEntity.getPos(); @@ -111,7 +111,7 @@ index 86cac164a2bf0e76528396e6aabbfd64cfc29559..da99b4bc7fe8460945070915073be141 int getContainerSize(); diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index 0190dd033bd60ad03c025150ece23fbf2a86f954..0aa7fa66e74b5b1bc5e5db9910a812daa419d9d8 100644 +index e89b6c6de030f1298f3d9919a8b066ed7467ce69..22c6a11dd9ea70a242804b91c8fa89cdac2f6f1a 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java @@ -309,7 +309,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess @@ -123,7 +123,7 @@ index 0190dd033bd60ad03c025150ece23fbf2a86f954..0aa7fa66e74b5b1bc5e5db9910a812da private final VecDeltaCodec packetPositionCodec = new VecDeltaCodec(); public boolean hasImpulse; @Nullable -@@ -5147,6 +5147,19 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -5153,6 +5153,19 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess this.setBoundingBox(this.makeBoundingBox()); } // Paper end - Block invalid positions and bounding box @@ -306,7 +306,7 @@ index c1ca84cf0dbb4fd091cfab517721c87e0f9074a0..5f70277c3548a9cd423585d374978422 ItemStack item = container.getItem(i); if (!item.isEmpty()) { diff --git a/net/minecraft/world/item/ItemStack.java b/net/minecraft/world/item/ItemStack.java -index 5dadbdb4bb4c0d3a2dcc33120ac725bfe3e6f65c..1f73b9c8119444cc0274edb0aa38c3f10362213a 100644 +index a63330b232dc41f0a5bb36bb94dfb84f01504699..7fbce8302739ab016f1b64f8227c6d7286b85850 100644 --- a/net/minecraft/world/item/ItemStack.java +++ b/net/minecraft/world/item/ItemStack.java @@ -93,8 +93,12 @@ import net.minecraft.world.level.block.state.pattern.BlockInWorld; @@ -323,7 +323,7 @@ index 5dadbdb4bb4c0d3a2dcc33120ac725bfe3e6f65c..1f73b9c8119444cc0274edb0aa38c3f1 private static final List OP_NBT_WARNING = List.of( Component.translatable("item.op_warning.line1").withStyle(ChatFormatting.RED, ChatFormatting.BOLD), Component.translatable("item.op_warning.line2").withStyle(ChatFormatting.RED), -@@ -972,6 +976,7 @@ public final class ItemStack implements DataComponentHolder { +@@ -978,6 +982,7 @@ public final class ItemStack implements DataComponentHolder { @Nullable public T set(DataComponentType component, @Nullable T value) { @@ -331,7 +331,7 @@ index 5dadbdb4bb4c0d3a2dcc33120ac725bfe3e6f65c..1f73b9c8119444cc0274edb0aa38c3f1 return this.components.set(component, value); } -@@ -1316,6 +1321,23 @@ public final class ItemStack implements DataComponentHolder { +@@ -1322,6 +1327,23 @@ public final class ItemStack implements DataComponentHolder { } public void setCount(int count) { @@ -355,7 +355,7 @@ index 5dadbdb4bb4c0d3a2dcc33120ac725bfe3e6f65c..1f73b9c8119444cc0274edb0aa38c3f1 this.count = count; } -@@ -1371,4 +1393,90 @@ public final class ItemStack implements DataComponentHolder { +@@ -1377,4 +1399,90 @@ public final class ItemStack implements DataComponentHolder { public boolean canDestroyBlock(BlockState state, Level level, BlockPos pos, Player player) { return this.getItem().canDestroyBlock(this, state, level, pos, player); } @@ -2399,7 +2399,7 @@ index 67719dce9017a4c86a70b62fb660bddc636d5582..c1cbb635b6c22b04ca33c68a4c9777f0 } diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java -index 56e7df059cd070a8f472d6712dfb08d14ffa8819..8c263cbb348411a4f1c2ed0a3e46a494d7622f68 100644 +index b27cbb55fcb980679819a605112533f366abc97e..b9931ba80f79db6d4c80fb707c788e449c71f52e 100644 --- a/net/minecraft/world/level/chunk/LevelChunk.java +++ b/net/minecraft/world/level/chunk/LevelChunk.java @@ -898,12 +898,14 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/ServerBotAction.java b/leaves-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/ServerBotAction.java index 7ec5b24f..68bb9eeb 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/ServerBotAction.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/ServerBotAction.java @@ -6,11 +6,13 @@ import net.minecraft.server.level.ServerPlayer; import org.apache.commons.lang3.tuple.Pair; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; +import org.leavesmc.leaves.LeavesLogger; import org.leavesmc.leaves.bot.ServerBot; import org.leavesmc.leaves.command.CommandArgument; import org.leavesmc.leaves.command.CommandArgumentResult; import org.leavesmc.leaves.event.bot.BotActionExecuteEvent; import org.leavesmc.leaves.event.bot.BotActionStopEvent; +import org.leavesmc.leaves.util.UpdateSuppressionException; import java.util.List; import java.util.UUID; @@ -86,7 +88,17 @@ public abstract class ServerBotAction> { return; } - if (this.doTick(bot)) { + boolean result = false; + try { + result = this.doTick(bot); + } catch (UpdateSuppressionException e) { + e.providePlayer(bot); + e.consume(); + } catch (Exception e) { + LeavesLogger.LOGGER.severe("An error occurred while executing bot " + bot.displayName + ", action " + this.name, e); + } + + if (result) { if (this.numberRemaining > 0) { this.numberRemaining--; } diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/util/UpdateSuppressionException.java b/leaves-server/src/main/java/org/leavesmc/leaves/util/UpdateSuppressionException.java index 150a0813..5f9c369b 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/util/UpdateSuppressionException.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/util/UpdateSuppressionException.java @@ -1,32 +1,125 @@ package org.leavesmc.leaves.util; import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.leavesmc.leaves.LeavesLogger; +import org.leavesmc.leaves.bot.ServerBot; +import org.leavesmc.leaves.event.player.UpdateSuppressionEvent; + +import java.util.ArrayList; +import java.util.List; public class UpdateSuppressionException extends RuntimeException { + private @Nullable BlockPos pos; + private @Nullable Level level; + private @Nullable Block source; + private @Nullable ServerPlayer player; + private final @NotNull Throwable throwable; - private final BlockPos pos; - private final Block source; - - public UpdateSuppressionException(BlockPos pos, Block source) { - super("Update suppression"); + public UpdateSuppressionException( + @Nullable BlockPos pos, + @Nullable Level level, + @Nullable Block source, + @Nullable ServerPlayer player, + @NotNull Throwable throwable + ) { + super("Update Suppression"); this.pos = pos; + this.level = level; this.source = source; + this.player = player; + this.throwable = throwable; } - public BlockPos getPos() { - return pos; + public void providePlayer(@NotNull ServerPlayer player) { + if (this.level == null) { + this.level = player.level(); + } + this.player = player; } - public Block getSource() { - return source; - } - - public String getMessage() { - if (pos != null) { - return "An update suppression processed, form [%s] to [x:%d,y:%d,z:%d]".formatted(source.getName(), pos.getX(), pos.getY(), pos.getZ()); - } else { - return "An update suppression processed, form [%s]".formatted(source.getName()); + public void provideLevel(@NotNull Level level) { + if (this.level != null) { + this.level = level; } } + + public void provideBlock(@NotNull Level level, @NotNull BlockPos pos, @NotNull Block source) { + provideLevel(level); + provideBlock(pos, source); + } + + public void provideBlock(@NotNull BlockPos pos, @NotNull Block source) { + if (this.pos != null) { + this.pos = pos; + } + if (this.source != null) { + this.source = source; + } + } + + public void consume() { + submitEvent(); + LeavesLogger.LOGGER.info(getMessage()); + } + + private void submitEvent() { + Location location = null; + if (pos != null && level != null) { + location = new Location(level.getWorld(), pos.getX(), pos.getY(), pos.getZ()); + } + Material material = null; + if (source != null) { + material = source.defaultBlockState().getBukkitMaterial(); + } + Player bukkitPlayer = null; + if (player != null) { + bukkitPlayer = player.getBukkitEntity(); + } + new UpdateSuppressionEvent(bukkitPlayer, location, material, throwable).callEvent(); + } + + @Override + public String getMessage() { + List messages = new ArrayList<>(); + messages.add("An %s update suppression was triggered".formatted(getTypeName())); + if (source != null) { + messages.add("from %s".formatted(source.defaultBlockState().getBukkitMaterial().name())); + } + if (pos != null) { + messages.add("at [x:%d,y:%d,z:%d]".formatted(pos.getX(), pos.getY(), pos.getZ())); + } + if (level != null) { + messages.add("in %s".formatted(level.dimension().location())); + } + if (player != null) { + if (player instanceof ServerBot) { + messages.add("by %s[bot]".formatted(player.displayName)); + } else { + messages.add("by %s".formatted(player.displayName)); + } + } + return String.join(" ", messages); + } + + @Contract(pure = true) + private @NotNull String getTypeName() { + Class type = throwable.getClass(); + if (type == ClassCastException.class) { + return "CCE"; + } else if (type == StackOverflowError.class) { + return "SOE"; + } else if (type == IllegalArgumentException.class) { + return "IAE"; + } + return type.getSimpleName(); + } }