From 74cc5505b021aab0e0b8f1552200d146a13656ad Mon Sep 17 00:00:00 2001 From: Xiao-no-love <140927721+Xiao-no-love@users.noreply.github.com> Date: Tue, 13 Oct 2026 18:28:28 +0800 Subject: [PATCH] =?UTF-8?q?fix(mixin):=20=E5=AD=90=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E7=BA=BF=E7=A8=8B=E4=B8=8A=20updateNeighbourForOutputSignal=20?= =?UTF-8?q?=E7=AC=AC=E4=BA=8C=E6=A0=BC=E9=82=BB=E5=B1=85=E8=AE=BF=E9=97=AE?= =?UTF-8?q?=E5=8A=A0=E5=8A=A0=E8=BD=BD=E5=AE=88=E5=8D=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根因:Level.updateNeighbourForOutputSignal 遍历6方向,第一格邻居有 hasChunkAt 守卫, 但若第一格是红石导体,会再往外取第二格(blockpos.relative(direction))并直接 getBlockState ——没有 hasChunkAt 守卫。原版主线程会按需同步生成区块;DR 细粒度子任务线程上则触发 ServerChunkCacheMixin.modzuozhi_subtaskSafeGetChunk 的 required=true 未命中分支, 抛 IllegalStateException + FaultGuard 降级。异常被 LevelChunk$BoundTickingBlockEntity.tick 崩溃保护包成 CrashReport("Ticking block entity"),同时细粒度被关 → 跑图卡顿。 实测:18:10:03 trial_spawner(-6765,-15,1376) tick 时 setChanged → updateNeighbourForOutputSignal → 第二格 getBlockState(chunk=-423,85 未加载) → 崩。 修复:新增 LevelNeighbourSignalGuardMixin,@WrapOperation 拦第二格 getBlockState(ordinal=1), 子任务线程 + !hasChunkAt 时返回 VOID_AIR(getWeakChanges=false,不传播红石信号), 与 getBlockState 越界分支语义一致。主线程/维度 worker 行为不变。 参考:Folia 对 updateNeighbourForOutputSignal 加加载守卫的同类修复思路。 --- .../mixin/LevelNeighbourSignalGuardMixin.java | 45 +++++++++++++++++++ .../resources/dimensionalripper.mixins.json | 1 + 2 files changed, 46 insertions(+) create mode 100644 src/main/java/dev/modzuozhi/mixin/LevelNeighbourSignalGuardMixin.java diff --git a/src/main/java/dev/modzuozhi/mixin/LevelNeighbourSignalGuardMixin.java b/src/main/java/dev/modzuozhi/mixin/LevelNeighbourSignalGuardMixin.java new file mode 100644 index 0000000..67ed3c0 --- /dev/null +++ b/src/main/java/dev/modzuozhi/mixin/LevelNeighbourSignalGuardMixin.java @@ -0,0 +1,45 @@ +package dev.modzuozhi.mixin; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import dev.modzuozhi.core.dimthread.FineGrainScheduler; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +/** + * 修复细粒度子任务线程上 {@code Level.updateNeighbourForOutputSignal} 触发未加载区块同步生成导致崩溃。 + *
+ * 原版该方法遍历 6 个方向:第一格邻居用 {@code hasChunkAt} 守卫,但若第一格是红石导体, + * 会再往外取第二格({@code blockpos.relative(direction)})并直接 {@code getBlockState}——没有 hasChunkAt 守卫。 + * 原版主线程上这个 {@code getBlockState} 会按需同步生成/加载区块;但在 DR 细粒度子任务线程上, + * {@code ServerChunkCacheMixin.modzuozhi_subtaskSafeGetChunk} 检测到 required=true 未命中, + * 会抛 {@code IllegalStateException}(并触发 {@link dev.modzuozhi.core.dimthread.FaultGuard} 降级)。 + * 该异常被 {@code LevelChunk$BoundTickingBlockEntity.tick} 的崩溃保护包成 CrashReport, + * 表现为"Ticking block entity"崩溃 + 细粒度被关 → 跑图卡顿。 + *
+ * 修复:拦第二格的 {@code getBlockState}(ordinal=1)。目标区块未加载时返回 {@code VOID_AIR} + * (与 {@code getBlockState} 越界分支语义一致:{@code VOID_AIR.getWeakChanges} 为 false, + * 不会触发 {@code neighborChanged},等价"该方向无红石信号传播"),避免子任务线程请求同步生成。 + *
+ * 仅在子任务线程生效;主线程/维度 worker 行为完全不变。
+ */
+@Mixin(Level.class)
+public abstract class LevelNeighbourSignalGuardMixin {
+
+ @WrapOperation(method = "updateNeighbourForOutputSignal",
+ at = @At(value = "INVOKE",
+ target = "Lnet/minecraft/world/level/Level;getBlockState(Lnet/minecraft/core/BlockPos;)Lnet/minecraft/world/level/block/state/BlockState;",
+ ordinal = 1))
+ private BlockState modzuozhi_guardSecondNeighbour(Level level, BlockPos pos, Operation