v1.7.3 - Entity Lookup Remove Guard
Pre-release新增修复:entity-lookup-remove-guard
拦截 PersistentEntitySectionManager.stopTracking 中的 EntityLookup.remove 调用,捕获 Int2ObjectLinkedOpenHashMap.fixPointers 抛出的 ArrayIndexOutOfBoundsException,避免单个实体移除失败导致整个服务端 tick 崩溃。
New Fix: entity-lookup-remove-guard
Catches ArrayIndexOutOfBoundsException thrown by Int2ObjectLinkedOpenHashMap.fixPointers inside EntityLookup.remove during PersistentEntitySectionManager.stopTracking, preventing single-entity removal failures from crashing the server tick loop.
修复的崩溃 / Crash being fixed
java.lang.ArrayIndexOutOfBoundsException: Index -1 out of bounds for length 513
at it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap.fixPointers(Int2ObjectLinkedOpenHashMap.java:979)
at it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap.removeEntry(Int2ObjectLinkedOpenHashMap.java:263)
at it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap.remove(Int2ObjectLinkedOpenHashMap.java:372)
at net.minecraft.world.level.entity.EntityLookup.remove(EntityLookup.java:52)
at net.minecraft.world.level.entity.PersistentEntitySectionManager.stopTracking(PersistentEntitySectionManager.java:157)
...
at net.minecraft.server.MinecraftServer.tickServer(MinecraftServer.java:1383)
根因 / Root cause
Sable 的 SubLevel 实体管理(跨维度/多线程)破坏了 EntityLookup 内部 Int2ObjectLinkedOpenHashMap 的链表状态。当某个 entry 的 prev/next 指针被设为 -1(表示"无链接"的哨兵值)却被当作数组下标访问时,fixPointers 抛出 Index -1 out of bounds for length N。异常沿 PersistentEntitySectionManager.stopTracking → updateChunkStatus → ChunkMap.onFullChunkStatusChange → ChunkHolder.demoteFullChunk → MinecraftServer.tickServer 一路传播,导致 tick 循环崩溃。
Sable's SubLevel entity management (cross-dimension / multi-threaded) corrupts the internal linked-map state of EntityLookup's backing Int2ObjectLinkedOpenHashMap. When an entry's prev / next pointer is set to -1 (sentinel meaning "no link") but later accessed as an array index, fixPointers throws Index -1 out of bounds for length N. The exception propagates up through PersistentEntitySectionManager.stopTracking -> updateChunkStatus -> ChunkMap.onFullChunkStatusChange -> ChunkHolder.demoteFullChunk -> MinecraftServer.tickServer, crashing the tick loop.
实现方式 / How
-
在
PersistentEntitySectionManager.stopTracking中的EntityLookup.remove调用上加@Redirect -
在调用点捕获
ArrayIndexOutOfBoundsException(以及其他Throwable) -
每次发生时输出一条
WARN日志(包含实体引用),便于排查 -
tick 继续正常运行,仅跳过出错实体的移除操作
-
@Redirecton theEntityLookup.removeinvocation insidePersistentEntitySectionManager.stopTracking -
Catches
ArrayIndexOutOfBoundsException(and any otherThrowable) at the call site -
Emits a single
WARNlog per occurrence with the entity reference for diagnosis -
Tick continues normally; only the offending entity's removal is skipped
注意事项 / Caveats
这是治标修复。它让服务器保持运行但不会修复 Int2ObjectLinkedOpenHashMap 的底层状态——损坏的 entry 仍然存在,可能在后续 remove 调用中再次出现。真正的修复应在 Sable 的实体卸载 / SubLevel 实体追踪代码中(参见 sable.mixins.json:entity.entity_unloading.PersistentEntitySectionManagerMixin 和 sable.mixins.json:entity.server_entities_tick.ChunkMapMixin)。
This is a symptomatic fix. It keeps the server alive but does not repair the underlying Int2ObjectLinkedOpenHashMap state — the corrupted entry remains and may surface again on subsequent remove calls. The true fix belongs in Sable's entity unloading / SubLevel entity tracking code (see sable.mixins.json:entity.entity_unloading.PersistentEntitySectionManagerMixin and sable.mixins.json:entity.server_entities_tick.ChunkMapMixin).
兼容性 / Compatibility
- Mixin 目标 / Mixin target:
net.minecraft.world.level.entity.PersistentEntitySectionManager - Redirect 目标 / Redirect target:
stopTracking中的EntityLookup.remove(Entity)调用 - Sable 的
PersistentEntitySectionManagerMixin使用@Inject注入在不同方法(processChunkUnload)上,因此不会发生 handler 冲突 / Sable'sPersistentEntitySectionManagerMixinuses@Injecton a different method (processChunkUnload), so there is no handler conflict.
产物 / Artifact
FuckSable-Unofficial-1.7.3.jar
环境兼容 / Environment
- Sable 1.x 与 2.x / Sable 1.x and 2.x
- NeoForge 1.21.1
- Mohist/Youer 混合服务端 / Mohist/Youer hybrid servers