diff --git a/gradle.properties b/gradle.properties index c0c0e79..5268276 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,7 +5,7 @@ channel=BETA clipVersion=3.0.17 weightVersion=2.0.12 # 0 for skip release, 1 for pre-release, 2 for release -release=1 +release=0 luminolRef=fd9f3cea2c95c6830a4903b32ba63a68d9a6cbc3 diff --git a/lophine-server/minecraft-patches/features/0034-Leaves-Catch-update-suppression-crash.patch b/lophine-server/minecraft-patches/features/0034-Leaves-Catch-update-suppression-crash.patch new file mode 100644 index 0000000..5928055 --- /dev/null +++ b/lophine-server/minecraft-patches/features/0034-Leaves-Catch-update-suppression-crash.patch @@ -0,0 +1,213 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Bacteriawa +Date: Tue, 2 Jun 2026 19:55:06 +0800 +Subject: [PATCH] Leaves: Catch update suppression crash + +Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com> +As a part of : Leaves (https://github.com/LeavesMC/Leaves) +Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html) + +diff --git a/net/minecraft/network/PacketProcessor.java b/net/minecraft/network/PacketProcessor.java +index 24f5b890b0126fc817863f99b676da1a548f7608..78bea975c15130c91c90f48c868ac32e2db7433f 100644 +--- a/net/minecraft/network/PacketProcessor.java ++++ b/net/minecraft/network/PacketProcessor.java +@@ -106,7 +106,19 @@ public class PacketProcessor implements AutoCloseable { + final int packetTimerId = profiler.getOrCreateTimerAndStart(() -> "Packet Handler: ".concat(ListenerAndPacket.this.packet.getClass().getName())); try { // Folia - profiler + this.packet.handle(this.listener); + } finally { profiler.stopTimer(packetTimerId); } // Folia - profiler ++ } catch (org.leavesmc.leaves.util.UpdateSuppressionException exception) { ++ if (this.listener instanceof net.minecraft.server.network.ServerGamePacketListenerImpl gamePacketListener) { ++ exception.providePlayer(gamePacketListener.player); ++ } ++ exception.consume(); + } catch (Exception var3) { ++ if (var3.getCause() instanceof org.leavesmc.leaves.util.UpdateSuppressionException exception) { ++ if (this.listener instanceof net.minecraft.server.network.ServerGamePacketListenerImpl gamePacketListener) { ++ exception.providePlayer(gamePacketListener.player); ++ } ++ exception.consume(); ++ } ++ + if (var3 instanceof ReportedException re && re.getCause() instanceof OutOfMemoryError) { + throw PacketUtils.makeReportedException(var3, this.packet, this.listener); + } +diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java +index 48f7d57f6d3ef4250e6b3cf42055d29d94d3f6e3..06482d945e4f7b1adc56168ad43bea34484a6fa9 100644 +--- a/net/minecraft/server/MinecraftServer.java ++++ b/net/minecraft/server/MinecraftServer.java +@@ -2010,11 +2010,26 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop implements ca.spottedleaf.moonrise.patch + if (ret != null) { + return ret; + } +- throw new IllegalArgumentException("Cannot get property " + property + " as it does not exist in " + this.owner); ++ IllegalArgumentException iae = new IllegalArgumentException("Cannot get property " + property + " as it does not exist in " + this.owner); ++ if (fun.bm.lophine.config.modules.fixes.UpdateSuppressionCrashFixConfig.enabled) { ++ 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; + // 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 e51f99de547f09f98b9e351bf84d8411994b62bc..7e7292dd8fcb27fdb8e69e42e5383b6c22154747 100644 +--- a/net/minecraft/world/level/chunk/LevelChunk.java ++++ b/net/minecraft/world/level/chunk/LevelChunk.java +@@ -385,6 +385,7 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource, ca.spot + return null; + } else { + Block newBlock = state.getBlock(); ++ try { + this.heightmaps.get(Heightmap.Types.MOTION_BLOCKING).update(localX, y, localZ, state); + this.heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(localX, y, localZ, state); + this.heightmaps.get(Heightmap.Types.OCEAN_FLOOR).update(localX, y, localZ, state); +@@ -453,6 +454,10 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource, ca.spot + this.markUnsaved(); + return oldState; + } ++ } catch (org.leavesmc.leaves.util.UpdateSuppressionException exception) { ++ exception.provideBlock(this.level, pos, newBlock); ++ throw exception; ++ } + } + } + } +diff --git a/net/minecraft/world/level/redstone/NeighborUpdater.java b/net/minecraft/world/level/redstone/NeighborUpdater.java +index 9b8d63f69ed1101f1b7b2728690e35165b9aeb99..44731e230869f0df058f6a426277befbb0d559e4 100644 +--- a/net/minecraft/world/level/redstone/NeighborUpdater.java ++++ b/net/minecraft/world/level/redstone/NeighborUpdater.java +@@ -87,9 +87,20 @@ public interface NeighborUpdater { + } finally { if (levelChunk != null) levelChunk.getChunkHot().stopTickingAndCount(); } // KioCG + // Spigot start + } catch (StackOverflowError ex) { ++ if (fun.bm.lophine.config.modules.fixes.UpdateSuppressionCrashFixConfig.enabled) { ++ throw new org.leavesmc.leaves.util.UpdateSuppressionException(pos, level, changedBlock, null, ex); ++ } + level.lastPhysicsProblem = pos.immutable(); + // Spigot end + } catch (Throwable var9) { ++ if (fun.bm.lophine.config.modules.fixes.UpdateSuppressionCrashFixConfig.enabled) { ++ if (var9 instanceof org.leavesmc.leaves.util.UpdateSuppressionException exception) { ++ exception.provideBlock(level, pos, changedBlock); ++ throw exception; ++ } ++ throw new org.leavesmc.leaves.util.UpdateSuppressionException(pos, level, changedBlock, null, var9); ++ } ++ + CrashReport report = CrashReport.forThrowable(var9, "Exception while updating neighbours"); + CrashReportCategory category = report.addCategory("Block being updated"); + category.setDetail( diff --git a/lophine-server/minecraft-patches/features/0035-Leaves-CCE-update-suppression.patch b/lophine-server/minecraft-patches/features/0035-Leaves-CCE-update-suppression.patch new file mode 100644 index 0000000..f7d627d --- /dev/null +++ b/lophine-server/minecraft-patches/features/0035-Leaves-CCE-update-suppression.patch @@ -0,0 +1,24 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Bacteriawa +Date: Tue, 2 Jun 2026 20:06:33 +0800 +Subject: [PATCH] Leaves: CCE update suppression + +Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com> +As a part of : Leaves (https://github.com/LeavesMC/Leaves) +Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html) + +diff --git a/net/minecraft/world/level/block/ShulkerBoxBlock.java b/net/minecraft/world/level/block/ShulkerBoxBlock.java +index 80d10b42106749254eb5f757986838acc1c064d2..ffa76dc1338c6c892a42b2148f9f01c933660b98 100644 +--- a/net/minecraft/world/level/block/ShulkerBoxBlock.java ++++ b/net/minecraft/world/level/block/ShulkerBoxBlock.java +@@ -182,7 +182,9 @@ public class ShulkerBoxBlock extends BaseEntityBlock { + @Override + protected int getAnalogOutputSignal(final BlockState state, final Level level, final BlockPos pos, final Direction direction) { + try { +- return AbstractContainerMenu.getRedstoneSignalFromBlockEntity(level.getBlockEntity(pos)); ++ return fun.bm.lophine.config.modules.experiment.RedStoneConfig.cce ++ ? AbstractContainerMenu.getRedstoneSignalFromContainer((net.minecraft.world.Container)level.getBlockEntity(pos)) ++ : AbstractContainerMenu.getRedstoneSignalFromBlockEntity(level.getBlockEntity(pos)); + } catch (ClassCastException ex) { + if (fun.bm.lophine.config.modules.fixes.UpdateSuppressionCrashFixConfig.enabled) { + throw new org.leavesmc.leaves.util.UpdateSuppressionException(pos, null, this, null, ex); diff --git a/lophine-server/minecraft-patches/features/0036-Leaves-Redstone-ignore-upwards-update.patch b/lophine-server/minecraft-patches/features/0036-Leaves-Redstone-ignore-upwards-update.patch new file mode 100644 index 0000000..c1067f2 --- /dev/null +++ b/lophine-server/minecraft-patches/features/0036-Leaves-Redstone-ignore-upwards-update.patch @@ -0,0 +1,62 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Bacteriawa +Date: Tue, 2 Jun 2026 20:15:44 +0800 +Subject: [PATCH] Leaves: Redstone ignore upwards update + +Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com> +As a part of : Leaves (https://github.com/LeavesMC/Leaves) +Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html) + +diff --git a/net/minecraft/world/level/block/ComparatorBlock.java b/net/minecraft/world/level/block/ComparatorBlock.java +index 45e11737bc2558a4ebfffe133d43111f45dd7d16..b6005e5e60ac571396d584c7f4dec3975a6f9923 100644 +--- a/net/minecraft/world/level/block/ComparatorBlock.java ++++ b/net/minecraft/world/level/block/ComparatorBlock.java +@@ -59,6 +59,9 @@ public class ComparatorBlock extends DiodeBlock implements EntityBlock { + final BlockState neighbourState, + final RandomSource random + ) { ++ if (fun.bm.lophine.config.modules.experiment.RedStoneConfig.redstoneIgnoreUpwardsUpdate && directionToNeighbour == Direction.DOWN) { ++ return state; ++ } + return directionToNeighbour == Direction.DOWN && !this.canSurviveOn(level, neighbourPos, neighbourState) + ? Blocks.AIR.defaultBlockState() + : super.updateShape(state, level, ticks, pos, directionToNeighbour, neighbourPos, neighbourState, random); +diff --git a/net/minecraft/world/level/block/RedStoneWireBlock.java b/net/minecraft/world/level/block/RedStoneWireBlock.java +index 759eb347299813c20226cc2fc5dc7718d12b7f56..66a05f099a263b0c9220f1416f3cf1221422cc20 100644 +--- a/net/minecraft/world/level/block/RedStoneWireBlock.java ++++ b/net/minecraft/world/level/block/RedStoneWireBlock.java +@@ -179,7 +179,9 @@ public class RedStoneWireBlock extends Block { + final RandomSource random + ) { + if (directionToNeighbour == Direction.DOWN) { +- return !this.canSurviveOn(level, neighbourPos, neighbourState) ? Blocks.AIR.defaultBlockState() : state; ++ return fun.bm.lophine.config.modules.experiment.RedStoneConfig.redstoneIgnoreUpwardsUpdate ++ ? state ++ : !this.canSurviveOn(level, neighbourPos, neighbourState) ? Blocks.AIR.defaultBlockState() : state; + } else if (directionToNeighbour == Direction.UP) { + return this.getConnectionState(level, state, pos); + } else { +@@ -243,7 +245,8 @@ public class RedStoneWireBlock extends Block { + BlockPos relativePos = pos.relative(direction); + BlockState relativeState = level.getBlockState(relativePos); + if (canConnectUp) { +- boolean isPlaceableAbove = relativeState.getBlock() instanceof TrapDoorBlock || this.canSurviveOn(level, relativePos, relativeState); ++ boolean isPlaceableAbove = (!fun.bm.lophine.config.modules.experiment.RedStoneConfig.redstoneIgnoreUpwardsUpdate && relativeState.getBlock() instanceof TrapDoorBlock) ++ || this.canSurviveOn(level, relativePos, relativeState); + if (isPlaceableAbove && shouldConnectTo(level.getBlockState(relativePos.above()))) { + if (relativeState.isFaceSturdy(level, relativePos, direction.getOpposite())) { + return RedstoneSide.UP; +diff --git a/net/minecraft/world/level/block/RepeaterBlock.java b/net/minecraft/world/level/block/RepeaterBlock.java +index d301ca4c91e75d715998aa7ed155fd44ccd64785..13928e667cfa36e2ebf45b30caf4c5be28f2f725 100644 +--- a/net/minecraft/world/level/block/RepeaterBlock.java ++++ b/net/minecraft/world/level/block/RepeaterBlock.java +@@ -70,6 +70,9 @@ public class RepeaterBlock extends DiodeBlock { + final BlockState neighbourState, + final RandomSource random + ) { ++ if (fun.bm.lophine.config.modules.experiment.RedStoneConfig.redstoneIgnoreUpwardsUpdate && directionToNeighbour == Direction.DOWN) { ++ return state; ++ } + if (directionToNeighbour == Direction.DOWN && !this.canSurviveOn(level, neighbourPos, neighbourState)) { + return Blocks.AIR.defaultBlockState(); + } else { diff --git a/lophine-server/minecraft-patches/features/0037-Instant-Block-Updater.patch b/lophine-server/minecraft-patches/features/0037-Instant-Block-Updater.patch new file mode 100644 index 0000000..465af7a --- /dev/null +++ b/lophine-server/minecraft-patches/features/0037-Instant-Block-Updater.patch @@ -0,0 +1,69 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Bacteriawa +Date: Tue, 2 Jun 2026 20:32:47 +0800 +Subject: [PATCH] Instant Block Updater + + +diff --git a/io/papermc/paper/threadedregions/RegionizedWorldData.java b/io/papermc/paper/threadedregions/RegionizedWorldData.java +index 64d407c5a6140a7e5dc47a8e304b4c00602e2bdd..dad62b80578f27cc39985ee6ded705bf3cc5d117 100644 +--- a/io/papermc/paper/threadedregions/RegionizedWorldData.java ++++ b/io/papermc/paper/threadedregions/RegionizedWorldData.java +@@ -44,6 +44,8 @@ import net.minecraft.world.level.chunk.LevelChunk; + import net.minecraft.world.level.material.Fluid; + import net.minecraft.world.level.pathfinder.PathTypeCache; + import net.minecraft.world.level.redstone.CollectingNeighborUpdater; ++import net.minecraft.world.level.redstone.InstantNeighborUpdater; ++import net.minecraft.world.level.redstone.NeighborUpdater; + import net.minecraft.world.level.saveddata.WanderingTraderData; + import net.minecraft.world.ticks.LevelTicks; + import org.bukkit.craftbukkit.block.CraftBlockState; +@@ -506,7 +508,7 @@ public final class RegionizedWorldData { + public long lastMidTickExecuteFailure; + // From Level + public boolean populating; +- public final CollectingNeighborUpdater neighborUpdater; ++ public final NeighborUpdater neighborUpdater; + public boolean captureBlockStates = false; + public boolean captureTreeGeneration = false; + public final Map capturedBlockStates = new java.util.LinkedHashMap<>(); // Paper +@@ -567,7 +569,9 @@ public final class RegionizedWorldData { + this.world = world; + this.blockLevelTicks = new LevelTicks<>(world::isPositionTickingWithEntitiesLoaded, world, true); + this.fluidLevelTicks = new LevelTicks<>(world::isPositionTickingWithEntitiesLoaded, world, false); +- this.neighborUpdater = new CollectingNeighborUpdater(world, world.neighbourUpdateMax); ++ this.neighborUpdater = fun.bm.lophine.config.modules.experiment.RedStoneConfig.instantBlockUpdater ++ ? new InstantNeighborUpdater(world) ++ : new CollectingNeighborUpdater(world, world.neighbourUpdateMax); + this.nearbyPlayers = new NearbyPlayers(world); + this.wireHandler = new alternate.current.wire.WireHandler(world); + this.turbo = new io.papermc.paper.redstone.RedstoneWireTurbo((RedStoneWireBlock)Blocks.REDSTONE_WIRE); +@@ -896,4 +900,4 @@ public final class RegionizedWorldData { + public int getChunkCount() { + return this.chunks.size(); + } +-} +\ No newline at end of file ++} +diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java +index f44f772628f5705c5dee9cb92295362ba09c20ce..ee10aceeddb59241e4b1d0bea021001787ea2f88 100644 +--- a/net/minecraft/server/level/ServerLevel.java ++++ b/net/minecraft/server/level/ServerLevel.java +@@ -999,11 +999,13 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet + // Paper - rewrite chunk system + profiler.pop(); + profiler.push("debugSynchronizers"); +- if (this.debugSynchronizers.hasAnySubscriberFor(DebugSubscriptions.NEIGHBOR_UPDATES)) { +- regionizedWorldData.neighborUpdater // Folia - region threading +- .setDebugListener(blockPos -> this.debugSynchronizers.broadcastEventToTracking(blockPos, DebugSubscriptions.NEIGHBOR_UPDATES, blockPos)); +- } else { +- regionizedWorldData.neighborUpdater.setDebugListener(null); // Folia - region threading ++ if (regionizedWorldData.neighborUpdater instanceof net.minecraft.world.level.redstone.CollectingNeighborUpdater neighborUpdater) { ++ if (this.debugSynchronizers.hasAnySubscriberFor(DebugSubscriptions.NEIGHBOR_UPDATES)) { ++ neighborUpdater // Folia - region threading ++ .setDebugListener(blockPos -> this.debugSynchronizers.broadcastEventToTracking(blockPos, DebugSubscriptions.NEIGHBOR_UPDATES, blockPos)); ++ } else { ++ neighborUpdater.setDebugListener(null); // Folia - region threading ++ } + } + + this.debugSynchronizers.tick(this.server.debugSubscribers()); diff --git a/lophine-server/minecraft-patches/features/0038-Revert-TrapDoorBlock-changes-form-Paper.patch b/lophine-server/minecraft-patches/features/0038-Revert-TrapDoorBlock-changes-form-Paper.patch new file mode 100644 index 0000000..e398f6d --- /dev/null +++ b/lophine-server/minecraft-patches/features/0038-Revert-TrapDoorBlock-changes-form-Paper.patch @@ -0,0 +1,43 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Bacteriawa +Date: Tue, 2 Jun 2026 20:37:27 +0800 +Subject: [PATCH] Revert TrapDoorBlock changes form Paper + + +diff --git a/net/minecraft/world/level/block/TrapDoorBlock.java b/net/minecraft/world/level/block/TrapDoorBlock.java +index cfc8b668980e0cba74b3f0d42c4902eb6aa8b01e..da4a39e3e8bf9672614a04fae9834a54555cc9f1 100644 +--- a/net/minecraft/world/level/block/TrapDoorBlock.java ++++ b/net/minecraft/world/level/block/TrapDoorBlock.java +@@ -133,31 +133,7 @@ public class TrapDoorBlock extends HorizontalDirectionalBlock implements SimpleW + if (!level.isClientSide()) { + boolean signal = level.hasNeighborSignal(pos); + if (signal != state.getValue(POWERED)) { +- // Paper start - Call BlockRedstoneEvent +- if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBinaryRedstoneChange(level, pos, signal)) { +- return; +- } +- // Paper end - Call BlockRedstoneEvent +- // Paper start - break redstone on trapdoors early +- boolean open = state.getValue(TrapDoorBlock.OPEN) != signal; +- // note: this must run before any state for this block/its neighbours are written to the world +- // we allow the redstone event to fire so that plugins can block +- if (signal && open) { // if we are now powered and it caused the trap door to open +- // in this case, first check for the redstone on top first +- BlockPos abovePos = pos.above(); +- BlockState above = level.getBlockState(abovePos); +- if (above.getBlock() instanceof RedStoneWireBlock) { +- level.setBlock(abovePos, Blocks.AIR.defaultBlockState(), Block.UPDATE_CLIENTS | Block.UPDATE_NEIGHBORS); +- Block.popResource(level, abovePos, new ItemStack(net.minecraft.world.item.Items.REDSTONE)); +- // now check that this didn't change our state +- if (level.getBlockState(pos) != state) { +- // our state was changed, so we cannot propagate this update +- return; +- } +- } +- } +- if (open) { +- // Paper end - break redstone on trapdoors early ++ if (state.getValue(OPEN) != signal) { + state = state.setValue(OPEN, signal); + this.playSound(null, level, pos, signal); + } diff --git a/lophine-server/minecraft-patches/features/0039-Leaves-Prevent-loss-of-item-drops-due-to-update-supp.patch b/lophine-server/minecraft-patches/features/0039-Leaves-Prevent-loss-of-item-drops-due-to-update-supp.patch new file mode 100644 index 0000000..b0ac880 --- /dev/null +++ b/lophine-server/minecraft-patches/features/0039-Leaves-Prevent-loss-of-item-drops-due-to-update-supp.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Bacteriawa +Date: Tue, 2 Jun 2026 20:42:45 +0800 +Subject: [PATCH] Leaves: Prevent loss of item drops due to update suppression + when breaking blocks + +Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com> +As a part of : Leaves (https://github.com/LeavesMC/Leaves/blob/ea91106ae57fc4cc14e2e0225009cf9919072f7f/leaves-server/minecraft-patches/features/0090-Servux-Protocol.patch) +Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html) + +diff --git a/net/minecraft/server/level/ServerPlayerGameMode.java b/net/minecraft/server/level/ServerPlayerGameMode.java +index e1de10e1a0ec221a1109a03d86fddf47b1c06a5f..d8cba057be61005d75b8c66910096aec148e2e2a 100644 +--- a/net/minecraft/server/level/ServerPlayerGameMode.java ++++ b/net/minecraft/server/level/ServerPlayerGameMode.java +@@ -392,7 +392,16 @@ public class ServerPlayerGameMode { + this.level.getCurrentWorldData().captureDrops = new java.util.ArrayList<>(); // Folia - region threading + // CraftBukkit end + BlockState adjustedState = block.playerWillDestroy(this.level, pos, state, this.player); +- boolean changed = this.level.removeBlock(pos, false); ++ boolean changed; ++ org.leavesmc.leaves.util.UpdateSuppressionException updateSuppressionException = null; ++ try { ++ changed = this.level.removeBlock(pos, false); ++ } catch (org.leavesmc.leaves.util.UpdateSuppressionException exception) { ++ updateSuppressionException = exception; ++ updateSuppressionException.provideBlock(this.level, pos, block); ++ updateSuppressionException.providePlayer(this.player); ++ changed = false; ++ } + if (SharedConstants.DEBUG_BLOCK_BREAK) { + LOGGER.info("server broke {} {} -> {}", pos, adjustedState, this.level.getBlockState(pos)); + } +@@ -424,6 +433,9 @@ public class ServerPlayerGameMode { + if (event.isDropItems()) { + org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDropItemEvent(bblock, bState, this.player, itemsToDrop); // Paper - capture all item additions to the world + } ++ if (updateSuppressionException != null) { ++ throw updateSuppressionException; ++ } + + // Drop event experience + if (changed) { diff --git a/lophine-server/minecraft-patches/features/0040-Leaves-Do-not-reset-placed-block-on-exception-Do-not.patch b/lophine-server/minecraft-patches/features/0040-Leaves-Do-not-reset-placed-block-on-exception-Do-not.patch new file mode 100644 index 0000000..3d98d16 --- /dev/null +++ b/lophine-server/minecraft-patches/features/0040-Leaves-Do-not-reset-placed-block-on-exception-Do-not.patch @@ -0,0 +1,52 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Bacteriawa +Date: Tue, 2 Jun 2026 20:50:57 +0800 +Subject: [PATCH] Leaves: Do not reset placed block on exception & Do not + prevent block entity and entity crash at LevelChunk + +Co-authored by: MC_XiaoHei +As a part of : Leaves (https://github.com/LeavesMC/Leaves) +Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html) + +diff --git a/net/minecraft/world/item/BlockItem.java b/net/minecraft/world/item/BlockItem.java +index 06160c24f1ffbe1445284bc81598cabb3ad20477..ca3f31a72060f797115787302d32a019fa8243e0 100644 +--- a/net/minecraft/world/item/BlockItem.java ++++ b/net/minecraft/world/item/BlockItem.java +@@ -69,20 +69,8 @@ public class BlockItem extends Item { + BlockState placedState = level.getBlockState(pos); + if (placedState.is(placementState.getBlock())) { + placedState = this.updateBlockStateFromTag(pos, level, itemStack, placedState); +- // Paper start - Reset placed block on exception +- try { + this.updateCustomBlockEntityTag(pos, level, player, itemStack, placedState); + updateBlockEntityComponents(level, pos, itemStack); +- } catch (Exception ex) { +- ((org.bukkit.craftbukkit.block.CraftBlockState) previousState).revertPlace(); +- if (player instanceof ServerPlayer serverPlayer) { +- net.minecraft.server.MinecraftServer.LOGGER.warn("Player {} tried placing invalid block", player.getScoreboardName(), ex); +- serverPlayer.connection.disconnect(net.minecraft.network.chat.Component.literal("Packet processing error")); +- return InteractionResult.FAIL; +- } +- throw ex; // Rethrow exception if not placed by a player +- } +- // Paper end - Reset placed block on exception + placedState.getBlock().setPlacedBy(level, pos, placedState, player, itemStack); + // CraftBukkit start - special case for handling block placement with water lilies, frog spawn and snow buckets + if (player != null && (this instanceof PlaceOnWaterBlockItem || this instanceof SolidBucketItem)) { +diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java +index 7e7292dd8fcb27fdb8e69e42e5383b6c22154747..b7ba4d8ed2cc65ba0e85a3cdf8b6568a7c9c02f1 100644 +--- a/net/minecraft/world/level/chunk/LevelChunk.java ++++ b/net/minecraft/world/level/chunk/LevelChunk.java +@@ -1000,12 +1000,6 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource, ca.spot + + profiler.pop(); + } catch (Throwable var5) { +- // Paper start - Prevent block entity and entity crashes +- final String msg = String.format("BlockEntity threw exception at %s:%s,%s,%s", io.papermc.paper.util.MCUtil.getLevelName(LevelChunk.this.getLevel()), this.getPos().getX(), this.getPos().getY(), this.getPos().getZ()); +- net.minecraft.server.MinecraftServer.LOGGER.error(msg, var5); +- net.minecraft.world.level.chunk.LevelChunk.this.level.getCraftServer().getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerInternalException(msg, var5))); // Paper - ServerExceptionEvent +- LevelChunk.this.removeBlockEntity(this.getPos()); +- // Paper end - Prevent block entity and entity crashes + } + } + }