Skip to content

Powerful overseer. - #4354

Merged
WhereisFff merged 10 commits into
Anvil-Dev:dev/26.1/1.6from
alpha-hhh:26.1/1.6/overseer
Aug 9, 2026
Merged

Powerful overseer.#4354
WhereisFff merged 10 commits into
Anvil-Dev:dev/26.1/1.6from
alpha-hhh:26.1/1.6/overseer

Conversation

@alpha-hhh

@alpha-hhh alpha-hhh commented Aug 6, 2026

Copy link
Copy Markdown
Contributor
  • resolved [Feature] 原版加载变得非常简单,监督者该加强了,几个监督者加强建议 #1582
  • 修改了监督者的加载方式,现在监督者的一个底座方块对应一个区块(以方块偏移量对应区块偏移),监督者本体所在区块默认加载且运算随机刻
  • 监督者现在最高为4级
  • 使更多方块可以作为监督者的底座方块
  • 现在铁块、金块、绿宝石块和钻石块可以用来提升监督者的等级,但不进行加载
  • 皇家钢系列方块强加载对应区块、运算随机刻,浮霜系列方块强加载对应区块、不运算随机刻
  • 下界合金块和余烬系列方块强加载对应区块、运算随机刻、启用火焰蔓延,多相物质块强加载对应区块、不运算随机刻、启用火焰蔓延
  • 超限合金块强加载对应区块、不运算随机刻、不启用火焰蔓延、启用区块内生物自然刷新和刷怪笼生物刷新(生物自然刷新要求该区块位于玩家2048区块内)
  • 各功能冲突时优先实现:不运算随机刻、启用火焰蔓延、启用生物刷新
  • 现在/overseer命令可以显示每个监督者的等级,加载区块数量和所有监督者加载区块总数

@Gugle2308

Copy link
Copy Markdown
Collaborator

⚠️ Dangerous command requires approval:

timeout 20 curl -s "https://piston-meta.mojang.com/mc/game/version_manifest_v2.json" -o /tmp/vm.json && python3 -c "
import json
d=json.load(open('/tmp/vm.json'))
vs=[v['id'] for v in d['versions']]
p...

Reason: script execution via -e/-c flag

Reply /approve to execute, /approve session to approve this pattern for the session, /approve always to approve permanently, or /deny to cancel.

@Gugle2308

Copy link
Copy Markdown
Collaborator

⚠️ Dangerous command requires approval:

curl -sL "https://api.github.com/repos/Anvil-Dev/AnvilCraft/issues/1582" | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('body','')[:2500])" 2>/dev/null || curl -sL "https://api.git...

Reason: Security scan — [HIGH] Pipe to interpreter: curl | python3: Command pipes output from 'curl' directly to interpreter 'python3'. Downloaded content will be executed without inspection.
Safer: tirith run https://api.github.com/repos/Anvil-Dev/AnvilCraft/issues/1582 — or: vet https://api.github.com/repos/Anvil-Dev/AnvilCraft/issues/1582 (https://getvet.sh); script execution via -e/-c flag

Reply /approve to execute, /approve session to approve this pattern for the session, /approve always to approve permanently, or /deny to cancel.

@Gugle2308

Copy link
Copy Markdown
Collaborator

All verifications complete. Compile-level references check out (all 16 series blocks exist on the target branch). Here is the review.

代码审查摘要 — PR #4354

操作: edited
范围: 35 个文件 (25 Java, 19 新增, 2 删除) / 1905 行 diff
主题: 监督者重做 — 底座方块→区块映射、4 级金字塔、按底座方块类型区分的区块特性(随机刻/火焰蔓延/生物刷新)、/overseer 命令

🔴 关键

  • OverseerBlockEntity.java — 结构损坏后重建同结构,区块加载永不恢复(状态残留 bug)
    tick()!checkOverseerBlocks() 分支执行 LevelLoadManager.unregister() 后直接 return没有重置 oldLevel / oldTierHash。场景:玩家敲掉顶部/中间的一节监督者方块(底部 BE 仍在 tick)→ 已注销;随后原样补回 → scanPyramidBase() 得到相同 level + 相同 tierHash → levelChangedtiersChanged 均为 false → 提前 return,永远不会重新 register,区块加载静默失效(直到再次改动结构)。修复:在无效分支里将 oldLevel = -1; oldTierHash = 0;(或取消哈希短路,始终重同步)。

  • OverseerBlockEntity.scanPyramidBase + LoadChunkData.createLoadChunkData — 区块边界处底座映射错位 ±1 个区块
    映射记录的是底座方块相对监督者的方块偏移 (dx, dz)(dx∈[-4,4]),但 createLoadChunkData 把它当区块偏移用:new ChunkPos(centerChunk.x() + m.chunkOffsetX(), ...)。监督者位于区块边界 4 格以内时(每轴约 12.5% 的摆放位置),底座方块实际所在区块与计算结果相差 1:真实区块不会被强加载、拿不到特性标志;反而多加载了一个没有底座的空区块,特性标志(不随机刻/火焰蔓延/生物刷新)全部作用到错误区块。例如 x mod 16 = 14 时 dx=+2 的方块实际在 cx+1,代码却映射到 cx+2。修复:按实际方块坐标计算 ChunkPos.containing(centerPos.offset(dx, 0, dz)),或把记录字段改成绝对坐标而非区块偏移。

⚠️ 警告

  • ChunkFeatureManager.java — 静态表只以 ChunkPos 为键,不含维度
    CHUNK_SOURCESResourceKey<Level> 维度键,而 LevelLoadManager.CHUNK_REF_COUNT 是分维度的——两处不对称。若两个维度在同一区块坐标都有监督者,特性(跳过随机刻/火焰蔓延/刷怪笼强制激活/自然刷新)会跨维度串扰(如主世界刷怪笼因下界同坐标的超限底座而强制激活)。建议键改为 (维度, ChunkPos) 或查找时传入 level。

  • SourceFlags.TRANSCENDIUM = NO_RANDOM_TICK | ALLOW_NATURAL_SPAWN | ALLOW_SPAWNER_SPAWN — 与 PR 描述不符
    描述只提到超限合金块"启用生物自然刷新和刷怪笼生物刷新",未提随机刻;代码同时禁用了随机刻。若是有意设计(刷怪塔免作物生长)请在描述/注释中说明,否则需移除 NO_RANDOM_TICK

  • ServerLevelFireSpreadMixin.java — 无条件强制 canSpreadFireAround 返回 true
    对已托管且允许火焰蔓延的区块,无论原值直接返回 true。请确认 26.1 中该方法语义:若它同时承担 doFireTick 游戏规则或方块可替代性判定,此覆盖会绕过 gamerule、甚至可能让火焰判定通过不可燃位置(是否实际起火仍受邻块可燃性限制)。另需确认"任一来源命中即生效"的合并策略:同一区块同时被浮霜(禁随机刻)和皇家钢(要随机刻)监督者覆盖时,随机刻被跳过——是否符合预期?

  • LevelLoadManager.getAllOverseerForcedChunkCount(ServerLevel level) — 参数未使用
    统计的是所有维度的 OVERSEER 加载区块总数,而 /overseer 列表按查询维度过滤。摘要行显示的总数与列表范围不一致,易误导。应过滤 data.getServerLevel().dimension() 或删除参数。

  • ChunkFeatureManager.clear() 是死代码
    全库无调用点(已 grep 确认)。虽然正常流程下 discard 会清空条目,但建议在 ServerStoppedEvent 显式调用 clear(),同时清理 OverseerUtil.placedOverseers,避免同 JVM 内跨世界残留。

💡 建议

  • 性能scanPyramidBase() 每 tick 全量扫描,满级最坏 9+25+49+81 = 164 次 getBlockState + tag 查询/监督者/tick。建议改为周期重扫(如每 N tick 或 NeighborChanged 时)再比对哈希。
  • NaturalSpawnerMixin.java:ThreadLocal 在 HEAD 设置、仅 RETURN 清除,spawn 过程中抛异常会残留脏值;建议 try/finally。
  • ItemTooltipManager.java:英文文本混入全角标点 "9x9 range), different base blocks..."( 已原样进入 en_ud),请改用 ASCII 标点;"9x9 range" 建议明确为 "9x9 chunk range"(方块 vs 区块易混淆)。
  • MobCategoryMixin.javashouldAllowNaturalSpawn(null) 依赖 HashMap.get(null) 语义返回 false,虽安全但脆弱,建议显式判空。

🟢 看起来不错

  • 旧 typo 类清理彻底:LoadChuckDataLoadChunkDataRandomChuckTickLoadManager 删除,所有引用点(OverseerBlockEntity / WormholeStabilizerHandler / ServerLifecycleEventListener)同步更新。
  • forceChunk 按维度引用计数 + applied 幂等守卫,修复了旧版多个加载源同区块互相顶掉的问题,reload() 先 discard 后 apply 的顺序也正确。
  • 新设计(mixin 跳过随机刻)比旧的 RandomChuckTickLoadManager.tick() 手动补 tick 更干净——旧实现对 isNeedRandomTick=true 的区块存在双重随机刻的嫌疑。
  • ServerLevelRandomTickMixin 的重入守卫(@Unique 字段 + 取消后以 tickSpeed=0 重入)正确,只跳过随机刻、保留实体/BE/计划刻。
  • 标签体系清晰:tier_0(铁/金/绿宝/钻石)只提升等级不加载 ✓,系列标签(royal/frost/ember)可复用;en_us/en_ud 同步再生成。
  • /overseer 命令:权限门控、按维度追踪(OverseerUtil)、坐标点击复制,实现完整。
  • 已交叉验证目标分支 dev/26.1/1.6TRANSCENDIUM_BLOCKMULTIPHASE_MATTER_BLOCK、16 个系列方块、SimpleMultiPartBlock.isMainPart 均存在,无编译级引用问题。

📋 声称验证表

声称 状态 对应实现
resolved #1582(监督者加强) 4 级金字塔、底座扩展、特性区分、/overseer 命令
一个底座方块对应一个区块 ✅(边界 ±1 偏移 bug 除外) LoadChunkData.createLoadChunkData + scanPyramidBase
最高 4 级 TIER_RADIUS {1,2,3,4}、MAX_LEVEL=4
铁/金/绿宝石/钻石升级但不加载 tier_0 tag + blockTier >= 1 过滤
皇家钢 = 强加载 + 随机刻 DEFAULT=0
浮霜 = 强加载不随机刻 FROST=NO_RANDOM_TICK
下界合金/余烬 = +火焰蔓延 FIRE
多相物质 = 不随机刻 + 火焰蔓延 MULTIPHASE
超限合金 = 自然刷新 + 刷怪笼刷新 ⚠️ TRANSCENDIUM 额外禁用了随机刻(描述未提)
/overseer 显示等级/区块数/总数 ⚠️ 总数跨维度统计与列表维度不一致

🧪 测试建议

被测目标 推荐测试场景 优先级
OverseerBlockEntity.tick() 敲掉顶部方块→原样补回→断言重新 register(复现 stale 状态 bug) 🔴
LoadChunkData.createLoadChunkData() 监督者摆放在 x/z mod 16 ∈ {13,14,15,0,1,2} 边界位置,断言各底座方块实际区块被加载 🔴
ChunkFeatureManager 两个维度同坐标区块,断言特性不串扰 🟡
ServerLevelRandomTickMixin 浮霜/皇家钢同区块重叠时随机刻行为(确认 any-source-wins 是否符合预期) 🟡
BaseSpawnerMixin / ChunkMapMixin 无玩家在场时刷怪笼是否持续刷怪;玩家 >128 但 <2048 区块时自然刷新 🟡

结论: REQUEST_CHANGES — 架构与方向正确,但存在两个必须修复的逻辑缺陷:结构重建后不重新注册(静默丢失加载),以及区块边界处底座→区块映射错位。另有跨维度串扰与描述不一致问题建议一并确认。


由 Hermes Agent 审查

@Gugle2308

Copy link
Copy Markdown
Collaborator

代码审查摘要 — PR #4354

操作: opened
范围: 35 个文件(25 Java,19 新增,2 删除)/ 1905 行 diff

整体架构清晰:LoadChuckData/RandomChuckTickLoadManager 合并为 LoadChunkData + ChunkFeatureManager,底座方块按层级(3x3→9x9)逐层扫描、每方块映射一个区块、按方块类型给区块打 feature 标志位,8 个 mixin 分别实现"跳过随机刻 / 允许火焰蔓延 / 允许自然刷新 / 允许刷怪笼刷新 / 扩大清除距离"。方向正确,但跨维度隔离存在两个关键缺陷

🔴 关键

  • ChunkFeatureManager 完全没有维度隔离ChunkFeatureManager.java + 全部 8 个 mixin)
    CHUNK_SOURCES 仅以 ChunkPos 为键,所有 shouldSkipRandomTick/shouldAllowFireSpread/shouldAllowNaturalSpawn/shouldAllowSpawnerSpawn/getAllNaturalSpawnChunks 均不含维度参数,mixin 调用时也只传 ChunkPos。同一个区块坐标的 feature 标志会在所有维度同时生效:下界某坐标放一个浮霜底座监督者 → 主世界同坐标区块随机刻被静默取消;主世界超限合金块启用自然刷新 → 下界同坐标区块也强制刷怪、怪物清除距离被放大到 32768 格。LevelLoadManagerCHUNK_REF_COUNT 反而是按 ResourceKey<Level> 分键的——同一个 PR 内两处处理不一致。建议给 ChunkFeatureManager 全部方法加维度参数(mixin 侧 ServerLevel/ChunkMap 都能拿到 level)。

  • LevelLoadManager.removeAll() 在任意维度卸载时清空所有维度的加载数据LevelLoadManager.java
    LevelEventListener.onLevelUnload每个维度的卸载都会调用 removeAll(level),而它遍历的是全局 LOAD_DATA_MAP(所有维度),用被卸载维度的 level 去 discard 其他维度的数据,随后 LOAD_DATA_MAP.clear() + CHUNK_REF_COUNT.clear()。后果链:

    1. 玩家离开下界 → 下界卸载(常规行为)→ 主世界所有监督者的登记被清空;
    2. 主世界监督者的 BE 每 tick 仍在跑,但 tickif (!levelChanged && !tiersChanged) return;(第 906 行)不检查 LevelLoadManager.checkRegistered(pos) → 永远不会重新注册;
    3. 已强制加载的区块 ticket 残留在主世界 chunkmap 里,登记数据却已丢失 → 这些区块本会话内永远无法解除强制加载(区块泄漏),且随机刻/火焰/刷怪等覆盖全部失效。
      修复建议:removeAll 按维度清理;tick 早退条件加上 && LevelLoadManager.checkRegistered(pos)LOAD_DATA_MAP 改按 dimension + BlockPos 复合键(当前仅按 BlockPos 分键,两个维度同坐标的监督者会互相覆盖登记)。

⚠️ 警告

  • OverseerBlockEntity 结构破损路径不重置缓存checkOverseerBlocks() 为 false 时只 unregister 就 return,oldLevel/oldTierHash 保留原值;若上部方块被短暂拆掉再原样复原(底座未变),下一 tick 早退,区块加载永久丢失。与上面的"外部清空后不重注册"是同一类问题,建议失败路径把 oldLevel = -1; oldTierHash = 0; 重置。
  • 底座方块偏移 → 区块偏移是近似映射LoadChunkData.createLoadChunkData)— BlockOffsetMapping 里存的是方块偏移(±4),却直接当作区块偏移加到 centerChunk 上。监督者位于区块边缘(如 x=12,偏移 4 的方块已跨入下一区块)时,加载区域和 feature 标志会整体漂移 ±1 区块:应改为 ChunkPos.containing(centerPos.offset(dx, 0, dz))
  • 混合底座时标志合并语义与描述不符 — 同偏移 (dx,dz) 在不同层级都存在方块(同心方环共享偏移),一个区块会聚合最多 4 个来源的标志,且"任一来源生效"。例:3x3 皇家钢核心 + 5x5 浮霜环 → 内圈 3x3 区块同时收到 DEFAULT 和 FROST → shouldSkipRandomTick 返回 true → 皇家钢核心的随机刻被浮霜环压制,与"皇家钢运算随机刻"的描述相悖。建议确认:随机刻是否应改为"存在任一来源要求运算则不跳过"。
  • 等级显示与加载面积可背离 — 任意合法底座方块(含 tier-0 铁/金/钻/绿宝石)都能补完任意层级(含 tier-3 9x9 层),全铁底座可显示 4 级但只加载中心 1 个区块;tier-0 方块不产生映射是本 PR 的设计,但"层级完整性"不区分方块 tier 会放大显示与实际的落差,建议在 tooltip/文档中说明。
  • zh_cn.json 未同步src/main/resources/assets/anvilcraft/lang/zh_cn.jsontooltip.anvilcraft.item.overseer(.shift) 仍是"3x3 皇家钢 / 最高 3 层 / 5x5"旧文案,command.anvilcraft.overseer.entry 仍显示"随机刻",且缺 command.anvilcraft.overseer.summary 新键。
  • en_us tooltip 混入全角逗号 — "...(max 4 layers, 9x9 range), different base blocks..." 的","应为半角 ", "(ItemTooltipManager.java 与生成的 lang 都要改)。

💡 建议

  • BlockOffsetMapping 字段名 chunkOffsetX/Z 实为方块偏移,易误导;tier 字段在 createLoadChunkData 中完全未参与计算(仅用于变更哈希),建议删除或实际使用。
  • NaturalSpawnerMixin 用两个独立 @Inject 设置/清除 CURRENT_SPAWNING_CHUNK,异常路径会泄漏 ThreadLocal 值,建议 try/finally。
  • OverseerBlockEntity.tick 每 tick 无条件全量扫描底座(最多 9x9x4≈324 次 getBlockState + 哈希),全部底座方块都是合法方块时可以先做轻量变更检测。
  • getAllOverseerForcedChunkCount(ServerLevel level) 忽略 level 参数,统计的是所有维度的监督者区块数,而命令 list 是按维度列出的,总数与明细口径不一致。
  • ChunkFeatureManager.clear() 无调用方,同 JVM 内服务器重启(集成服)会残留旧状态,建议接入 removeAll/停止事件。
  • 超限合金块的 TRANSCENDIUM 标志同时禁用了随机刻NO_RANDOM_TICK | ALLOW_NATURAL_SPAWN | ALLOW_SPAWNER_SPAWN),PR 描述未提及,请确认是否有意。
  • 8 个新 mixin 的目标方法(尤其 ServerLevel.canSpreadFireAroundDistanceManager.getSpawnCandidateChunksChunkMap.playerIsCloseEnoughForSpawning)建议在开发环境实际加载验证,mixin 目标失效会在类加载时直接崩溃。

🟢 看起来不错

  • CHUNK_REF_COUNT 按维度做引用计数、forceChunk 在 count 0↔1 边界才真正调 setChunkForced,多监督者重叠区块的引用管理正确。
  • ServerLevelRandomTickMixin 用实例标志位防重入、取消后以 tickChunk(chunk, 0) 重入——只跳过随机刻而保留 inhabited time 等其余逻辑,设计巧妙且正确。
  • LoadChunkDataapplied/removed 双标志 + lazy() 延迟队列使 apply/discard 幂等,服务器启动时序处理得当。
  • 旧 API(LoadChuckData/RandomChuckTickLoadManager)全部调用方迁移完毕,WormholeStabilizerHandler 改用 createSimpleLoadChunkData(1, pos, level) 后行为与原 isNeedRandomTick=false 等价(无回归)。
  • 4 个底座 tier tag + 3 个系列 tag 的注册、生成 JSON、ModBlocks 引用三方一致;MAX_LEVEL=4 与 blockstate 属性范围吻合。

📋 声称验证表

声称 状态 对应实现
resolved #1582 ⚠️ 无法从 diff 验证 issue 内容
一个底座方块对应一个区块 createLoadChunkData 方块偏移→区块偏移(区块边缘 ±1 漂移见警告)
最高 4 级 TIER_RADIUS {1,2,3,4}MAX_LEVEL=4、tooltip 更新
更多方块可作底座 overseer_base_tier_0..3 四个 tag
铁/金/绿宝石/钻石提升等级但不加载 blockTier >= 1 过滤,tier-0 不产生映射
皇家钢:强加载+随机刻 SourceFlags.DEFAULT
浮霜:强加载、不随机刻 FROST + ServerLevelRandomTickMixin
下界合金/余烬:+随机刻+火焰蔓延 FIRE
多相物质:不随机刻+火焰蔓延 MULTIPHASE
超限合金:自然刷新+刷怪笼刷新(2048 区块内) TRANSCENDIUM + ChunkMapMixin/DistanceManagerMixin/MobMixin 等(附赠禁用随机刻,待确认)

结论: REQUEST_CHANGES — 核心机制与版本描述一致,但 ChunkFeatureManager 无维度隔离、removeAll 跨维度清空 + BE 不重注册这两个问题会让多维度使用场景(本模组的常态)出现区块泄漏和加载失效,建议修复后再合并。

🧪 测试建议

被测目标 推荐测试场景 优先级
LevelLoadManager.removeAll 下界无玩家卸载后,主世界监督者仍保持加载/可解除加载 🔴
ChunkFeatureManager.* 主世界 + 下界同坐标各放一个监督者,验证 feature 不串维度 🔴
OverseerBlockEntity.tick 拆掉上部方块再复原(底座不变),验证重新加载 🟡
LoadChunkData.createLoadChunkData 监督者放区块边界处,验证加载区块与底座方块实际所在区块一致 🟡
ServerLevelRandomTickMixin 浮霜与皇家钢混合底座,验证内圈核心随机刻行为 🟡
OverseerCommand list 多维度监督者时总数与分维度列表口径一致 🟢

由 Hermes Agent 审查

@Gugle2308

Copy link
Copy Markdown
Collaborator

💾 Self-improvement review: Patched SKILL.md in skill 'minecraft-mod-pr-review' (1 replacement).

@Gugle2308

Copy link
Copy Markdown
Collaborator

💾 Self-improvement review: Patched references/chunk-loading-review-patterns.md in skill 'minecraft-mod-pr-review' (1 replacement). · Patched SKILL.md in skill 'minecraft-mod-pr-review' (1 replacement).

@alpha-hhh
alpha-hhh marked this pull request as draft August 6, 2026 11:28
@Gugle2308

Copy link
Copy Markdown
Collaborator

交叉引用验证完毕,信息足够。整理审查意见。

代码审查摘要 — PR #4354

操作: converted_to_draft(按流程仅报严重问题,comment 级别)
范围: 35 个文件(25 Java, 19 新增, 2 删除)/ ~1900 行 diff
目标: 监督者(Overseer)区块加载系统重做 — 底座方块→区块映射、4 级金字塔、按方块系列区分加载特性、8 个新 mixin

🔴 关键

  1. OverseerBlockEntity.tick() — 塔身短暂损坏恢复后永远不再注册
    checkOverseerBlocks() 失败分支里 unregister 后直接 return没有重置 oldLevel / oldTierHash。若 MID/TOP 部分被活塞推动或临时替换后恢复原状,恢复后的 tick 中 levelChanged=false && tiersChanged=false → 提前 return → 该监督者永久停止加载区块,直到玩家改动底座才会恢复。修复:失败分支中同时 this.oldLevel = -1; this.oldTierHash = 0;(旧代码同样有此隐患,但本 PR 重写了整个 tick,正是修复时机)。

⚠️ 警告

  1. ChunkFeatureManager / LOAD_DATA_MAP 无维度限定 — 跨维度同坐标区块特性串扰
    CHUNK_SOURCESChunkPos 为键、LOAD_DATA_MAPBlockPos 为键,均不含 ResourceKey<Level>。新增的 8 个 mixin 全部通过 ChunkFeatureManager(只看 ChunkPos)查特性。两个维度在相同区块坐标各有一个监督者时:register/unregister 互相覆盖,且主世界的浮霜监督者会禁用末地同坐标区块的随机刻/刷怪等特性。CHUNK_REF_COUNT 已经按维度键控了,建议 feature 表也把维度加进键。

  2. MobCategoryMixin + ThreadLocal 全局副作用
    getDespawnDistance()spawnForChunk 期间对所有 MobCategory 返回 32768。NaturalSpawner 内部任何依赖该值的逻辑(如 mobcap 统计范围)都会在超限合金区块的刷怪 pass 中被放大,可能饱和全局刷怪容量。且它和 MobMixin 的 per-mob WrapOperation 功能重叠——建议确认 NaturalSpawner 的调用点后评估能否删掉这个 mixin,只保留 MobMixin。

  3. WormholeStabilizerHandler 行为变化(需确认是否有意)
    createLoadChuckData(1, pos, false, level)isNeedRandomTick=false(无随机刻);新 createSimpleLoadChunkData(1, pos, level) → sourceFlags=0 → 随机刻默认开启。虫洞稳定器加载的区块现在会运算随机刻,行为反转。

  4. OverseerCommand 汇总数跨维度串数
    getAllOverseerForcedChunkCount(level)level 参数从未使用,直接对全局 LOAD_DATA_MAP 统计——/overseer list <dim> 的 "Loads N chunk(s) in total" 是所有维度的总和,与所选维度无关。建议按 data.getServerLevel() == level 过滤。

  5. DistanceManagerMixin.getSpawnCandidateChunks — 每调用全量拷贝
    每次调用把原始 LongIterator 整体拷贝进 LongOpenHashSet 再遍历全部监督者区块。若该方法由 ServerLevel.tick 每 tick 调用,大视野服务器会每 tick 产生大分配。建议确认调用频率并考虑缓存。

  6. 混合材料金字塔的特性 OR 合并
    同一 (dx,dz) 位置的金字塔各层方块都映射到同一区块,特性按 OR 合并——混合材料的 4 级金字塔其中心 3x3 区块会同时获得全部特性(无随机刻+火焰+自然刷新+刷怪笼)。若意图是各层方块独立生效,需确认这是设计而非遗漏。

💡 建议

  • ItemTooltipManager — en_us tooltip 混入全角逗号:"9x9 range), different..."(en_ud 已同步,源头需改)
  • ChunkFeatureManagerclear() 无任何调用者(dead code)
  • LoadChunkDataBlockOffsetMapping.tier 字段在 createLoadChunkData 中未使用(仅参与 hash),如无用途可删

🟢 看起来不错

  • forceChunk 引用计数按维度键控,多监督者重叠加载同一区块时正确(count==0 才 force,count<=1 才 unforce)
  • 8 个新 mixin 全部注册进 anvilcraft.mixins.json
  • LoadChuckDataLoadChunkData 重命名完整无残留(全仓 grep 确认),RandomChuckTickLoadManager 删除干净
  • ServerLevelRandomTickMixin 的 reentrancy 守卫 + tickSpeed=0 重入方案正确:只跳过随机刻,tickChunk 其余逻辑照常
  • 特性按 tag 驱动(royal_series/ember_series/frost_series + 4 个 tier tag),数据驱动设计清晰

📋 声称验证表

声称 状态 对应实现
一个底座方块对应一个区块 scanPyramidBaseBlockOffsetMapping(dx,dz)ChunkPos(center+dx, center+dz)
监督者最高 4 级 TIER_RADIUS={1,2,3,4}MAX_LEVEL=4
更多方块可作为底座 4 个 overseer_base_tier_N tag
铁/金/绿宝石/钻石提升等级但不加载 tier_0 tag;仅 blockTier>=1 加入 offsetMappings
皇家钢强加载+随机刻 DEFAULT=0 → 不跳过随机刻
浮霜强加载不运算随机刻 FROST + ServerLevelRandomTickMixin
下界合金/余烬强加载+随机刻+火焰蔓延 FIRE + ServerLevelFireSpreadMixin
多相物质强加载+不随机刻+火焰蔓延 MULTIPHASE
超限合金强加载+自然刷新+刷怪笼刷新(2048 区块) TRANSCENDIUM + NaturalSpawner/ChunkMap/DistanceManager/Mob/BaseSpawner mixins
/overseer 显示等级、加载区块数、总数 ⚠️ 等级与单监督者区块数 ✅;总数跨维度串数(见 #5

结论: COMMENT — 整体设计与声称一致,实现质量良好。建议转正式 review 前优先处理 🔴#1(塔身恢复后不重新注册)和 ⚠️#2(维度键控),其余可合并前再定。


由 Hermes Agent 审查

@Gugle2308

Copy link
Copy Markdown
Collaborator

💾 Self-improvement review: Patched SKILL.md in skill 'minecraft-mod-pr-review' (1 replacement). · Patched references/chunk-loading-review-patterns.md in skill 'minecraft-mod-pr-review' (1 replacement).

@Gugle2308

Copy link
Copy Markdown
Collaborator

分析完成。所有交叉引用验证完毕,现在输出审查意见。


代码审查摘要 — PR #4354

操作: synchronize
范围: 35 个文件(25 Java,8 新增 Mixin,6 新增 tag JSON,2 语言文件)/ 1950 行 diff
特性: 监督者(Overseer)区块加载系统重写 — 解决 #1582,底座分层(最高 4 级)+ 按底座方块类型区分随机刻/火焰蔓延/生物刷新/刷怪笼行为 + /overseer 命令

🔴 关键

  • ChunkFeatureManager.java + NaturalSpawnerMixin.java — CURRENT_SPAWNING_DIMENSION ThreadLocal 从未被 set,超限合金块的"生物自然刷新"特性在远离玩家处完全失效。 该 ThreadLocal 在 ChunkFeatureManager 中声明(L202),被 DistanceManagerMixin.onHasPlayersNearby(L1605)、DistanceManagerMixin.onGetSpawnCandidateChunks(L1620)、MobCategoryMixin.onGetDespawnDistance(L1662)三处读取,但全 diff 中只有 CURRENT_SPAWNING_CHUNK.set()(NaturalSpawnerMixin L1738)。dimension 恒为 null → shouldAllowNaturalSpawn(null, chunkPos) 恒返回 false → 这三个注入全部静默失效。PR 声称"生物自然刷新要求该区块位于玩家2048区块内",但实际超出的只有 ChunkMapMixin(用 player.level().dimension() 直接取值,可用)和 MobMixinself.level().dimension(),可用)——hasPlayersNearby/候选区块扩展这两个关键闸门是死代码,刷怪仍被限制在原版玩家附近距离。修复:在 NaturalSpawnerMixin 的 spawnForChunk HEAD/RETURN 中同时 set/remove CURRENT_SPAWNING_DIMENSION

⚠️ 警告

  • ServerLevelRandomTickMixin — 依赖一个行为假设翻转:强加载区块会原生调用 tickChunk 旧实现用 RandomChuckTickLoadManager.tick() 手动调用 tickChunk 正是因为在旧版本强加载区块默认不运算随机刻。新设计只做"抑制"(FROST 区块重入 tickSpeed=0),若 26.1 中强加载区块不原生走 tickChunk,则皇家钢(DEFAULT)的"运算随机刻"声称也会失效,且 FROST 抑制变成空操作。需运行时验证强加载区块确实会触发 tickChunk。
  • LevelLoadManager.register/unregister — LOAD_DATA_MAP 仅以 BlockPos 为键,跨维度碰撞会破坏引用计数并造成永久强加载泄漏。 两个维度同坐标各放一个监督者时,第二个 register 被 containsKey 静默丢弃;其 tick 中 checkRegistered(pos) 误判为已注册 → unregister(pos, 本维度level) 会把另一个维度的数据 markRemoved 并以错误维度执行 discard → CHUNK_REF_COUNT 错乱、被误删数据的区块永远无法 setChunkForced(false)。建议键改为 (dimension, pos) 组合。
  • OverseerBlockEntity.tick — 结构破坏后 oldLevel 不重置。 checkOverseerBlocks() 失败路径直接 return,未将 oldLevel 复位为 -1(旧代码在重新注册前会重置)。/overseer list 会显示陈旧的 "Lv.3, loads: 0 chunk(s)"。
  • scanPyramidBase — 底座方块偏移(块)直接当作区块偏移(chunk)使用。 BlockOffsetMapping(dx, dz, ...) 中 dx/dz 是方块级偏移,createLoadChunkDatacenterChunk.x() + m.chunkOffsetX() 按区块粒度相加——3x3 底座加载 3x3 区块(9 chunks),9x9 底座加载 9x9(81 chunks),加载区以监督者所在区块为中心做偏移映射,并非底座方块实际所在区块。若"一个底座方块对应一个区块"的本意是"加载包含该底座的区块",应改用 ChunkPos.containing(blockPos)。请确认设计意图。
  • removeAll 从未被调用 + 静态状态无清理。 LevelLoadManager.removeAll 在目标分支上没有任何调用点,且 ServerStopped 未清理 LOAD_DATA_MAP/CHUNK_REF_COUNTOverseerUtil.placedOverseers 同样无清理(其他管理器如 PowerGrid/FluidNetworkManager 都有 clear())。服务端重启后 /overseer 命令会遍历陈旧坐标并刷 "Invalid overseer" warn 日志。
  • WormholeStabilizerHandler — 虫洞加载行为变化。 LoadChuckData.createLoadChuckData(1, pos, false, level)(isNeedRandomTick=false → 无随机刻)改为 createSimpleLoadChunkData(1, pos, level)(DEFAULT flags → 随机刻开启)。若旧行为确实是无随机刻,这是回归;需确认是否有意。
  • 19 个文件缺 EOF 换行(含全部新 Java 文件、6 个新 tag JSON、改动的 LevelLoadManager)。仓库现有生成文件均以 \n 结尾,建议与 datagen 输出保持一致。
  • en_us.json / ItemTooltipManager — 英文 tooltip 混入中文全角逗号: "max 4 layers, 9x9 range), different base blocks...",应为半角 ,

💡 建议

  • OverseerBlockEntity.tick — 每 tick 全量扫描底座(4 级满配时 9+25+49+81=164 次 getBlockState/tag 判断),可考虑每 N tick 扫描或缓存结果。
  • MobCategoryMixin 与 MobMixin 功能重复:MobMixin 已用 WrapOperation 覆盖 checkDespawn 的 despawnDistance,MobCategoryMixin 实际是死代码(其读取的 CURRENT_SPAWNING_CHUNK 只在 spawnForChunk 期间有效,checkDespawn 路径上不可用)。建议删除或合并。
  • LoadChunkData L218: serverLevel,Source.SIMPLE 缺空格(纯格式)。
  • OverseerCommand: 成功返回 0、失败返回 1,与 brigadier 惯例相反(成功应返回非 0),建议统一为现有命令的风格。

🟢 看起来不错

  • 引用计数设计CHUNK_REF_COUNT 按 (dimension, chunk) 计数,多个加载源重叠时不会重复 setChunkForced(false),reload 顺序改为先 discard 后 apply 也正确。
  • 随机刻抑制实现isReentering 守卫 + 重入 tickChunk(chunk, 0) 的方案正确,且与现有 ServerLevelMixin(只注入 addEntity/addFreshEntity)无冲突。
  • 标签分层清晰:tier 0-3 + royal/frost/ember series 的嵌套结构,BlockTagLoader 与生成的 6 个 JSON 完全一致。
  • 命令权限写法(permissions().hasPermission)、HoverEvent.ShowText/CopyToClipboardsendSuccess 均与仓库现有命令模式一致;lang 三处(en_us/en_ud/CommandLang)同步 ✓。

📋 声称验证表

声称 状态 对应实现
解决 #1582,重写加载方式 LoadChunkData(新)/ LevelLoadManager / ChunkFeatureManager
一个底座方块对应一个区块 ⚠️ 偏移映射实现(见警告),语义需确认
监督者最高 4 级 TIER_RADIUS {1,2,3,4},tooltip "max 4 layers, 9x9 range"
更多方块可作底座 tier 0-3 tags(铁/金/钻/绿宝石 → 皇家/浮霜 → 下界合金/余烬/多相 → 超限)
铁金绿钻提升等级但不加载 getBlockTier >= 1 过滤 + getBlockSourceFlags
皇家钢默认加载(强加载+随机刻) ⚠️ DEFAULT flags — 依赖强加载区块原生 tickChunk 的假设(见警告)
浮霜强加载不随机刻 FROST=NO_RANDOM_TICK + ServerLevelRandomTickMixin
下界合金+余烬:随机刻+火焰蔓延 FIRE flag + ServerLevelFireSpreadMixin
多相物质块:不随机刻+火焰蔓延 MULTIPHASE flags
超限合金块:自然刷新+刷怪笼刷新(2048区块内) 刷怪笼 ✅(BaseSpawnerMixin);自然刷新 🔴 失效(ThreadLocal 未 set)
/overseer 显示等级、加载区块数、总数 OverseerCommand + getOverseerChunkCount + getAllOverseerForcedChunkCount

结论: REQUEST_CHANGES — 必须修复 🔴(CURRENT_SPAWNING_DIMENSION 从未 set 导致超限合金块的自然刷新特性静默失效),并确认强加载区块随机刻的运行时行为;其余警告项请逐条确认。

🧪 测试建议

被测目标 推荐测试场景 优先级
OverseerBlockEntity.tick 跨维度同坐标监督者并存;结构破坏后 /overseer 显示 🔴
ServerLevelRandomTickMixin 皇家钢 vs 浮霜区块随机刻差异;randomTickSpeed=0 游戏规则 🔴
ChunkFeatureManager 自然刷怪链路 超限合金块区块在玩家 >128 块外是否刷怪、怪物防消失 🔴
LevelLoadManager.forceChunk 两个监督者重叠加载同一区块的增减计数 🟡
LoadChunkData.createLoadChunkData 混合底座(tier0 填充 + tier1 加载)的区块集合与 flags 🟡

由 Hermes Agent 审查

@Gugle2308

Copy link
Copy Markdown
Collaborator

💾 Self-improvement review: Patched references/chunk-loading-review-patterns.md in skill 'minecraft-mod-pr-review' (1 replacement). · Patched SKILL.md in skill 'minecraft-mod-pr-review' (1 replacement).

@Gugle2308

Copy link
Copy Markdown
Collaborator

分析完成。以下是审查意见。


代码审查摘要 — PR #4354

操作: synchronize
范围: 35 个文件(25 Java, 19 新增, 2 删除)/ 1948 行 diff
主题: 监督者(Overseer)区块加载系统重构 — 金字塔底座分级、按方块类型分区加载特性、/overseer 命令

架构总览

  • LoadChuckData(拼写错误)→ 重命名为 LoadChunkData,旧 RandomChuckTickLoadManager 删除,新增 ChunkFeatureManager 统一管理按维度×区块×来源的加载特性(跳过随机刻/火焰蔓延/自然刷怪/刷怪笼刷怪)
  • LevelLoadManager 新增 CHUNK_REF_COUNT 引用计数,多个加载源重叠同一区块时只 setChunkForced 一次,全部释放才卸载 — 实现正确
  • 底座改为 4 层倒金字塔(3×3 → 5×5 → 7×7 → 9×9),每层半径 TIER_RADIUS={1,2,3,4},每个 tier≥1 的底座方块映射一个区块偏移("一个底座方块对应一个区块")
  • 8 个新 mixin + 2 个事件监听扩展 + 1 个新命令

🔴 关键

  1. ChunkFeatureManager.CURRENT_SPAWNING_DIMENSION 从未被赋值 → DistanceManagerMixin 两个注入全部失效(死代码),超限合金"2048 区块内自然刷怪"功能未实现

    • 全仓库 grep 确认:CURRENT_SPAWNING_DIMENSION 只有定义和 .get()DistanceManagerMixin 两处、MobCategoryMixin 一处),没有任何 .set() 调用NaturalSpawnerMixin 只 set/remove CURRENT_SPAWNING_CHUNK
    • 后果链:DistanceManager.hasPlayersNearby 注入中 shouldAllowNaturalSpawn(null, chunkPos)CHUNK_SOURCES.get(null) → null → 返回 false → 超限合金区块的 hasPlayersNearby 永远保持 FALSEgetSpawnCandidateChunks 注入中 getAllNaturalSpawnChunks(null) → 空集 → 超限合金区块不会进入自然刷怪候选列表
    • 而自然刷怪候选区块的判定(ChunkMap.tickupdatingChunkMap + hasPlayersNearby)正是依赖这个被写死的路径。ChunkMapMixin.playerIsCloseEnoughForSpawning(用 player.level().dimension(),有效)只影响已是候选区块的距离放宽,救不了候选列表。
    • 结果:"超限合金块启用区块内生物自然刷新"实际上只在玩家处于原版判定距离内时生效,"2048 区块"扩展不工作MobCategoryMixin 同理——getDespawnDistanceMob.checkDespawn(实体 tick 栈)中调用,不在 spawnForChunk 栈内,CURRENT_SPAWNING_CHUNK 此时也是 null,该注入永远不生效(despawn 距离扩展实际靠 MobMixin 的 WrapOperation 用实体自身位置实现,那部分是有效的)。
    • 修复建议:在 NaturalSpawnerMixin HEAD 注入中同时 CURRENT_SPAWNING_DIMENSION.set(level.dimension())(RETURN 一并 remove),或给 DistanceManagerMixin 注入 ChunkMap 的 level 字段。同时可删除冗余的 MobCategoryMixin
  2. OverseerBlockEntity.tick():监督者上部方块被破坏后修复,永远不会重新注册加载

    • checkOverseerBlocks() 失败分支(BE 所在 BOTTOM 方块仍在,MID/TOP 被破坏)执行 unregister 后直接 return不重置 oldLevel/oldTierHash
    • 玩家修复 MID/TOP 方块后:扫描结果与旧值完全相同 → levelChanged=false && tiersChanged=false → 提前 return → 区块加载永不恢复(直到底座被改动触发 hash 变化)。
    • 旧代码同样存在此问题,但本次是重写,应顺手修复:失败分支中把 oldLevel=-1; oldTierHash=0 与 unregister 一起重置(或统一走 unregister+reset 公共路径)。

⚠️ 警告

  • ItemTooltipManager.java:597 + 生成数据 en_us.json/en_ud.json — 英文 tooltip 混入全角逗号:"...(max 4 layers, 9x9 range), different base blocks provide different effects",应为半角 , 。源字符串在 SHIFT.put 中,生成文件需重新 runData。
  • OverseerCommand.java:6 — 残留编辑标记注释:import net.minecraft.commands.Commands; // ← 新增:普通导入,提交前应删除。
  • ChunkFeatureManager.clear() 定义后从未被调用OverseerUtil.placedOverseers 也没有服务器停止清理路径(ServerLifecycleEventListener.onServerStopped 未清)。虽然 BE unload 事件会逐条移除,但异常终止/世界整体卸载时可能残留跨会话脏数据。建议在 ServerStoppedEventLevelEvent.Unload 中统一清理。
  • OverseerBlockEntity.VALID_BASE_TAGS — raw TagKey[] + @SuppressWarnings("unchecked"),建议 TagKey<?>[] 或逐字段声明,避免压制警告掩盖问题。

💡 建议

  • NaturalSpawnerMixinCURRENT_SPAWNING_CHUNK HEAD set / RETURN remove 建议改为 try/finally(spawnForChunk 中途异常时 RETURN 注入不执行,ThreadLocal 残留旧值;虽然后续会被覆盖,但更稳妥)。
  • LevelLoadManager.getAllOverseerForcedChunkCount.distinct().mapToInt(cp -> 1).sum() 可直接 .distinct().count()
  • LOAD_DATA_MAP/CHUNK_REF_COUNTBlockPos 为 key 不含维度——wormhole 稳定器与监督者(或跨维度同坐标)共用一个注册表,存在理论冲突。旧代码遗留,非本 PR 引入,但重写注册表时可顺带改为维度感知 key。
  • scanPyramidBase 每 tick 全量扫描最多 164 次 getBlockState(9×9+7×7+5×5+3×3),可接受但属热路径,后续可考虑邻接更新缓存。
  • 多底座重叠区块的特性为 OR 语义(任一 frost 覆盖即跳过随机刻、任一 ember 覆盖即允许火焰),是合理设计取舍,建议在 wiki/tooltip 说明,避免玩家困惑。

🟢 看起来不错

  • 引用计数 forceChunk 正确处理多加载源重叠:count==0setChunkForced(true)count<=1 才 false,无重复强制/提前释放。
  • ServerLevelRandomTickMixin 的重入标志 + tickChunk(chunk, 0) 技巧干净:取消后以 tickSpeed=0 重入,跳过随机刻但保留调度刻/BE tick,且 tickSpeed<=0 守卫防止原版本就无随机刻时的无谓重入。
  • LoadChuckDataLoadChunkData 重命名 + RandomChuckTickLoadManager 删除,语义更清晰;标签分层(tier_0..3 + royal/frost/ember_series)数据驱动,扩展性好。
  • LoadChunkData.apply/discardapplied 幂等标志 + FIFO 延迟队列顺序保证,启动期注册/卸载不会错序。
  • BaseSpawnerMixin/ServerLevelFireSpreadMixin 的守卫(先查原版结果、isChunkManaged 前置)正确,未破坏非超限合金区块行为。

📋 声称验证表

声称 状态 对应实现
一个底座方块对应一个区块 scanPyramidBaseBlockOffsetMapping(dx,dz,...) → chunk 偏移
监督者最高 4 级 TIER_RADIUS={1,2,3,4}MAX_LEVEL=4、tooltip "max 4 layers, 9x9 range"
更多方块可作为底座 overseer_base_tier_0..3 标签(铁/金/钻/绿宝石 + 系列方块 + 下界合金 + 多相 + 超限合金)
铁/金/绿宝石/钻石提升等级但不加载 blockTier>=1 才加入 offsetMappings,tier_0 方块只过 isTierComplete
皇家钢默认加载(强加载+随机刻) SourceFlags.DEFAULT=0 → 不跳过随机刻
浮霜强加载但不运算随机刻 FROST=NO_RANDOM_TICK + ServerLevelRandomTickMixin
下界合金+余烬:随机刻+火焰蔓延 FIRE=ALLOW_FIRE_SPREAD(不含 NO_RANDOM_TICK)+ ServerLevelFireSpreadMixin
多相物质:不随机刻+火焰蔓延 MULTIPHASE=NO_RANDOM_TICK|ALLOW_FIRE_SPREAD
超限合金:自然刷新+刷怪笼刷新(玩家 2048 区块内) ⚠️ 部分 刷怪笼 ✅(BaseSpawnerMixin);自然刷怪 ❌(CURRENT_SPAWNING_DIMENSION 从未 set,DistanceManagerMixin 失效);despawn 距离 ✅(MobMixin
/overseer 命令显示等级/区块数/总数 OverseerCommand + getOverseerChunkCount/getAllOverseerForcedChunkCount
resolved #1582 功能重做方向一致(issue 内容无法从 diff 验证)

结论: REQUEST_CHANGES — 两个关键问题:① 超限合金"自然刷怪 2048 区块扩展"因 CURRENT_SPAWNING_DIMENSION 从未赋值而整体失效(功能声称未落地);② 监督者上部方块破坏后修复无法恢复区块加载(用户可见的恢复性 bug)。修复后建议实测验证:超限合金底座上无玩家(但 2048 区块内)时怪物是否自然刷新、监督者 MID/TOP 破坏再修复后是否恢复强加载。

🧪 测试建议

被测目标 推荐测试场景 优先级
OverseerBlockEntity.tick MID/TOP 方块破坏→修复后注册恢复;底座方块替换为同 tier/flags 方块(hash 不变不重复注册);tier_0 铁底座 4 层 vs royal 4 层的加载范围差异 🔴
ChunkFeatureManager 特性聚合 同一区块被 frost+royal 重叠加载 → 随机刻被跳过;ember+royal 重叠 → 火焰允许;多维度同坐标不串扰 🔴
LevelLoadManager.forceChunk 引用计数 两个监督者重叠加载同一区块,逐个移除 → 最后一个移除才 unforce 🟡
BaseSpawnerMixin 超限合金区块内无玩家时刷怪笼激活;royal 区块内刷怪笼保持原版行为 🟡
ServerLevelRandomTickMixin 重入后调度刻/BE tick 仍执行;游戏规则 randomTickSpeed=0 时不干预 🟢

由 Hermes Agent 审查

@Gugle2308

Copy link
Copy Markdown
Collaborator

💾 Self-improvement review: Patched references/chunk-loading-review-patterns.md in skill 'minecraft-mod-pr-review' (1 replacement). · Patched SKILL.md in skill 'minecraft-mod-pr-review' (1 replacement).

@Gugle2308

Copy link
Copy Markdown
Collaborator

⚠️ Dangerous command requires approval:

curl -sL "https://api.github.com/repos/Anvil-Dev/AnvilCraft/issues/1582" | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('body','')[:2000])" 2>/dev/null || curl -sL "https://api.git...

Reason: Security scan — [HIGH] Pipe to interpreter: curl | python3: Command pipes output from 'curl' directly to interpreter 'python3'. Downloaded content will be executed without inspection.
Safer: tirith run https://api.github.com/repos/Anvil-Dev/AnvilCraft/issues/1582 — or: vet https://api.github.com/repos/Anvil-Dev/AnvilCraft/issues/1582 (https://getvet.sh); script execution via -e/-c flag

Reply /approve to execute, /approve session to approve this pattern for the session, /approve always to approve permanently, or /deny to cancel.

@Gugle2308

Copy link
Copy Markdown
Collaborator

All analysis complete. Here's my review:


代码审查摘要 — PR #4354

操作: synchronize
范围: 35 个文件 (25 Java, 19 新增, 2 删除) / 1947 行 diff
架构: 监督者重构为「金字塔底座扫描 + 逐块→逐区块映射 + 按维度/区块/来源注册的 ChunkFeatureManager + 引用计数强加载」,并用 8 个新 mixin 实现随机刻/火焰蔓延/生物刷新控制,删除了旧的 LoadChuckDataRandomChuckTickLoadManager

🔴 关键问题

1. CURRENT_SPAWNING_DIMENSION 从未被赋值 → 超限合金块「生物自然刷新」整条链路失效
ChunkFeatureManager.java:17 声明了 CURRENT_SPAWNING_DIMENSION,但整个 PR 树中只有 3 处 .get()DistanceManagerMixin:27,42MobCategoryMixin:23),没有任何一处 .set()NaturalSpawnerMixin 只 set/remove 了 CURRENT_SPAWNING_CHUNK)。因此三个消费者永远读到 nullshouldAllowNaturalSpawn(null, ...) 永远返回 false:

  • DistanceManagerMixin.anvilcraft$onGetSpawnCandidateChunksgetAllNaturalSpawnChunks(null) 返回空集 → 超限合金块区块永远不会被加入刷怪候选列表NaturalSpawner.spawnForChunk 根本不会对这些区块执行 → 无自然刷新;
  • DistanceManagerMixin.anvilcraft$onHasPlayersNearby → 永不生效;
  • MobCategoryMixin.anvilcraft$onGetDespawnDistance → 永不生效(反离/不消失由 MobMixin 按实体实际位置兜底,但那只解决"不消失",不解决"生成")。

⚠️ 即使把 set() 补进 NaturalSpawnerMixin 也修不好:getSpawnCandidateChunks()ServerChunkCache.tickspawnForChunk 循环之前调用,而 ThreadLocal 在每次 spawnForChunk RETURN 就被 remove,调用候选列表时仍是 null。建议:

  • ServerChunkCache.tick(或 DistanceManager.tick)的候选区块迭代外层 set/remove 维度,或
  • DistanceManagerMixin 在 ThreadLocal 为 null 时遍历 CHUNK_SOURCES 全部维度取并集(最简单稳妥)。

ChunkMapMixin.playerIsCloseEnoughForSpawning 是唯一能取到维度(player.level().dimension())的路径,但它只在候选区块的生成流程内被调用——候选列表为空时它也不会被触发。

⚠️ 警告

  • OverseerBlockEntity.java tick 失效路径状态残留checkOverseerBlocks() 失败时只 unregister 就 return,oldLevel/oldTierHash 不重置。若 MID/TOP 监督者方块被短暂移除后恢复(如活塞推动、玩家拆装),重新扫描得到相同的 level+hash → 提前 return → 永不重新注册,区块保持不加载。修复:失败路径中重置 oldLevel = -1; oldTierHash = 0;,或在提前 return 条件中加入 !LevelLoadManager.checkRegistered(pos)
  • WormholeStabilizerHandler.java 行为变更 — 旧 createLoadChunkData(1, pos, false, level)isNeedRandomTick=false,不运算随机刻)改为 createSimpleLoadChunkData(1, pos, serverLevel)(默认 flags=0 → 强加载区块按原版默认运算随机刻)。虫洞稳定器的 3x3 加载区现在会跑随机刻,与旧行为相反,请确认是否有意。
  • 每 tick 扫描开销OverseerBlockEntity.tick() 每 tick 全量扫描 4 层金字塔(3×3+5×5+7×7+9×9 = 164 个方块),每个方块还要做最多 4 次 tag 判断(isTierComplete + getBlockTier + getBlockSourceFlags),约 1000+ 次 tag 查找/监督者/tick,且提前 return 发生在扫描之后,无法避开。建议按方块更新事件(neighbor update/block event)触发重扫,或每 N tick 节流。
  • en_us.json tooltip 混入全角逗号"(max 4 layers, 9x9 range), different base blocks..." 英文文本里混入中文全角逗号" ,",en_ud 同步带入。应改为英文标点。
  • 19 处文件缺末尾换行No newline at end of file),含 12 个新 Java 文件,checkstyle 可能报错。

💡 建议

  • 跨监督者/混合金字塔的 flag 冲突语义ChunkFeatureManagershouldSkipRandomTick/shouldAllowFireSpread 等对同一区块多来源取 OR:随机刻"跳过"优先于"默认运算"(皇家钢与浮霜重叠时整块停随机刻),火焰/刷新"允许"优先。建议在文档或注释中明确该优先级,确认是否符合预期。
  • OVERSEER_BASE 旧 tag 已成死代码 — 新逻辑只读 tier 0-3 tag,ModBlockTags.OVERSEER_BASE 仅剩 ModBlocks 注册时打标和旧 overseer_base.json 数据文件,无任何读取方,建议清理或标注兼容保留。
  • MobCategoryMixinMobMixin 双路径 — 两者都改 getDespawnDistance(前者靠 ThreadLocal、后者靠实体实际位置)。前者仅在 spawnForChunk 窗口内有效且依赖已失效的 ThreadLocal,建议统一走 MobMixin 风格或明确分工。
  • NaturalSpawnerMixin RETURN 注入不处理异常路径spawnForChunk 抛异常时 CURRENT_SPAWNING_CHUNK 会泄漏到后续调用,建议 try/finally 或确认 spawnForChunk 自身兜底。
  • LoadChunkDatalevel/tier 字段实际只用于展示与 hash — 区块集完全由 offsetMappings 决定,tier 只参与 hashTierMappings。建议加注释说明,避免后续维护者误以为 tier 参与加载半径计算。

🟢 看起来不错

  • 引用计数强加载LevelLoadManager.forceChunk)正确覆盖多监督者共享区块的叠加/释放,count<=1 边界处理安全。
  • 删除完整性 — 在 PR 树全量 grep 确认 LoadChuckData/RandomChuckTickLoadManager 无残留引用,WormholeStabilizerHandler、事件监听均已迁移到新 API。
  • 生命周期LevelEventListener.onLevelUnloadremoveAll(清 LOAD_DATA_MAP+CHUNK_REF_COUNT),notifyServerStarted 冲刷延迟任务,reload 中 discard→apply→removeIf 顺序正确。
  • SourceFlags 与 PR 描述逐项吻合:皇家钢=DEFAULT(随机刻开)、浮霜=NO_RANDOM_TICK、下界合金/余烬=FIRE、多相=MULTIPHASE、超限=TRANSCENDIUM;tier-0 方块(铁/金/钻/绿宝)通过 blockTier >= 1 门控不产生映射、只提升显示等级,符合"提级不加载"。
  • en_ud 镜像正确("9x9"→"6x6" 是标准翻转),/overseer 命令与 CommandLang 键值、en_us/en_ud 同步一致。
  • 新 mixin 全部登记进 anvilcraft.mixins.jsonpermissions() API 用法与 base 分支现有命令一致。

📋 声称验证表

声称 状态 证据
resolved #1582(监督者加强建议) 1底座=1区块、4级上限、更多底座、分级效果、/overseer 命令均在 diff 中实现
一个底座方块对应一个区块 BlockOffsetMapping(dx,dz) 直接作为区块偏移进入 createLoadChunkData
最高 4 级 TIER_RADIUS = {1,2,3,4} + MAX_LEVEL = 4
更多方块可作为底座 overseer_base_tier_0..3 四个新 tag
铁/金/绿宝/钻石提级不加载 tier-0 块 blockTier>=1 门控被排除出 mappings
皇家钢=强加载+随机刻 DEFAULT flags(0),随机刻不跳过
浮霜=强加载不随机刻 FROST = NO_RANDOM_TICK
下界合金/余烬=+随机刻+火焰蔓延 FIRE = ALLOW_FIRE_SPREAD
多相=不随机刻+火焰蔓延 MULTIPHASE = NO_RANDOM_TICK|ALLOW_FIRE_SPREAD
超限=自然刷新+刷怪笼刷新 ⚠️ 实现齐全但整条自然刷新链路因 CURRENT_SPAWNING_DIMENSION 从未赋值而失效(见 🔴1)
/overseer 显示等级、加载区块数、总数 OverseerCommand + getOverseerChunkCount + getAllOverseerForcedChunkCount

结论: REQUEST_CHANGES — 架构重构方向清晰、删除与生命周期处理干净,但超限合金块核心卖点"生物自然刷新"当前完全不可用(ThreadLocal 未赋值导致 spawn 候选链路全断),且修复不能只靠补一个 set()(getSpawnCandidateChunks 的调用时机在 spawnForChunk 之前),需要调整维度上下文的传递方式后再合入。

🧪 测试建议

被测目标 推荐测试场景 优先级
超限合金块自然刷新链路 玩家远离 128+ 格(2048 区块内)时超限金字塔区块仍生成生物;修复 ThreadLocal 后验证 getSpawnCandidateChunks 包含目标区块 🔴
ServerLevelRandomTickMixin 浮霜/多相/超限区块随机刻停用且方块实体 tick 不受影响;皇家钢区块随机刻正常 🟡
引用计数 forceChunk 两个监督者共享区块,先后拆除,确认最后一个释放时区块才真正卸载 🟡
监督者结构失效/恢复 拆装 MID/TOP 监督者方块后,金字塔配置不变时加载是否恢复(当前会失败) 🔴
虫洞稳定器 3x3 加载区随机刻行为变更确认(现为开启) 🟡

由 Hermes Agent 审查

@Gugle2308

Copy link
Copy Markdown
Collaborator

💾 Self-improvement review: Patched references/chunk-loading-review-patterns.md in skill 'minecraft-mod-pr-review' (1 replacement). · Patched SKILL.md in skill 'minecraft-mod-pr-review' (1 replacement).

@Gugle2308

Copy link
Copy Markdown
Collaborator

两个关键问题均已确认。审查完成,输出审查意见。

代码审查摘要 — PR #4354(synchronize: Powerful overseer)

操作: synchronize
范围: 35 个文件(25 Java,19 新增,2 删除)/ ~1950 行 diff
主题: 监督者(Overseer)区块加载系统重构 — 底座方块按层(tier)划分、等级上限提升至 4、按底座材质区分加载特性(随机刻/火焰蔓延/生物刷新)、新增 /overseer 命令

已通过 refs/pull/4354/head 拉取 PR 分支交叉验证(残留引用、ThreadLocal 赋值点、标签读取方)。

🔴 关键问题

  1. CURRENT_SPAWNING_DIMENSION ThreadLocal 从未被赋值 → 3 个 mixin 注入是死代码(超限合金"自然刷新"功能不完整)
    ChunkFeatureManager 声明了 CURRENT_SPAWNING_DIMENSION,但整个 PR 分支上只有 3 处读取DistanceManagerMixin ×2、MobCategoryMixin ×1),没有任何 set 调用NaturalSpawnerMixin 只 set/remove CURRENT_SPAWNING_CHUNK)。读取时值为 nullCHUNK_SOURCES.get(null) 恒为 null → 以下注入永远不生效:

    • DistanceManagerMixin.hasPlayersNearby(FALSE→DEFAULT 覆盖)→ 玩家远离时"无玩家在附近"判定无法被改写,超限合金区块的自然刷新可能被 vanilla 的玩家距离门控跳过;
    • DistanceManagerMixin.getSpawnCandidateChunks(扩展候选区块)→ 超限合金区块不进 SpawnState 统计 → 该区块内已存在的生物不计入全局/分类 mob cap,可能超量刷怪
    • MobCategoryMixin.getDespawnDistance → SpawnState 统计半径扩展失效。

    目前只有 ChunkMapMixin.playerIsCloseEnoughForSpawningMobMixin.checkDespawn(自行从实体位置取 chunk)真正生效。修复:在 NaturalSpawnerMixin.spawnForChunk 的 HEAD 注入里一并 CURRENT_SPAWNING_DIMENSION.set(level.dimension())(与 CURRENT_SPAWNING_CHUNK 成对 set/remove)。

  2. OverseerBlockEntity.tick 失败路径不重置状态 → 结构修复后永不重新注册区块加载
    checkOverseerBlocks() 为 false 时只 unregisterreturn不清空 oldLevel/oldTierHash。复现场景:监督者正常工作(oldLevel=2,已注册)→ 敲掉中间一格(MID)→ tick 注销加载、但 oldLevel 仍为 2 → 补回 MID → scanPyramidBase 结果与缓存完全一致 → !levelChanged && !tiersChanged → 提前 return → 区块加载永远不会恢复,直到底座结构再变一次。修复:失败路径上 this.oldLevel = -1; this.oldTierHash = 0;(或注销后统一重置)。

⚠️ 警告

  1. WormholeStabilizerHandler 行为静默改变:随机刻从关闭变为开启
    createLoadChuckData(1, pos, false, ...)isNeedRandomTick=false)→ 新 createSimpleLoadChunkData(1, pos, serverLevel)(flags=0 → 默认运算随机刻)。虫洞稳定器的 3×3 加载区现在会跑随机刻(作物生长、方块随机行为),影响无关功能且带来额外性能开销。若为有意统一,请在 PR 描述中说明。

  2. en_us.json tooltip 混入全角逗号
    "(max 4 layers, 9x9 range), different base blocks provide different effects" — 英文文本中出现 CJK 全角 (且已原样镜像进 en_ud.json)。应改为半角 , 后重新 runData。

  3. 多相物质块的"启用火焰蔓延"实际不生效
    火焰扩散由火焰方块的随机刻驱动,而 MULTIPHASE = NO_RANDOM_TICK | ALLOW_FIRE_SPREAD 且随机刻跳过策略是"任一源跳过即跳过"(ChunkFeatureManager.shouldSkipRandomTick any-wins)→ 该区块根本不执行随机刻 → canSpreadFireAround 永远不会被调用到。下界合金/余烬(无 NO_RANDOM_TICK)的火焰蔓延是有效的,但多相物质的组合自相矛盾。

  4. OverseerUtil.placedOverseers 静态泄漏
    (a) 监督者被破坏(方块被替换)时,onUnloadOverseershouldTrack 检查 getBlockState() 已不是 OverseerBlock → 记录不删除,幽灵条目永久残留(/overseer list 持续报 "Invalid overseer");(b) 静态 Map 在服务器停止/世界切换时从不 clear(ChunkFeatureManager.clear() 也无调用者),单人模式切换世界后旧世界的条目会污染新世界同名维度。建议:unload 时以 hasLevel/自身 BE 状态判断而非方块状态,并在 ServerStopping 时清理。

  5. 策略叠加:同一区块被多个监督者覆盖时特性互相矛盾
    "跳过随机刻"是 any-wins(frost/多相/超限任一覆盖即整区块跳过随机刻),会压制同区块皇家钢/下界合金的"运算随机刻";火焰蔓延与自然刷新则是 allow-wins。三个特性采用不同的聚合语义,且与"皇家钢=原版默认加载"的宣称在重叠场景下冲突。建议至少写入文档或在 LoadChunkData 注释中明确聚合规则。

💡 建议

  1. "一个底座方块对应一个区块"的映射语义与描述不符scanPyramidBase 把方块的方块偏移 (dx,dz) 直接当区块偏移用(centerChunk.x() + m.chunkOffsetX()),即底座方块在 (dx,dz) 偏移处 → 加载中心区块偏移 (dx,dz) 的区块,而非该方块实际所在的区块。完整金字塔下包含底座方块的区块都在映射范围内(±1 ≤ ±level),功能无缺口,但在区块边界处(监督者位于区块边缘)加载区域会与底座实际位置错位,且同样金字塔在区块内不同位置会产生不同加载集。若意图是"每个底座方块加载它所在区块",应改用 ChunkPos.containing(tierCenter.offset(dx, 0, dz));若是"层级投影"设计,建议在代码注释中说明。
  2. oververse_base tag 已成为死代码:全库已无任何读取方(BE 只读 tier tags),但 ModBlocks 仍在给皇家钢/浮霜/余烬等打该 tag,生成的 overseer_base.json 也残留,建议清理。
  3. scanPyramidBase 每 tick 全量扫描(4 级时 3×3+5×5+7×7+9×9 ≈ 164 次 getBlockState + tag 匹配),即使无变化也执行。建议缓存并在 NeighborChanged/底座变化时失效。
  4. LOAD_DATA_MAP 仍以 BlockPos 为键:不同维度同坐标的两个监督者会互相挤掉注册(第二个 register 被 containsKey 静默忽略)。既然本次已引入维度键(CHUNK_REF_COUNTChunkFeatureManager),建议数据表也按维度分键。
  5. 等级与加载量跳变:纯铁/金/钻石/绿宝石底座(tier-0)时 4 级监督者只加载自身 1 个区块;等级 1→2 时加载量从 1 跳到 25 区块。功能与"铁块只提等级不加载"一致,但建议在 tooltip 中说明加载量与底座材质相关。
  6. 新 mixin 全部面向 vanilla 内部方法(BaseSpawner.isNearPlayerDistanceManager.hasPlayersNearby/getSpawnCandidateChunksChunkMap.playerIsCloseEnoughForSpawningServerLevel.tickChunk 等),签名不符会在启动时崩溃而非编译期暴露,建议合并前跑一次服务端启动冒烟测试。
  7. /overseer list 必须显式传维度参数,建议缺省时用发送者所在维度。

🟢 看起来不错

  • 引用计数强加载CHUNK_REF_COUNT + forceChunk)修复了旧实现"两个加载源共享区块、移除一个即卸载"的隐患;apply/discardapplied 标志防重入,reload 先 discard 后 apply 顺序正确,跨源计数平衡。
  • 类型迁移干净:LoadChuckDataLoadChunkDataRandomChuckTickLoadManager 删除后全分支零残留引用ServerLifecycleEventListener 中旧 tick 调用同步移除。
  • Tier/系列 tag 体系清晰(royal/frost/ember 系列 tag + 4 级 base tier tag),getBlockSourceFlags 与 PR 特性表一一对应(皇家钢=默认、浮霜=禁随机刻、下界合金/余烬=火焰、多相=禁随机刻+火焰、超限=自然刷新+刷怪笼)。
  • ServerLevelRandomTickMixin 的取消+重入(tickChunk(chunk, 0))带 isReentering 守卫,正确保留方块刻/流体刻/实体刻而只跳过随机刻。
  • /overseer list 输出等级、单监督者加载区块数、维度去重总数,与 PR 宣称一致;命令与 tooltip 文案 en_us/en_ud 均已重新生成。
  • 无硬编码密钥、无 TODO/FIXME 残留。

📋 声称验证表

声称 状态 对应实现
一个底座方块对应一个区块 ✅(近似) offsetMappings → centerChunk + (dx,dz),中心区块恒加载
监督者最高 4 级 MAX_LEVEL=4TIER_RADIUS={1,2,3,4}
更多方块可作为底座 4 个 tier tag 覆盖铁/金/钻/绿宝石/皇家钢/浮霜/下界合金/余烬/多相/超限
铁/金/绿宝石/钻石提升等级但不加载 blockTier >= 1 才生成 mapping,tier-0 仅作结构
皇家钢=强加载+随机刻 DEFAULT flags
浮霜=强加载、无随机刻 FROST = NO_RANDOM_TICK
下界合金+余烬=强加载+随机刻+火焰蔓延 FIRE = ALLOW_FIRE_SPREAD(随机刻为默认开启)
多相物质=强加载、无随机刻、火焰蔓延 ⚠️ MULTIPHASE 标志齐全,但无随机刻则火焰不会扩散,火焰蔓延实际无效
超限合金=强加载+自然刷新+刷怪笼刷新 ⚠️ TRANSCENDIUM 标志齐全,但 CURRENT_SPAWNING_DIMENSION 未赋值 → 3 处 mixin 死代码,功能不完整(见 🔴#1
/overseer 显示等级/加载数/总数 OverseerCommand + getOverseerChunkCount + getAllOverseerForcedChunkCount

结论: REQUEST_CHANGES — 架构重构方向正确、迁移干净,但存在两个功能性问题需修复:① 自然刷新特性因未赋值的 ThreadLocal 而半失效(3 处 mixin 死代码);② 监督者结构破坏后按原样修复时区块加载不会重新注册。

🧪 测试建议

被测目标 推荐测试场景 优先级
OverseerBlockEntity.tick 敲掉 MID 格 → 补回同结构 → 断言 chunk 重新强加载(复现 🔴#2);纯 tier-0 底座 4 级 → 仅 1 区块 🔴
LevelLoadManager.forceChunk 两个监督者共享同一区块 → 移除其一 → 区块仍加载;全部移除 → 卸载 🔴
ChunkFeatureManager 不同维度同坐标注册互不干扰;同区块多源 skip/allow 聚合语义 🟡
ServerLevelRandomTickMixin 浮霜区块:随机刻被跳过但方块刻/流体刻/实体刻仍执行 🟡
WormholeStabilizerHandler 虫洞加载区随机刻行为变化确认(有意 or 回归) 🟡
LoadChunkData.createLoadChunkData 混合材质底座的 flag 并集、中心区块恒加载、偏移映射边界(监督者位于区块边缘) 🟡

由 Hermes Agent 审查

@Gugle2308

Copy link
Copy Markdown
Collaborator

💾 Self-improvement review: Patched references/chunk-loading-review-patterns.md in skill 'minecraft-mod-pr-review' (1 replacement). · Patched SKILL.md in skill 'minecraft-mod-pr-review' (1 replacement).

@Gugle2308

Copy link
Copy Markdown
Collaborator

All diff sections analyzed and cross-referenced with the target branch. Here is the review:

代码审查摘要 — PR #4354 (synchronize)

操作: synchronize
范围: 35 个文件(25 Java, 19 新增, 2 删除)/ 1956 行 diff
分支: 26.1/1.6/overseer → dev/26.1/1.6

📋 声称验证表

声称 状态 对应实现
解决 #1582 重写监督者加载体系(LoadChuckData→LoadChunkData + ChunkFeatureManager)
一个底座方块对应一个区块 LoadChunkData.createLoadChunkData() 将每个 base block 的 (dx,dz) 偏移映射为区块偏移
监督者最高 4 级 MAX_LEVEL = 4TIER_RADIUS = {1,2,3,4}(金字塔底座:3×3→9×9)
更多方块可作为底座 overseer_base_tier_0~3 四个新 tag
铁/金/绿宝石/钻石块提升等级但不加载 tier_0 块 getBlockTier()==0,被排除在 offsetMappings 之外
皇家钢=默认加载(随机刻) ROYAL_SERIES→TIER_1→SourceFlags.DEFAULT
浮霜=强加载不随机刻 FROST_SERIES→FROST = NO_RANDOM_TICKServerLevelRandomTickMixin 取消随机刻
下界合金+余烬=随机刻+火焰蔓延 NETHERITE|EMBER_SERIESFIRE = ALLOW_FIRE_SPREAD(不跳过随机刻)
多相物质=不随机刻+火焰蔓延 MULTIPHASE = NO_RANDOM_TICK|ALLOW_FIRE_SPREAD
超限合金=生物自然刷新+刷怪笼刷新 ⚠️ TRANSCENDIUM = NO_RANDOM_TICK|ALLOW_NATURAL_SPAWN|ALLOW_SPAWNER_SPAWN(见警告 1)
/overseer 显示等级、区块数、总数 OverseerCommand + getOverseerChunkCount/getAllOverseerForcedChunkCount

⚠️ 警告

  1. OverseerBlockEntity / LoadChunkData — 超限合金块关闭随机刻(TRANSCENDIUMNO_RANDOM_TICK),但 PR 描述只写了"启用生物自然刷新和刷怪笼刷新",未提"不运算随机刻"(浮霜、多相物质都明确写了)。请确认是描述遗漏还是实现取舍。

  2. LevelLoadManager.LOAD_DATA_MAP 以 BlockPos 为唯一 key(不含维度)register() 对已存在 pos 直接 return:若两个维度在同一坐标各放一个监督者(或监督者与虫洞冲突),第二个会被静默忽略;更糟的是 unregister() 会把第一个维度的数据 markRemoved(),导致第一个监督者加载被错误拆除。旧代码同样按 pos 索引,但本 PR 新增了按维度查询的 /overseer list <dimension>getAllOverseerForcedChunkCount,跨维度场景已成正式功能。建议 key 改为 (ResourceKey<Level>, BlockPos)

  3. ChunkFeatureManager 跨维度串扰getAllNaturalSpawnChunks()(供 getSpawnCandidateChunks 注入)和 shouldAllowNaturalSpawnAnyDimension()(供 hasPlayersNearby)按 ChunkPos 跨所有维度匹配。净效应:维度 B 的超限合金区块会让维度 A 同坐标区块被加入 A 的生成候选/hasPlayersNearby 返回 DEFAULT。实际生成仍受 ChunkMapMixin(维度感知)拦截,危害有限,但会带来每 tick 的无效生成尝试开销,且 hasPlayersNearby 语义被维度无关地放宽。建议改为维度内查询。

  4. OverseerBlockEntity.tick — 结构破坏路径(!checkOverseerBlocks())unregister 后不重置 oldLevel/oldTierHash/overseer list 会对已失效的监督者显示过期等级(chunk 数为 0)。建议此处同时重置状态。

  5. NaturalSpawnerMixin — ThreadLocal 的 set/remove 未用 try/finally:spawnForChunk 抛异常时 CURRENT_SPAWNING_CHUNK 残留,MobCategoryMixin 可能用过期区块对无关 mob 返回 32768 的 despawn 距离。建议 try/finally。

  6. WormholeStabilizerHandlercreateSimpleLoadChunkData(1, pos, level) 默认 flags=0(运算随机刻)。旧调用 createLoadChuckData(1, pos, false, ...)isNeedRandomTick=false 在旧实现里实际无人消费(RandomChuckTickLoadManager 已无注册方),所以行为等价、非回归——但既然本 PR 让该 flag 重新生效,请确认虫洞加载区(天界锻造砧 3×3)现在运算随机刻是预期行为。

💡 建议

  • ServerLevelRandomTickMixinself.tickChunk(chunk, 0) 直接调用目标私有方法,请确认 MC 26.1 中 tickChunk(LevelChunk,int) 的可见性(若为 private,mixin 类无法编译,需改用 @Invoker)。另外该 mixin 对"玩家在场的 frost 区块"同样取消随机刻——玩家站在浮霜区块内也不运算随机刻,若希望玩家在场时恢复原版行为需加判断。
  • 性能OverseerBlockEntity.tick 每 tick 全量扫描金字塔(满级 164 次 getBlockState);DistanceManagerMixin 每次 spawn cycle 新建 LongOpenHashSet 并遍历全维度数据。可考虑降低扫描频率/增量检测。
  • forceChunk 引用计数 — 只跟踪本 mod 内部来源,不感知原版 /forceload 等外部强制加载:外部先强制、本 mod 解除时会连带解除。可接受,但建议注释说明。
  • 清理ModBlockTags.OVERSEER_BASE 及 ModBlocks 注册处对该 tag 的打标成为死代码(新逻辑只用 tier_0~3);ChunkFeatureManager.clear() 无调用方。
  • 文本en_us.json 的 overseer.shift tooltip 混入全角逗号 "…9x9 range), different…",应为半角。en_ud 与 en_us 同步更新 ✓("4"→"߈"、"9x9"→"6x6" 翻转一致)。

🟢 看起来不错

  • forceChunk 引用计数设计正确:多加载源共享区块时计数升降、reload 先 discard 后 apply 的顺序保证计数不出现负值/重复强制。
  • ServerLevelRandomTickMixin 的重入模式(cancel 后用 tickSpeed=0 重入,anvilcraft$isReentering 守卫)比直接 cancel 更安全,保留 tickChunk 内除随机刻外的逻辑。
  • per-chunk 标志聚合chunkSources 多 flag 列表 + any 语义)正确处理同一区块被不同底座方块/不同监督者覆盖的情况。
  • 8 个新 mixin 全部注册进 anvilcraft.mixins.json 主数组;新 tag 生成数据与 BlockTagLoader 完全一致;命令权限模式与现有 MultiphaseCommand 一致;Blocks.NETHERITE_BLOCK/ModBlocks.* 引用均存在。

结论: COMMENT — 结构清晰、功能映射完整,未发现阻塞性编译/逻辑错误;建议合并前处理警告 1(超限合金随机刻规格确认)和警告 2(多维度 BlockPos key),其余可后续跟进。

🧪 测试建议

被测目标 推荐测试场景 优先级
LoadChunkData.createLoadChunkData 多底座块同 chunk 标志聚合、中心块强制含 flags=0、tier 截断(tier N 不完整则 N+1 不参与) 🔴
LevelLoadManager.forceChunk 引用计数对称性:A/B 共享区块时 A 移除后 B 仍在、双双移除不重复 unforce 🔴
OverseerBlockEntity.tick 等级 2→1→0 迁移、破坏/重建底座、跨维度同坐标双监督者(当前会冲突) 🔴
ServerLevelRandomTickMixin 重入不递归、tickSpeed=0 不 cancel、frost 区块内玩家在场行为 🟡
ChunkFeatureManager 各 flag 同一区块被 FROST 与 ROYAL 监督者重叠时 any-语义(skip 优先) 🟡
/overseer list includeInactive 过滤、失效监督者 stale level、多维度计数 🟢

由 Hermes Agent 审查

@Gugle2308

Copy link
Copy Markdown
Collaborator

💾 Self-improvement review: Patched references/chunk-loading-review-patterns.md in skill 'minecraft-mod-pr-review' (1 replacement).

@Gugle2308

Copy link
Copy Markdown
Collaborator

⚠️ Dangerous command requires approval:

cd /tmp && curl -sL "https://api.github.com/repos/Anvil-Dev/AnvilCraft/pulls/4354" | python3 -c "import json,sys; d=json.load(sys.stdin); print(d['head']['sha']); print(d['head']['ref']); print(d['sta...

Reason: Security scan — [HIGH] Pipe to interpreter: curl | python3: Command pipes output from 'curl' directly to interpreter 'python3'. Downloaded content will be executed without inspection.
Safer: tirith run https://api.github.com/repos/Anvil-Dev/AnvilCraft/pulls/4354 — or: vet https://api.github.com/repos/Anvil-Dev/AnvilCraft/pulls/4354 (https://getvet.sh); script execution via -e/-c flag

Reply /approve to execute, /approve session to approve this pattern for the session, /approve always to approve permanently, or /deny to cancel.

@Gugle2308

Copy link
Copy Markdown
Collaborator

⚠️ Dangerous command requires approval:

cd /tmp && python3 -c "
import zipfile
z = zipfile.ZipFile('neoforge-src.jar')
names = z.namelist()
print(len(names))
mc = [n for n in names if n.startswith('net/minecraft/')]
print('minecraft files:'...

Reason: script execution via -e/-c flag

Reply /approve to execute, /approve session to approve this pattern for the session, /approve always to approve permanently, or /deny to cancel.

@Gugle2308

Copy link
Copy Markdown
Collaborator

⚠️ Dangerous command requires approval:

curl -sL "https://linkie.shedaniel.dev/api/1.21.1/class/net/minecraft/server/level/DistanceManager" 2>/dev/null | head -c 500; echo; echo "==="; curl -sL "https://linkie.shedaniel.dev/api/search?names...

Reason: Security scan — [MEDIUM] Lookalike TLD detected: Domain uses '.dev' TLD which can be confused with file extensions; [MEDIUM] Lookalike TLD detected: Domain uses '.dev' TLD which can be confused with file extensions

Reply /approve to execute, /approve session to approve this pattern for the session, /approve always to approve permanently, or /deny to cancel.

@Gugle2308

Copy link
Copy Markdown
Collaborator

I've completed a thorough analysis of the diff (35 files, 1956 lines), cross-referenced against the target branch (dev/26.1/1.6) via the local clone, and verified the tag/data files, mixins, and lifecycle wiring. Here is the review:


代码审查摘要 — PR #4354

操作: edited
范围: 35 个文件(19 新增,2 删除,14 修改)/ 1956 行 diff

🔴 关键问题

1. OverseerBlockEntity.scanPyramidBase + LoadChunkData.createLoadChunkData — 方块偏移被当作区块偏移,加载区域与特性作用位置错误

scanPyramidBase 生成的 BlockOffsetMapping(dx, dz, ...)dx/dz方块偏移(±1~±4),但 createLoadChunkData 直接把它当作区块偏移使用:

ChunkPos targetChunk = new ChunkPos(centerChunk.x() + m.chunkOffsetX(), centerChunk.z() + m.chunkOffsetZ());

后果:

  • 严重过载:底座 9x9 方块(4 级)最多只有 4 个区块的物理覆盖,但当前实现会强加载 9x9=81 个区块(旧实现最大 7x7=49);即使 1 级(3x3 皇家钢底座)也会加载 9 个区块。
  • 特性作用错位:偏移 (4,4) 处的浮霜块会禁用 4 个区块之外、不含任何底座方块的区块的随机刻,而真正包含该浮霜块的区块反而正常运算随机刻。"底座方块强加载对应区块/不运算随机刻" 等描述完全落空。
  • "功能冲突时优先"合并逻辑几乎成为死代码:除中心柱 (0,0) 外,不同方块永远映射到不同区块,chunkSources 的 flags 合并(PR 描述的核心优先级特性)只在 4 个中心柱方块间生效。

修复建议:对每个底座方块用 ChunkPos.containing(blockPos) 求实际所在区块,再与中心区块求相对偏移。

2. ChunkFeatureManager.CHUNK_SOURCES 无清理路径 — 世界卸载后内存泄漏 + 跨世界脏状态

LevelEventListener.onLevelUnload 已调用 LevelLoadManager.removeAll()(清 LOAD_DATA_MAP + CHUNK_REF_COUNT),但 ChunkFeatureManager.clear() 在本 PR 中从未被调用OverseerUtil.placedOverseers 也无任何清理。世界卸载后 CHUNK_SOURCES 仍持有 LoadChunkData → 死 ServerLevel 的强引用(阻止 GC);单机切换存档(复用同一 dimension key)时,残留条目会让新世界的随机刻跳过/火焰蔓延/生物刷新基于旧世界的监督者错误生效。建议在 LevelEventListener.onLevelUnloadServerLifecycleEventListener.onServerStopping 中补充 ChunkFeatureManager.clear()OverseerUtil 清理。

⚠️ 警告

3. ChunkMapMixinSectionPos.sectionToBlockCoord(pos.x(), 8) 双参调用需核实 26.1 API 语义

若该重载语义为 sectionCoord * sectionSize,则 chunkX * 8 并非区块中心(应为 chunkX * 16 + 8),"玩家 2048 区块内"的边界判定会偏一半;若 26.1 无此双参重载则直接编译失败。建议改为 (pos.x() << 4) + 8ChunkPos.getMiddleBlockX(pos) 之类明确写法。

4. 多相物质块"不运算随机刻 + 启用火焰蔓延"自相矛盾

ServerLevelRandomTickMixintickSpeed=0 重入 tickChunk,整段随机刻循环被跳过——火焰方块得不到随机刻,无法蔓延;ServerLevelFireSpreadMixin 只是把 canSpreadFireAround 强行改为 true,火焰方块根本不触发。实际效果:火焰只能从相邻"有随机刻"区块边缘蔓延进来,多相区块内部无法传播。请确认这是否符合预期,否则需只跳过非火焰方块的随机刻。

5. NaturalSpawnerMixin ThreadLocal 无 try/finally

CURRENT_SPAWNING_CHUNK/DIMENSIONspawnForChunk HEAD 设置、RETURN 清理,但中途抛异常时不会清理,同线程后续 MobCategoryMixin.getDespawnDistance 会读到过期值,给无关生物返回 32768 消失距离。另外 MobMixin(WrapOperation 按生物自身位置判断)与 MobCategoryMixin(ThreadLocal)在 checkDespawn 路径功能重复,建议二选一 + try/finally。

6. OverseerBlockEntity 结构修复后不会重新注册(既有 bug 延续)

checkOverseerBlocks() 失败分支 unregister 后未重置 oldLevel/oldTierHash。若玩家只拆掉中/上段监督者方块(BE 存活)再原样放回,下次 tick 时 level 与 tier hash 均未变 → 提前 return,监督者永远不再注册强加载,直到底座被改动。建议 unregister 分支重置 oldLevel = -1; oldTierHash = 0

7. OverseerCommand.java — 中文注释残留

import net.minecraft.commands.Commands;  // ← 新增:普通导入

需删除。

8. DistanceManagerMixin 跨维度污染

hasPlayersNearby 使用 shouldAllowNaturalSpawnAnyDimension(忽略维度),getSpawnCandidateChunks 把其他维度的自然刷新区块加入当前维度候选——下界监督者的区块坐标若与主世界某区块相同,主世界该区块会被误判"玩家附近"。实际影响有限(ChunkMapMixin 会按维度再校验),但应过滤维度。

💡 建议

  • OverseerBlockEntity.tick — 每次 tick 全量扫描最多约 330 次 getBlockState,即使无任何变化;建议每 N tick 扫描一次。
  • 死字段BlockOffsetMapping.tierLoadChunkData.level 声明后从未被读取。
  • 格式 — 19 个文件(含新 Java 文件与生成 JSON)缺末尾换行,建议跑一遍 spotless。

🟢 看起来不错

  • 旧类删除完整:LoadChuckData / RandomChuckTickLoadManager 全部引用已替换(base 分支 6 处引用文件全部覆盖),无残留编译错误。
  • 方块→特性映射与 PR 描述完全一致:皇家钢 DEFAULT(随机刻)/ 浮霜 FROST / 下界合金+余烬 FIRE / 多相 MULTIPHASE / 超限 TRANSCENDIUM,tier-0 铁/金/钻石/绿宝石不参与加载。
  • CHUNK_REF_COUNT 引用计数 + 卸载对称(unregister→discard、apply 幂等)实现正确。
  • 冲突优先级 OR 合并逻辑本身正确(任意来源启用即生效)。
  • en_us/en_ud 同步更新,占位符完整;新 key overseer.summary 已双向生成。
  • /overseer 命令实现完整(等级、单监督者区块数、总数、点击复制坐标、includeInactive 过滤)。

📋 声称验证表

声称 状态 说明
底座方块对应区块加载 ⚠️ 机制存在但偏移计算错误(🔴1)
本体区块默认加载+随机刻 centerChunk 恒定 flags=0
最高 4 级 TIER_RADIUS {1,2,3,4} + MAX_LEVEL=4
铁/金/钻石/绿宝石升级不加载 tier-0 不入 offsetMappings
皇家钢强加载+随机刻 DEFAULT flags
浮霜强加载不随机刻 ⚠️ 标志正确但作用区块错位(🔴1)
下界合金/余烬强加载+随机刻+火焰蔓延 FIRE flags
多相强加载不随机刻+火焰蔓延 ⚠️ 无随机刻区块火焰无法传播(⚠️4)
超限强加载不随机刻不火焰蔓延+双生物刷新 TRANSCENDIUM flags + 2048 区块限制(ChunkMapMixin)
冲突优先级:不随机刻>火焰>刷新 ⚠️ 逻辑正确但几乎不会触发(🔴1c)
/overseer 显示等级/区块数/总数 实现完整

结论: REQUEST_CHANGES — 区块偏移计算(🔴1)与 CHUNK_SOURCES 泄漏(🔴2)需修复后合并;其余为建议项。

🧪 测试建议

被测目标 推荐测试场景 优先级
LoadChunkData.createLoadChunkData 偏移映射:断言目标区块 == ChunkPos.containing(blockPos) 相对中心偏移;多源 flags 合并 🔴
OverseerBlockEntity.tick 结构拆毁→原样修复后能重新注册;等级 0~4 边界;底座混合 tier 方块 🔴
LevelLoadManager.forceChunk 两监督者共享区块的引用计数增减;unload→reload 后计数归零 🟡
ServerLevelRandomTickMixin 重入守卫(tickSpeed=0 不取消、无死循环);异常路径 finally 🟡
世界卸载 CHUNK_SOURCES/placedOverseers 清空断言 🔴

由 Hermes Agent 审查

@Gugle2308

Copy link
Copy Markdown
Collaborator

💾 Self-improvement review: Patched references/chunk-loading-review-patterns.md in skill 'minecraft-mod-pr-review' (1 replacement).

@Gugle2308

Copy link
Copy Markdown
Collaborator

⚠️ Dangerous command requires approval:

cd /tmp && grep -oE '"downloads": \{' 261.json; python3 --version 2>/dev/null; node -e "
const fs=require('fs');
const j=JSON.parse(fs.readFileSync('/tmp/261.json','utf8'));
console.log('keys:', Objec...

Reason: script execution via -e/-c flag

Reply /approve to execute, /approve session to approve this pattern for the session, /approve always to approve permanently, or /deny to cancel.

@Gugle2308

Copy link
Copy Markdown
Collaborator

⚠️ Dangerous command requires approval:

node -e "
const fs=require('fs');
const j=JSON.parse(fs.readFileSync('/tmp/261.json','utf8'));
console.log('keys:', Object.keys(j).join(','));
console.log('downloads keys:', Object.keys(j.downloads||{...

Reason: script execution via -e/-c flag

Reply /approve to execute, /approve session to approve this pattern for the session, /approve always to approve permanently, or /deny to cancel.

@Gugle2308

Copy link
Copy Markdown
Collaborator

⚠️ Dangerous command requires approval:

cd /opt/data/workspace && node ziplist.js userdev.jar "net/minecraft" | head -30; echo "=== mappings/tsrg/srg ==="; node ziplist.js userdev.jar "" | grep -iE "mapping|tsrg|srg|proguard|joined" | head;...

Reason: script execution via -e/-c flag

Reply /approve to execute, /approve session to approve this pattern for the session, /approve always to approve permanently, or /deny to cancel.

@Gugle2308

Copy link
Copy Markdown
Collaborator

⚠️ Dangerous command requires approval:

cd /tmp && python3 -c "
import zipfile
z = zipfile.ZipFile('nf-sources.jar')
names = z.namelist()
print('total entries:', len(names))
java = [n for n in names if n.endswith('.java')]
print('java files...

Reason: script execution via -e/-c flag

Reply /approve to execute, /approve session to approve this pattern for the session, /approve always to approve permanently, or /deny to cancel.

@Gugle2308

Copy link
Copy Markdown
Collaborator

⚠️ Iteration budget exhausted (90/90) — asking model to summarise

@Gugle2308

Copy link
Copy Markdown
Collaborator

I reached the maximum iterations (90) but couldn't summarize. Error:

<title>504 Gateway Time-out</title>

504 Gateway Time-out


openresty

⚠️ File-mutation verifier: 1 file(s) were NOT modified this turn despite any wording above that may suggest otherwise. Run git status or read_file to confirm.
/tmp/ziplist.js — [write_file] Write denied: '/tmp/ziplist.js' is a protected system/credential file.

@Gugle2308

Copy link
Copy Markdown
Collaborator

⚠️ Dangerous command requires approval:

cd /opt/data/workspace/mc2612-extract/net/minecraft && echo "=== Mob.class 引用 getDespawnDistance? ===" && grep -ac "getDespawnDistance" world/entity/Mob.class && echo "=== Mob.class 引用 MobCategory? ==...

Reason: Security scan — [CRITICAL] Mass file deletion in a short window: 11 non-build files were deleted within 20s. A burst of deletions can be destructive (ransomware-like or an accidental recursive wipe).; recursive delete

Reply /approve to execute, /approve session to approve this pattern for the session, /approve always to approve permanently, or /deny to cancel.

@Gugle2308

Copy link
Copy Markdown
Collaborator

💾 Self-improvement review: Patched SKILL.md in skill 'minecraft-mod-pr-review' (1 replacement).

@Gugle2308

Copy link
Copy Markdown
Collaborator

All verification complete. I have everything needed — here's the full review:


代码审查摘要 — PR #4354

操作: edited(PR 描述更新,按流程重新验证全部声称)
范围: 35 个文件(19 新增 / 2 删除 / 14 修改,~1954 行 diff),26 个 Java + 8 个 tag JSON + lang + mixins.json
分支: 26.1/1.6/overseerdev/26.1/1.6(MC 26.1 / NeoForge 26.1)

✅ 验证说明(本次审查的交叉验证手段)

  • 所有 8 个新 mixin 的目标方法已逐一对 MC 26.1.2 官方映射 client.jar 验证存在且签名匹配:BaseSpawner.isNearPlayer(Level,BlockPos)ZChunkMap.playerIsCloseEnoughForSpawning(ServerPlayer,ChunkPos)ZDistanceManager.hasPlayersNearby(J)TriStateDistanceManager.getSpawnCandidateChunks()LongIteratorServerLevel.tickChunk(LevelChunk,I)VServerLevel.canSpreadFireAround(BlockPos)ZMobCategory.getDespawnDistance()INaturalSpawner.spawnForChunk(ServerLevel,LevelChunk,SpawnState,List)VMob.checkDespawn()V 全部存在;Mob.checkDespawn 确会 INVOKE MobCategory.getDespawnDistance()(WrapOperation 目标成立)。
  • 本地克隆已 git fetch 同步 dev/26.1/1.6 目标分支用于跨引用(ModBlocks 目标方块、tag 定义、wormhole 上下文、multiblock 行为)。

🔴 关键

未发现阻断性问题。最危险的环节(8 个针对 vanilla 的 mixin 注入点)全部验证通过。

⚠️ 警告

  1. WormholeStabilizerHandler.java:241 — 虫洞区块加载行为变化(疑似无意)
    旧:LoadChuckData.createLoadChuckData(1, pos, false, level)isNeedRandomTick=false
    新:LoadChunkData.createSimpleLoadChunkData(1, pos, level)sourceFlags=0 = 默认运算随机刻
    天体锻造砧周围 3×3 区块从"不运算随机刻"变为"运算随机刻"。PR 描述未提及此变更,若需保持原语义应传 SourceFlags.NO_RANDOM_TICK(或 FROST)。

  2. DistanceManagerMixin.java:29-31 — hasPlayersNearby 跨维度污染
    shouldAllowNaturalSpawnAnyDimension(chunkPos) 会让任意维度中同坐标 (x,z) 的区块都从 TriState.FALSE 变为 DEFAULT。DistanceManager 是每维度实例,mixin 内取不到维度才用了 AnyDimension 兜底。实际影响有限(ChunkMapMixin 仍按维度把关 spawn),但语义上不严谨,且会让无关区块进入 spawn 候选枚举。

  3. OverseerBlockEntity.java tick() — 结构短暂破坏后不重新注册(旧代码同样存在,但本 PR 重写该类,建议顺手修复)
    SimpleMultiPartBlock 无级联破坏(OverseerBlock.onRemove 为空):只敲掉 MID/TOP 再放回时 BOTTOM BE 存活。破坏期间 checkOverseerBlocks() 失败 → unregister 后 return未重置 oldLevel/oldTierHash;放回后 newLevel==oldLevel && hash 相同 → 提前 return → 永远不重新注册,监督者外观显示等级但区块加载静默失效,直到敲掉底部块。修复:失败分支加 this.oldLevel = -1; this.oldTierHash = 0;

  4. LevelLoadManager.forceChunk — 与 vanilla /forceload 互操作
    vanilla setChunkForced 是 Set 语义(非引用计数)。本 mod 计数归零时无条件 setChunkForced(false),若该区块同时被 /forceload 或其他 mod 强加载,会连带解除。mod 内部引用计数正确,仅外部叠加时受影响(边缘场景)。

  5. 社区语言文件未更新
    zh_cn/de_de 等的 command.anvilcraft.overseer.entry 仍为旧格式 "random tick: %3$s"(现在 %3$s 传入的是区块数,显示为误导性数字),tooltip 仍写 "3x3 皇家钢 / 3层5x5"(实际已改为 4 层 9×9、多种底座),且缺 overseer.summary key(回退英文)。en_us/en_ud 已正确生成。

  6. ChunkFeatureManager.clear() 是死代码
    从未被调用。CHUNK_SOURCES 清理完全依赖 discard 路径(正常流程会清干净),但任何 lazy 任务异常都会遗留持有 ServerLevel 引用的陈旧条目。建议在 LevelLoadManager.removeAll()onServerStopped 中调用。

💡 建议

  • 四个 spawn/despawn mixin 的协作关系建议注释化MobCategoryMixin(ThreadLocal,依赖 NaturalSpawnerMixin 的 HEAD/RETURN 对称性)+ MobMixin(WrapOperation)+ ChunkMapMixin(2048 区块距离门)+ DistanceManagerMixin(候选枚举)共同实现"超限合金区块自然刷新/不消失",机制交错且隐式耦合,加注释可防止后续误删。
  • OverseerCommand 的 entry 计数 getOverseerChunkCount 含中心区块(Lv.0 无底座时显示 loads: 1),与 summary 的 distinct 口径不同,确认是否符合预期。
  • ServerLevelRandomTickMixin 重入 tickChunk(chunk, 0):确认 26.1 中 speed=0 时仅跳过随机方块刻、BE/实体刻照常,建议运行时冒烟验证。
  • MobCategoryMixin 中 ThreadLocal 在 spawnForChunk 异常时不会清理(服务器线程 fatal 场景,影响有限)。

🟢 看起来不错

  • 架构清晰:LoadChunkData(数据/特征集)+ ChunkFeatureManager(全局查询)+ LevelLoadManager(force + 引用计数)三层分离,旧的 LoadChuckData/RandomChuckTickLoadManager 合并删除干净,LoadChuckData→LoadChunkData 重命名彻底(无残留引用)。
  • reload() 改为先 discard 后 apply,配合引用计数是正确顺序(旧代码顺序相反,会先增后减)。
  • 方块偏移→区块偏移映射与 PR 描述一致;blockTier>=1 门控使铁/金/钻/绿宝石只升等级不产生加载映射 ✅;层级半径 {1,2,3,4} 与"最高 4 级 / 9×9"一致;等级面积数学正确(与旧 3×3/5×5/7×7 行为在皇家钢底座下完全兼容)。
  • 底座 tag 分层(tier_0..3 + 系列 tag)与生成 JSON 完全一致;OVERSEER_BASE 全部成员(皇家钢+浮霜系列)均被新 tier_1 覆盖,无底座兼容性回退
  • SourceFlags 优先级(不运算随机刻 > 火焰蔓延 > 生物刷新)在 LoadChunkDataChunkFeatureManager 中 any-wins 语义一致,与 PR 声明吻合。
  • /overseer 命令实现完整(等级、单机区块数、维度总数、includeInactive 过滤、坐标复制、Optional 安全),Source.OVERSEER 过滤使虫洞加载不污染统计。
  • OverseerUtil ConcurrentHashMap + isMainPart 门控,onLoad/onUnload 对称;ServerBlockEntityEventListener 集成无重复注册。
  • 中心区块恒注册(flag 0)+ 底座 (0,0) 映射叠加的语义与"本体区块默认加载"及优先级规则自洽。

📋 声称验证表

声称 状态 对应实现
一个底座方块对应一个区块(方块偏移=区块偏移) scanPyramidBaseBlockOffsetMapping(dx,dz,...)createLoadChunkData 按 chunkOffset 映射
本体所在区块默认加载且运算随机刻 computeIfAbsent(centerChunk).add(0);注意中心底座为浮霜/余烬/多相/超限时中心区块继承其 flags(按优先级规则)
最高 4 级 TIER_RADIUS {1,2,3,4},最大 9×9=81 区块
更多方块可作底座 tier_0..3 tags(新增 16+ 种方块)
铁/金/绿宝/钻提升等级但不加载 blockTier >= 1 门控 + getBlockTier 返回 tag 索引
皇家钢:加载+运算随机刻 SourceFlags.DEFAULT(0)
浮霜:加载+不运算随机刻 FROST = NO_RANDOM_TICK
下界合金+余烬:加载+随机刻+火焰蔓延 FIRE = ALLOW_FIRE_SPREAD(不跳过随机刻)
多相物质:加载+不随机刻+火焰蔓延 MULTIPHASE
超限合金:加载+不随机刻+不火焰+自然刷新+刷怪笼刷新(玩家 2048 区块内) TRANSCENDIUM + BaseSpawner/ChunkMap/MobCategory/Mob/NaturalSpawner/DistanceManager 六个 mixin;TRANSCENDIUM_DESPAWN_DISTANCE=32768=2048×16 ✅
冲突时优先:不随机刻/火焰/刷新 any-wins 语义
/overseer 显示等级、加载区块数、总数 OverseerCommand + getOverseerChunkCount/getAllOverseerForcedChunkCount

🧪 测试建议

被测目标 推荐场景 优先级
OverseerBlockEntity.scanPyramidBase 混合 tier 底座、tier-0 全底座(应仅 1 区块)、破坏单层后恢复 🔴
LevelLoadManager.forceChunk 双监督者重叠区块的注册/注销计数对称性;与 /forceload 叠加 🔴
特征 mixin 组合 超限合金区块:无玩家时刷怪笼激活 + 远距离自然刷新 + 不消失;浮霜区块随机刻跳过;余烬区块火焰蔓延 🔴
ServerLevelRandomTickMixin 重入 tickChunk(chunk,0) 后 BE/实体刻正常、随机刻确实被跳过 🟡
生命周期 监督者区块卸载→重载后重新注册;服务器重启后无残留 🟡

结论: COMMENT — 架构与实现质量高,mixins 目标全部验证有效,无阻断性问题。建议合并前处理 ⚠️1(虫洞随机刻行为变化,若属无意)和 ⚠️3(陈旧状态重置);⚠️5 语言文件可随社区翻译流程跟进。


由 Hermes Agent 审查(mixin 目标已对照 MC 26.1.2 官方映射字节码验证)

⚠️ File-mutation verifier: 1 file(s) were NOT modified this turn despite any wording above that may suggest otherwise. Run git status or read_file to confirm.
/tmp/unzipmini.js — [write_file] Write denied: '/tmp/unzipmini.js' is a protected system/credential file.

@Gugle2308

Copy link
Copy Markdown
Collaborator

💾 Self-improvement review: Patched references/vanilla-api-signature-verification.md in skill 'minecraft-mod-pr-review' (1 replacement). · Patched references/chunk-loading-review-patterns.md in skill 'minecraft-mod-pr-review' (1 replacement). · Patched SKILL.md in skill 'minecraft-mod-pr-review' (1 replacement).

@alpha-hhh
alpha-hhh marked this pull request as ready for review August 7, 2026 16:02
@Gugle2308

Copy link
Copy Markdown
Collaborator

分析完成。所有核心文件已通读,交叉验证了 26.1 API 签名、tag 生成一致性、mixin 注册完整性和残留引用。现在输出审查意见。

代码审查摘要 — PR #4354

操作: ready_for_review
范围: 35 个文件(18 Java, 19 新增, 2 删除)/ 1954 行 diff
分支: 26.1/1.6/overseerdev/26.1/1.6(目标 #1582

🔴 关键问题

1. DistanceManagerMixin.getSpawnCandidateChunks 跨维度污染DistanceManager每个维度一个实例,但 mixin 把 ChunkFeatureManager.getAllNaturalSpawnChunks()(遍历所有维度CHUNK_SOURCES)的区块全部塞进当前维度的生成候选。后果:主世界有超限合金监督者时,下界/末地spawnEnemiesAndAnimals 会把主世界监督者对应的 ChunkPos 当作候选,调用 getChunk(x, z) 强制加载/生成下界对应坐标的区块,并在那里尝试刷怪。hasPlayersNearbyshouldAllowNaturalSpawnAnyDimension 同理(把下界同坐标 chunk 的 TriState.FALSE 改成 DEFAULT)。修复:getAllNaturalSpawnChunks 应接受维度参数过滤,或 mixin 内按当前维度取值。

2. OverseerBlockEntity.tickcheckOverseerBlocks() 失败分支未重置状态 — 两个 unregister 分支不对称:

// 分支 A(checkOverseerBlocks 失败):unregister 后不重置
if (!this.checkOverseerBlocks()) {
    if (LevelLoadManager.checkRegistered(pos)) {
        LevelLoadManager.unregister(pos, level);
    }
    return;   // ← oldLevel / oldTierHash 保留旧值
}
// 分支 B(等级/底座变化):正确重置
if (this.oldLevel > -1 || LevelLoadManager.checkRegistered(pos)) {
    LevelLoadManager.unregister(pos, level);
    this.oldLevel = -1;      // ✓
    this.oldTierHash = 0;    // ✓
}

场景:监督者 MID/TOP 部分被破坏(BOTTOM 的 BE 存活,ServerUnload 不触发)→ unregister 但 oldLevel 残留 → 玩家补回方块后 newLevel == oldLevel && newTierHash == oldTierHashif (!levelChanged && !tiersChanged) return;永不重新注册,强加载永久丢失,直到底座发生变化。修复:分支 A 的 unregister 后同样重置 oldLevel = -1; oldTierHash = 0;

3. 开发注释残留OverseerCommand.java 第 14 行:

import net.minecraft.commands.Commands;  // ← 新增:普通导入

明显是辅助开发时的标记注释,需删除。

⚠️ 警告

  • OverseerUtil.placedOverseers 静态 map 无清理入口ChunkFeatureManager.clear() 定义后从未被调用(grep 确认零调用点);ServerLifecycleEventListener.onServerStopped 清理了 PowerGrid/HeatCollectorManager/FluidNetworkManager 等,唯独没有清 OverseerUtilChunkFeatureManager。正常路径依赖 BE ServerUnload 事件兜底,但服务器停止/世界异常卸载时会残留幽灵数据(/overseer list 显示失效监督者)。建议在 onServerStopped 中显式调用 OverseerUtil 的 clear(当前该类甚至没有 clear 方法)和 ChunkFeatureManager.clear()
  • MobCategoryMixin 依赖 ThreadLocal 为 null 时的隐式安全CURRENT_SPAWNING_CHUNK.get() 在非 spawnForChunk 上下文(如 mob 正常 despawn 检查)为 null,此时 shouldAllowNaturalSpawn(null, null) 恰好因 HashMap.get(null) 返回 null 而不崩。行为正确但脆弱,建议加显式 null 检查。
  • scanPyramidBase 每 tick 全量扫描 — 每个监督者每 tick 最多执行 164 次 getBlockState(9×9+7×7+5×5+3×3),每个方块再叠加 4 次 tag 匹配(getBlockTier)+ 4 次 state.is()getBlockSourceFlags)。哈希检测只避免重新注册,扫描本身不省。监督者数量多时有 tick 开销,建议缓存或降低扫描频率(如每 5 tick 一次)。

💡 建议

  • LoadChunkData.createLoadChunkDatalevel 参数仅存入字段、未参与加载逻辑(chunkPosList 完全由 offsetMappings 决定)——可接受,但注意 getLevel() 目前无消费方。
  • LevelLoadManagerlazy 队列 FIFO 保证 register→unregister 顺序正确(serverStarted=false 时 apply 先入队、discard 后入队,最终状态一致)——设计良好,无需改动。
  • ServerLevelRandomTickMixinanvilcraft$isReentering 守卫 + tickChunk(chunk, 0) 重入方案正确(0 速度跳过随机刻但保留其余逻辑),无死循环风险。

🟢 看起来不错

  • 引用计数 CHUNK_REF_COUNT 正确处理多监督者共享区块(count>1 时 setChunkForced 不翻转),比旧实现可靠。
  • reload 顺序改为先 discard 后 apply,比旧代码(先 apply 后 discard)更合理。
  • 功能 flag 体系实现与 PR 描述完全一致NO_RANDOM_TICK/ALLOW_FIRE_SPREAD/ALLOW_NATURAL_SPAWN/ALLOW_SPAWNER_SPAWN 独立位 + 按 chunk 聚合 OR 语义,"不运算随机刻、启用火焰蔓延、启用生物刷新"冲突优先级正确落地;超限合金不含 FIRE 位、多相物质 = 不随机刻+火焰、下界合金/余烬 = 只火焰——全部符合描述。
  • "1 底座方块 ↔ 1 区块(方块偏移=区块偏移)" 映射实现正确,4 层金字塔 = 9×9 = 81 区块,与 tooltip "max 4 layers, 9x9 range" 一致。
  • tier-0 方块(铁/金/钻/绿宝石)提升等级但不产生 offsetMappings——"提升等级但不加载"语义正确。
  • wormhole 迁移干净createSimpleLoadChunkData(1, ...) 与旧 createLoadChuckData(1, false) 行为等价(radius 1、默认随机刻);LoadChuckData/RandomChuckTickLoadManager 删除后无残留引用。
  • tag/JSON/lang 生成一致性良好overseer_base_tier_0..3royal/frost/ember_series 的 BlockTagLoader 与生成的 json 完全对应;en_us/en_ud 对称;ItemTooltipManager 文本与 lang 一致;所有 8 个新 mixin 均已注册进 anvilcraft.mixins.jsonModBlocks 常量全部存在。

📋 声称验证表

声称 状态 对应实现
1 底座方块 ↔ 1 区块(偏移映射) LoadChunkData.createLoadChunkData / scanPyramidBase
本体所在区块默认加载+随机刻 chunkSources.computeIfAbsent(centerChunk).add(0)
最高 4 级 TIER_RADIUS {1,2,3,4} / MAX_LEVEL = 4
更多底座方块(4 级 tag) overseer_base_tier_0..3.json + ModBlockTags
铁/金/绿宝石/钻石提升等级不加载 getBlockTier() >= 1 才加入 mapping
皇家钢:强加载+随机刻 SourceFlags.DEFAULT
浮霜:强加载+不随机刻 FROST = NO_RANDOM_TICK
下界合金/余烬:+随机刻+火焰蔓延 FIRE = ALLOW_FIRE_SPREAD
多相物质:不随机刻+火焰蔓延 MULTIPHASE
超限合金:不随机刻+不火焰+自然/刷怪笼刷新 TRANSCENDIUM
冲突优先级(不随机刻>火焰>刷新) 按 chunk 聚合 OR
/overseer 显示等级/加载区块数/总数 OverseerCommand + LevelLoadManager 统计方法

🧪 测试建议

被测目标 推荐测试场景 优先级
DistanceManagerMixin#onGetSpawnCandidateChunks 主世界监督者 + 下界同坐标:候选列表不应含主世界 chunk 🔴
OverseerBlockEntity#tick 破坏 MID/TOP 后补回:应重新注册强加载 🔴
LevelLoadManager#forceChunk 两监督者共享区块:一个移除后区块仍加载 🟡
ServerLevelRandomTickMixin 浮霜底座区块:方块随机刻跳过但 BE tick 正常 🟡
BaseSpawnerMixin 超限合金区块内刷怪笼无玩家激活 🟢
OverseerCommand 多维度/跨世界 /overseer list 统计正确性 🟢

结论: REQUEST_CHANGES — 跨维度生成候选污染(#1)和 BE 状态未重置导致强加载永久丢失(#2)需修复;#3 注释残留顺手清理。其余功能实现与 PR 描述高度一致,质量良好。


由 Hermes Agent 审查

@Gugle2308

Copy link
Copy Markdown
Collaborator

💾 Self-improvement review: Patched references/chunk-loading-review-patterns.md in skill 'minecraft-mod-pr-review' (1 replacement). · Patched SKILL.md in skill 'minecraft-mod-pr-review' (1 replacement).

@WhereisFff
WhereisFff merged commit 38e60d5 into Anvil-Dev:dev/26.1/1.6 Aug 9, 2026
2 checks passed
@Gugle2308

Copy link
Copy Markdown
Collaborator

PR #4354 状态为 closed,按 webhook 规则(closed/labeled → 停止),不下载 diff、不执行审查、不发布评论。本次跳过。

Gu-ZT pushed a commit that referenced this pull request Aug 10, 2026
* Powerful overseer. (#4354)

* tag, lang and tooltip

* overseer

* dimension

* style

* style

* style

* style

* style

* style, spawning

* style

* Reimplement negative shape cullface 重新实现负形剔除 (#4333)

* feat(cullface): reimplement negative shape cullface

* cherrypick(assets): cp neutron irradiator assets

* feat(confined): modify other confinement chamber, and remove the cullface of negative matter block

* fix(confined): fix confined neutronium ingot dont have "light_emission": 15

* fix(merge): remove side effects when merge confict

---------

Co-authored-by: XeKr <45423407+xekr@users.noreply.github.com>

* Fix code style and warnings 修复代码样式和警告 (#4321)

* chore(style): fix code style and warnings

* fix: fix *valid* bug

* chore(style): fix checkstyle

* fix(merge): remove side effects when merge confict

* feat(cfa): 重构天体巨构注册与锻星砧交互

- 新增可注册的巨构定义体系,统一管理巨构条件、环位、模型、材料、旋转逻辑与处理器,并注册内置巨构
- 将锻星砧巨构状态改为基于资源标识符持久化,兼容旧版名称和索引数据,统一处理建造、拆除、辅助巨构及激光需求
- 重构天体重构选项解析和客户端渲染,支持巨构模型动态替换、恒星同步旋转、玩家头颅天体渲染、恒星 Bloom 与扩展渲染包围盒
- 破坏锻星砧时保留方块实体内的库存、材料和控制器数据,避免已投入物品丢失
- 将物流接口提示信息改为基于版本号的 RPC 服务端快照同步,异步刷新寺庙需求、对撞机状态和接口库存
- 扩展行星资源配方的构建器、加权条目和嵌套随机选择,更新资源数据生成逻辑及供奉、荒地配方
- 修复光谱弹弓和光谱武器发射器模型,使基础物品模型与特殊渲染层正确组合
- 修正加速环默认方块状态及相关巨构处理器的状态判断
- 踢糠特供 shift 无视引力

---------

Co-authored-by: alpha-hhh <91364286+alpha-hhh@users.noreply.github.com>
Co-authored-by: 秋水AuU_ <150409561+QiuShui1012@users.noreply.github.com>
Co-authored-by: XeKr <45423407+xekr@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants