fix(mixin): 子任务线程上 updateNeighbourForOutputSignal 第二格邻居访问加加载守卫
根因: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 加加载守卫的同类修复思路。
This commit is contained in:
1 parent
92ba852fc5
commit
74cc5505b0
2 files changed
+46
No files matched your search
@@ -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} 触发未加载区块同步生成导致崩溃。
|
||||
* <p>
|
||||
* 原版该方法遍历 6 个方向:第一格邻居用 {@code hasChunkAt} 守卫,但<strong>若第一格是红石导体,
|
||||
* 会再往外取第二格</strong>({@code blockpos.relative(direction)})并直接 {@code getBlockState}——<strong>没有 hasChunkAt 守卫</strong>。
|
||||
* 原版主线程上这个 {@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"崩溃 + 细粒度被关 → 跑图卡顿。
|
||||
* <p>
|
||||
* 修复:拦第二格的 {@code getBlockState}(ordinal=1)。目标区块未加载时返回 {@code VOID_AIR}
|
||||
* (与 {@code getBlockState} 越界分支语义一致:{@code VOID_AIR.getWeakChanges} 为 false,
|
||||
* 不会触发 {@code neighborChanged},等价"该方向无红石信号传播"),避免子任务线程请求同步生成。
|
||||
* <p>
|
||||
* 仅在子任务线程生效;主线程/维度 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<BlockState> original) {
|
||||
if (FineGrainScheduler.inSubTask() && !level.hasChunkAt(pos)) {
|
||||
// 未加载的第二格邻居:不请求同步生成,返回 VOID_AIR(getWeakChanges=false,不传播信号)。
|
||||
return Blocks.VOID_AIR.defaultBlockState();
|
||||
}
|
||||
return original.call(level, pos);
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,7 @@
|
||||
"LevelGetChunkMixin",
|
||||
"LevelMixin",
|
||||
"LevelRandomMixin",
|
||||
"LevelNeighbourSignalGuardMixin",
|
||||
"LevelTicksMixin",
|
||||
"LivingEntityGetInBlockStateMixin",
|
||||
"MinecraftServerDimMixin",
|
||||
|
||||
Reference in new issue
Block a user