Skip to content

Fix blueprint integrity & build behavior, improve structure scanner interaction 修复蓝图完整性与建造行为并完善结构扫描器交互 - #4962

Merged
PigeonNian merged 1 commit into
Anvil-Dev:dev/1.21/1.6from
WhereisFff:dev/1.21/fix5
Sep 20, 2026
Merged

PigeonNian merged 1 commit into
Anvil-Dev:dev/1.21/1.6from
WhereisFff:dev/1.21/fix5

Conversation

@WhereisFff

@WhereisFff WhereisFff commented Sep 20, 2026

Copy link
Copy Markdown
Contributor
  • 统一扫描、导入和旧磁盘的蓝图规范化,补全多方块部件并清理孤立部件及无源流体
  • 校验部件重叠、移动活塞和尺寸超限,统一保存、预览、展示物识别与部署的数据
  • 抑制蓝图静默建造期间的邻居更新、方块事件和计划刻,避免恢复方块实体时触发间接更新
  • 按实际可用液体源过滤部分建造中的流动液体,避免缺少源头时生成孤立流体
  • 修正粉碎台、筛网和拆包台的建造材料,支持从容器或掉落物消耗冲压平台与升级材料,并在放置失败时返还
  • 为结构扫描器添加滚轮调节范围和界面状态提示,显示导入修复统计及文件操作错误
  • 统一扫描范围与边框计算,仅在持有或佩戴铁砧锤时显示扫描范围
  • 修正巨型铁砧落点坐标,统一碰撞边距计算
  • fixed [Bug] 建筑杖蓝图放水层 #4956
  • fixed [Bug] 巨型铁砧落地碎裂 #4959
  • fixed [Bug] 结构扫描仪渲染与框内不一致 #4961
  • fixed [Bug] 智能方块放置器/建筑杖无法放置粉碎/过筛/解包加工台 #4960

- 统一扫描、导入和旧磁盘的蓝图规范化,补全多方块部件并清理孤立部件及无源流体
- 校验部件重叠、移动活塞和尺寸超限,统一保存、预览、展示物识别与部署的数据
- 抑制蓝图静默建造期间的邻居更新、方块事件和计划刻,避免恢复方块实体时触发间接更新
- 按实际可用液体源过滤部分建造中的流动液体,避免缺少源头时生成孤立流体
- 修正粉碎台、筛网和拆包台的建造材料,支持从容器或掉落物消耗冲压平台与升级材料,并在放置失败时返还
- 为结构扫描器添加滚轮调节范围和界面状态提示,显示导入修复统计及文件操作错误
- 统一扫描范围与边框计算,仅在持有或佩戴铁砧锤时显示扫描范围
- 修正巨型铁砧落点坐标,统一碰撞边距计算
Copilot AI lite review requested due to automatic review settings September 20, 2026 12:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@Gugle2308

Copy link
Copy Markdown
Collaborator

⚠️ Dangerous command requires approval:

cd /tmp; curl -sL "https://api.github.com/repos/Anvil-Dev/AnvilCraft/pulls/4962" -o meta.json 2>/dev/null; python3 -c "
import json
d=json.load(open('/tmp/meta.json'))
print('state',d.get('state'),'me...

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 && python3 -c "
import sys
sys.argv=['x','/tmp/minecraft-client-1.21.1.jar']
exec(open('mc_probe_4962.py').read().split('targets = [')[0])
print('Level obf:', CLASSES.get('net.m...

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 && python3 -c "
import zipfile
z=zipfile.ZipFile('nf-src.jar')
names=[n for n in z.namelist() if 'world/level/Level.java' in n or n.endswith('LevelTicks.java')]
print(names[:10]...

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 && rm -rf mc261 && mkdir mc261 && cd mc261 && unzip -o -q /opt/data/workspace/client261.jar 'net/minecraft/world/level/Level.class' 'net/minecraft/server/level/ServerLevel.class' 'net/minecraf...

Reason: 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

⚠️ Dangerous command requires approval:

cd /tmp && unzip -o -q client-sources.jar "net/minecraft/client/gui/screens/inventory/AbstractContainerScreen.java" -d /tmp/mcsrc 2>/dev/null; ls /tmp/mcsrc/net/minecraft/client/gui/screens/inventory/...

Reason: Security scan — [MEDIUM] Archive extraction to sensitive path: Archive command 'unzip' extracts to a potentially sensitive location

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:

for i in 4956 4959 4960 4961; do echo "--- #$i ---"; curl -s "https://api.github.com/repos/Anvil-Dev/AnvilCraft/issues/$i" | python3 -c "import sys,json;d=json.load(sys.stdin);print(d.get('title'));pr...

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/$i — or: vet https://api.github.com/repos/Anvil-Dev/AnvilCraft/issues/$i (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.

@PigeonNian
PigeonNian merged commit 56ce7b8 into Anvil-Dev:dev/1.21/1.6 Sep 20, 2026
2 checks passed
@Gugle2308

Copy link
Copy Markdown
Collaborator

(action = closed,按规则跳过审查,不发布审查意见。本次未下载 diff、未发表任何评论。)

@Gugle2308

Copy link
Copy Markdown
Collaborator

代码审查摘要 — PR #4962

操作: opened(dev/1.21/fix5dev/1.21/1.6,1 commit,mergeable_state: clean
范围: 35 个文件(29 Java / 6 资源,新增 10、删除 0)/ +912 −391(与 API 元数据逐项核对一致,无截断、无 ghost 文件)
标题: 英文+中文都已覆盖两个主题,无需修改(未执行 gh pr edit


🔴 关键(需修复后再合并)

1. StructureScannerActionPacket「confirm」分支漏捕获新增的 IllegalArgumentException(主保存按钮会抛出到网络层)

// StructureScannerActionPacket.java:118-122  —— 无 try/catch
String structureName = name.isEmpty() ? "structure_" + System.currentTimeMillis() : name;
dev.dubhe.anvilcraft.util.StructureSaveUtil.saveStructureToDisk(player.level(), blockEntity, structureName);

调用链:saveStructureToDiskbuildStructureNBTStructureSaveUtil.buildSnapshotBlueprintNormalizer.normalize,后者本 PR 新增三处 IllegalArgumentException

  • Moving piston at …(扫描层正好抓到活塞动画中的 moving_piston,扫描每 tick 一层,很容易撞上)
  • Overlapping blueprint parts at …
  • Complete blueprint exceeds 16x16x16 at …

StructureSaveUtil.saveStructureToDiskcatch (IOException)(第 137 行),而同一个 PR 已经在其它两条保存路径补齐了兜底(StructureScannerBlockEntity.performAutoSave 340-344、StructureScannerSavePacket catch (IOException | IllegalArgumentException)),只有 GUI 主保存按钮这条路径遗漏。anvillib 侧是 ctx.enqueueWork(() -> this.handleOnServer(...)),没有兜底 try/catch,异常会直接在服务端线程抛出(最坏情况崩服/踢人),而且本 PR 新加的界面状态提示在这条主路径上完全收不到错误。

建议:与同分支的 no_disk / output_not_empty 保持一致,包一层并回发状态包:

try {
    StructureSaveUtil.saveStructureToDisk(...);
} catch (IOException | IllegalArgumentException e) {
    PacketDistributor.sendToPlayer(serverPlayer, new StructureScannerStatusPacket(menu.containerId,
        Component.translatable("screen.anvilcraft.structure_scanner.file_failed", e.getMessage())));
}

⚠️ 警告

2. BlueprintFluids.reachable 的遮挡判断是死代码
Shapes.mergedFaceOccludes(state.getCollisionShape(view, pos), target.getCollisionShape(view, next), direction) 两侧都是流体方块(LiquidBlock 碰撞形状恒为空),永远返回 false,等于没有过滤能力。要么删掉(BFS 只沿非 UP 方向扩展已经表达了重力语义),要么换成真正会阻断的判断。
另:commitavailable 只包含 declared ∪ cells,"蓝图边缘贴着世界中已有水池"时,边界外的流动水层会被保守判为不可达而删掉。缺陷 #4956 的复现场景建议额外覆盖一次这种边界供水。

3. 越界补全部件 + 16 上限 = 旧数据突然无法保存
新的 scanNextLayer 会按 forEachPart 记录扫描范围之外的部件(门/床/活塞头/多方块),归一化后包围盒可能变成 17 格 → Complete blueprint exceeds 16x16x16。扫描上限本来就是 16,所以"扫到 16 宽区域里有一个朝外延伸的部件"会让整份蓝图直接失效(自动保存只写日志、手动保存抛异常,见问题 1)。行为变更本身合理,但请确认这是期望语义,并让用户在 GUI 上看到可读原因(配合问题 1 的修复即可)。

4. 界面提示吞掉了原来会进聊天栏的错误
BlueprintClientFiles.message() 现在只在当前 screen 是 StructureScannerScreen 时显示,否则静默丢弃。文件传输超时(isBusy)与 receive 失败发生在异步流程里,玩家此时常常已经关掉 GUI → 错误信息彻底消失(此前是聊天栏消息)。建议保留聊天回退。

5. 静默窗口内 Level.setBlock 全量改道,丢失 vanilla 语义
quietly() 覆盖整个提交调用栈,窗口内任何来源的 level.setBlock 都会走 BuildingCommit.set:不经 Block.updateOrDestroy(旧方块不掉落)、不触发 onPlace/setPlacedBy。对本 PR 自己的放置是预期行为,但注释只写了"抑制间接更新",建议明确写出"窗口内第三方/BE 恢复触发的 setBlock 也会被降级为静默写入、无掉落无回调",或用一个 pos 白名单把改道限制在蓝图自己的格子上。另外 isQuiet 不区分客户端,这里只是靠"commit 都是服务端调用"隐含成立,建议注释/断言固化该前提。


💡 建议

  • BlueprintNormalizer.CACHEmaximumSize(32) 无过期策略,key 持有 HolderLookup.Provider 与整份 NBT;建议加 expireAfterAccess/weakKeys(),避免跨存档、跨维度长期持有旧 registry。(顺带确认:CompoundTag 已覆写 boolean equals(Object) / int hashCode()(官方 mappings 有),所以按值命中成立,缓存不会退化成恒 miss。)
  • BuildingMaterials.reserve() 之后再过滤流动液体:当下不会漏扣材料——流动液体格没有 BE contents、isLiquidBlock && !isSourcegroup.fluids.add 之前就 continue 了,所以这些格没有预留任何资源。但顺序很脆弱,未来一旦给这类格预分配资源就会变成"扣了材料没放方块"。建议前移到 reserve 之前(declared 此时已可用)。
  • 异常类型不统一:同一份校验有的调用方 catch (ConstructionBlueprintException | IllegalArgumentException),有的只 catch 前者。建议让 normalizeConstructionBlueprintException(包装)或在签名上显式声明,减少调用方漏 catch 的机会(问题 1 就是这类漏网)。
  • 死代码BlueprintMultiblocks.forEachPart(pos, state, placement, consumer) 已无调用方(其余都改用 2 参版本 + 归一化预展开),可删。
  • 展示物连带变化:新的 block_placement_rules 让 getPlacementItems(三种加工台) 返回 [冲压平台, 升级件]MultiblockUtil.ingredientList(JEI 多方块材料清单)会因此显示两件材料而不是加工台物品本身。请确认这是期望展示。

🟢 看起来不错

  • 新旧磁盘兼容设计正确:新盘统一存 NORTH/false(坐标在保存时已由 ScannerDiskNormalizer 烘焙),旧盘仍带原朝向/翻转 → 载入时统一归一化,不会二次变换;saveImportedStructure 同样写 NORTH/falseStructureLoadUtil/StructureDiskPreviewSupport 侧一致。
  • 静默写入仍保留撤销记录BuildingCommit.set 内部调用 BuildingRodUndo.replaced,被 mixin 改道的 setBlock 不会漏撤销;同时绕过 LevelChunk.setBlockState 的 RETURN 钩子,也不会重复记录。
  • Mixin 目标经官方 1.21.1 mappings 逐个核对全部存在Level.setBlock(BlockPos,BlockState,int,int) / updateNeighbourForOutputSignal / neighborShapeChangedServerLevel.updateNeighborsAt / updateNeighborsAtExceptFromFacing / neighborChanged(BlockPos,Block,BlockPos) / blockEventLevelTicks.schedule(ScheduledTick)。三个新 mixin 都在 common 列表、命名与排序正确,不会启动即崩。
  • 滚轮调节确实可达ContainerEventHandler.mouseScrolled 是遍历子控件的 default 方法(mappings 里能看到 lambda$mouseScrolled$1(... GuiEventListener)),AbstractContainerScreen 未覆写,所以 Screen 末尾的 super.mouseScrolled 会把事件派发给新增的 RangeValue
  • 加工台材料的消耗/返还链自洽ProcessingTablePlacement 先 simulate 再实取,升级槽不足或放置失败时双项 refund(含 finally 兜底);baseMaterial/isConverted 只对三种加工台生效(STAMPING_PLATFORM 自身 materialFor 为空,不会自我引用);upgradeEntity + placeFromEntities 的扣减/回滚对称;pointer 的 matches 早于 placeToPos,不会出现"只用一个升级件就放出加工台"的 dupe(数据规则虽然把两件都列为可放置物,但 matches 仍要求手持/槽内是冲压平台且另有升级件)。
  • 扫描范围与边框统一:客户端改用 Shapes.create(scannerBE.getScanBounds()),与 calculateWorldPos/worldBlockToPreview 互逆一致,修掉了旧客户端 (rangeX-1)/2 与扫描用 rangeX/2 的错位([Bug] 结构扫描仪渲染与框内不一致 #4961)。
  • 巨型铁砧落点BlockPos.containing(x, y + COLLISION_MARGIN, z) 让"3×3×3 包围盒中心格"在 frac(y)≈1 的退化情形也稳定(旧写法会落到最下层),与 deflate(COLLISION_MARGIN) 同源常量一致。
  • 其它:en_us/en_ud/ScreenLang 三处新增键一致(en_ud 占位符顺序经解码核对无误);added/removed 统计经 stageImport 写入 tag 再由客户端读取,闭环;count = original − complete 的 added/removed 统计与修复语义一致;无 TODO/调试残留、无硬编码凭据、无 ghost 文件。

📋 声称验证表

声称 状态 对应文件/证据
统一扫描/导入/旧磁盘归一化,补全部件+清理孤立部件 BlueprintNormalizershouldRecord 驱动重展开,sameFamily+repair 保留部件族与结构性属性)
清理无源流体 BlueprintFluids.reachable + normalizeremoveIf#4956 场景自洽)
校验部件重叠 / 移动活塞 / 尺寸超限 三处 IllegalArgumentException(但见 🔴 调用方漏 catch)
统一保存、预览、展示物识别、部署的数据 StructureSaveUtil.buildSnapshot 成为唯一入口,DiskDisplaySupport.getImportedDisplay/StructureLoadUtil/BuildingRodService 全走归一化快照
静默建造期间抑制邻居更新/方块事件/计划刻 3 个新 mixin + BuildingCommit.quietly(目标方法已用 mappings 核实)
按实际可用液体源过滤部分建造的流动液体 commit(..., declared) 的 prune(有保守边界,见 ⚠️ 2)
修正粉碎台/筛网/拆包台建造材料,支持容器或掉落物消耗,失败返还 ProcessingTablePlacement + 两个 pointer + BuildingBlockMaterial.baseMaterial + ModBlockPlacementRuleProvider + 3 个新规则 JSON(#4960
滚轮调节范围 / 界面状态提示 / 导入修复统计 / 文件错误 RangeValueStructureScannerStatusPacketadded/removed tag、showStatus(消息回退见 ⚠️ 4)
统一扫描范围与边框计算,仅持锤/戴锤显示 getScanBounds() + hasScannerHammer#4961
修正巨型铁砧落点坐标、统一碰撞边距 FallingGiantAnvilEntity#4961 相关)
fixed #4956 / #4961 / #4960 三个 issue 均 open 且 assignee = WhereisFff,标题与本 PR 修改点一一对应

🧪 测试建议

被测目标 推荐场景 优先级
StructureScannerActionPacket confirm 路径 扫描时让活塞动作 → 点保存:应出界面错误提示、不抛异常 🔴
BlueprintNormalizer.normalize 移动活塞 / 部件重叠 / 16 格越界部件 → 三条消息正确、导入与自动保存都被 catch 🔴
ProcessingTablePlacement.placeFrom* 容器只有冲压平台无升级件、升级件槽位被占、放置目标被阻挡、掉落物只剩 1 个 → 材料必须全额返还 🔴
扫描预览坐标映射 扫描器朝 N/S/W/E × 正/倒置,含门、床、多方块、活塞:GUI 预览与 getScanBounds 边框必须与框内实际一致 🟡
commit 流动液体过滤 蓝图边缘贴着已存在水池、蓝图自带水源层(#4956 复现)、部分建造(partial) 🟡
旧磁盘/旧扫描缓存兼容 用更新前的 .nbt 与 BE 内已持久化的 scannedBlocks 载入:部件应被补全、孤立部件被清理、部署结果与保存前一致 🟡
滚轮调节 三个 range 输入框滚轮 / 下拉列表滚轮 / 文本框滚轮不互相抢事件,边界(0 与最大)夹紧 🟢
撤销(Undo) 静默蓝图提交后整体撤销:被 mixin 改道的 setBlock 也必须还原 🟢

结论: REQUEST_CHANGES — 设计与实现质量整体很高(归一化收敛、静默建造、材料/返还、mixin 目标与滚轮派发都已核实无误),但问题 1 是新增校验直接打到玩家主操作路径上的漏 catch,异常会穿出 packet handler,属于合并前应修的一处;其余为警告与建议。

@Gugle2308

Copy link
Copy Markdown
Collaborator

gh is unauthenticated (invalid token) — I'll skip the title edit and suggest one instead. Here is the review:


代码审查摘要 — PR #4962

操作: opened(处理 opened,正常审查)
范围: 35 个文件(29 Java / 10 新增 / 0 删除)/ +912 −391;dev/1.21/fix5dev/1.21/1.6(MC 1.21.1 / NeoForge 21.1.238)
diff 完整性: patch-diff 与 API changed_files: 35 一致 ✓

✅ 已实测/交叉核实的关键点

  • Mixin 注入目标全部存在且声明在预期类中(用 MC 1.21.1 官方 client mappings 逐类核对,版本与目标分支一致,无版本漂移风险):
    • ServerLevel 自身声明 updateNeighborsAt / updateNeighborsAtExceptFromFacing / neighborChanged(BlockPos,Block,BlockPos) / blockEvent(ServerLevel) (Object) this 强制转换不会在 ClientLevel 上触发 CCE ✓(BlueprintServerLevelMixin 的写法安全)。
    • Level 声明且实现了 setBlock(BlockPos,BlockState,int,int)(非抽象,方法体约 49 行)→ HEAD-cancel 能真正短路原版流程;updateNeighbourForOutputSignal / neighborShapeChanged 均为 void 单重载,CallbackInfo 处理器匹配 ✓。
    • LevelTicks 只有一个 schedule(ScheduledTick),即方块/流体计划刻的唯一汇入口 → 抑制有效,且 this == level.getBlockTicks()/getFluidTicks() 身份判断成立 ✓。
    • BuildingCommit.set() 直接走 LevelChunkSection.setBlockState不回调 level.setBlock → 新增的 Level.setBlock 注入不会自我递归 ✓。
  • Shapes.mergedFaceOccludes(VoxelShape,VoxelShape,Direction) 在 1.21.1 存在(BlueprintFluids 可编译)✓;AABB.encapsulatingFullBlocks ✓;GuiGraphics.drawScrollingString 来自本项目自有的 GuiGraphicsMixinTextWidget/StructureScannerScreen:482 早就在用)✓。
  • 规范化幂等ScannerDiskNormalizer.normalize(..., NORTH, false) 为恒等映射(源码核对),BlueprintNormalizer.normalize 的 min 锚定 ZERO、max 锚定 size-1,因此新格式磁盘再次 load() 是无操作 ✓ —— 这是「保存/预览/展示物/部署统一」能成立的前提,已验证。
  • 磁盘元数据与文件坐标系成对变更StructureSaveUtil.saveStructureToDisk 现在写入 NORTH/false + 标签内 size(:110-123),与 buildStructureNBT 已规范化的帧配套;未被本 PR 改动的两个消费者(StructureDiskPreviewSupport:312-335 的 rotation、SmartBlockPlacerBlockEntity:658quarterTurns = target − scannerFacing + 行列翻转)仍自洽:旧磁盘(预览帧 + 真实扫描朝向)与新磁盘(规范帧 + NORTH)两者补偿量正好差一个 90°,与 ScannerDiskNormalizer 的坐标旋转互为逆 ✓。建议仍实测一次「旧磁盘 + 新磁盘」在智能方块放置器上的朝向。
  • StructureScannerStatusPacket 引入客户端类,符合本仓库既有惯例(network/ 下 10+ 个包同样直接引用 net.minecraft.client.*)✓。

🔴 关键

未发现阻塞性问题(无崩溃/重复扣费/存档破坏级缺陷)。

⚠️ 警告

  1. BuildingRodService.commit:被过滤掉的流动液体会照旧扣材料:570-583 的液体源可达性过滤发生在 materials.reserve(...):555-569之后materials.consume():613之前BuildingMaterials.consume() 会按 source.reserved 全额扣费,因此每个被丢弃的流动液体格(例如一格流动水 = 1 个水桶)仍会被消耗,但方块不会被放置。建议把可达性过滤前置到预留循环之前(用 declared + 所有 group 的 cells 先算出保留集合),或在移除 cell 时同步回退对应预留。
  2. 客户端文件操作提示在 GUI 关闭时会彻底丢失BlueprintClientFiles.message(...):181-190)改为仅当 StructureScannerScreen 打开且 containerId 匹配时调用 showStatus;原先走 player.sendSystemMessage。于是导入/导出失败、isBusy()"Transfer timed out":84-90)、openDirectory() 失败在玩家关屏后既无聊天栏提示也无日志(超时分支连日志都没有)。建议屏幕不可用时回退到聊天消息。
  3. BlueprintNormalizer.CACHE:28)没有任何失效入口 — 该静态 Guava 缓存的 key 强引用 NBT 副本 + HolderLookup.Provider,上限 32 条。客户端登出清理路径 DiskDisplaySupport.logout():153-160)清空了 PATTERNS/RESULTS/StructureLoadUtil 缓存/BlueprintClientFiles,但没有清它 → 跨世界切换后仍持有旧 level 的 registry provider,且数据包重载改变 OrdinaryBlockAdapter.projectionState 输入时会返回陈旧结果。建议补 clear() 并挂到同一登出/重载钩子。
  4. 无源流动液体在扫描/保存路径上是静默删除BlueprintNormalizer.normalize 对所有入口(扫描保存、导出、导入、旧磁盘)都执行「无蓝图内液体源 ⇒ 删除流动方块」,修复统计只通过导入 GUI 展示;直接扫描保存(含 performAutoSave:340-344LOGGER.warn)时玩家看不到任何提示。如果扫描框切到瀑布中段/水面边缘,这些流体格会无声消失。建议至少在自动保存失败/删除非零时给玩家一条提示,并写进手册。
  5. 扫描器边框不再完全遵循 goggleModeRenderEventListener.hasScannerHammer:247-250)与 AnvilHammerItem.shouldRenderEffect 做 AND,使 ALWAYS_SHOW / TOGGLE_WITH_KEY 对结构扫描器边框失效(:253-255)。按 PR 描述这是有意为之,但它改写了客户端配置项的既有语义,建议注释/文档说明;另外 hasScannerHammer 逐字重复了 AnvilHammerItem私有isHolding(主手/副手 instanceof 判断),可考虑公开复用避免分叉。

💡 建议

  • commitavailable 只含蓝图声明位置 + 本次放置的 cells:世界里已存在、但不属于蓝图的液体源不会让下游流动保留(部分建造于既有水体上时会被删)。若这是期望行为可忽略,否则可把格子周边的实际世界流体并入可达图。
  • 新增的三张 block_placement_rules(粉碎台/筛网/拆包台)把冲压平台与升级材料写成同一 properties: "" 下的两条并列规则,getPlacementItems/getPlacementIngredients 会同时列出两者(正确),但 getPlacementItemCount 单独接受任意一件;真正的「两件材料」约束只存在于 ProcessingTablePlacement 里。当前两个 pointer 的 matches() 都对该类方块短路,所以不可达,但建议在 provider 处加一行注释或注释性规则语义,防止后续回归。
  • Level.setBlock 是游戏最热方法之一,HEAD 注入会给每次调用加一次 ThreadLocal.get();且整方法 cancel 会连带丢弃 flags 语义、邻居形状更新与掉落抑制(BuildingCommit.set 不看 flags)。蓝图提交场景可接受,但值得在类注释里写明「静默期 setBlock 退化为 BuildingCommit.set 语义」。
  • PR 标题只覆盖三块改动,遗漏了巨型铁砧落点与加工台材料修正。建议标题:
    Fix blueprint integrity & build behavior, structure scanner interaction and giant anvil landing 修复蓝图完整性、建造行为、结构扫描器交互与巨型铁砧落点
    gh auth status 显示 token 已失效,本次未自动修改)

🟢 看起来不错

  • ProcessingTablePlacement 的失败路径处理扎实:placeFromHandler/placeFromEntitiestry/finally + refund/restoreEntity 保证放置失败时材料回收(含 ItemEntity 数量回填与空栈 discard),且先模拟抽取再实扣,符合「失败返还」的声称。
  • BlueprintNormalizer 把「补全部件 → 孤立部件/无源流体清理 → 重叠/移动活塞/16³ 校验 → 重算 min/max 与调色板」集中到一个入口,且校验时机在写入世界之前,同时给导入 GUI 返回 added/removed 统计,设计良好。
  • BlueprintMultiblocks 的 4 参 forEachPart(placement) 用「先算原始件的偏移、再整体变换」替代「先变换核心、再算偏移」,在 offsetFrom 关于朝向等变的前提下等价(已按源码核对),消除了旧实现里 owners/partState 的复杂合并逻辑。
  • 巨型铁砧:COLLISION_MARGIN 常量统一了 deflateBlockPos.containing(x, y + margin, z);后者正是让「落点格」与 deflate 后包围盒的中间层对齐(y=64.99 时旧写法取 64,新写法取 65),修复方向正确。
  • 扫描层记录改为「先按 worldBlockToPreview 逆变换取预览坐标、再 +1 偏移」,与旧存储约定逐轴一致(已按 calculateWorldPos 的四个朝向分支逐一验算逆映射);captured 集合去重避免同格重复记录。
  • en_ud 新增键位置与 en_us 对齐、%s 顺序(先 added 后 removed)与 Java 调用一致 ✓;三张生成 JSON 无行尾换行与本仓库生成器既有产物一致,非问题。

📋 声称验证表

声称 状态 对应实现
统一扫描/导入/旧磁盘规范化,补全部件 + 清理孤立部件与无源流体 BlueprintNormalizer, BlueprintMultiblocks, BlueprintFluids, StructureSaveUtil.buildSnapshot, StructureLoadUtil:82, BuildingRodClient:165, DiskDisplaySupport:117
校验部件重叠、移动活塞、尺寸超限;统一保存/预览/展示物/部署 BlueprintNormalizer:55/68/94StructureSaveUtil:110-123BlueprintNormalizer.load(含 32 条缓存)
抑制静默建造期的邻居更新、方块事件、计划刻 BuildingCommit.quietly + BlueprintLevelMixin / BlueprintServerLevelMixin / BlueprintTicksMixinBuildingRodService:666 包裹 place
按实际可用液体源过滤部分建造中的流动液体 ⚠️ BuildingRodService:570-583(逻辑正确,但材料已在预留后仍被扣费,见 W1)
修正加工台建造材料;支持容器/掉落物两路消耗冲压平台+升级材料并失败返还 ProcessingTablePlacementBlockItemHandlerPointer:83-124ItemEntityPointer:104-138ModBlockPlacementRuleProvider.addBlockRules 早退分支 + 3 张新 JSON、UseItemOnBlock.materialFor 转 public
扫描器滚轮调范围 + 界面状态提示(导入统计/文件错误) ✅ / ⚠️ StructureScannerScreen.RangeValue:266-283showStatus/renderLabels:515-535StructureScannerStatusPacketBlueprintClientFiles.receive(提示丢失风险见 W2)
统一扫描范围与边框计算,仅持/戴铁砧锤时显示 ⚠️ StructureScannerBlockEntity.getScanBounds + RenderEventListener 共用(覆盖 goggleMode 语义,见 W5)
修正巨型铁砧落点坐标,统一碰撞边距 FallingGiantAnvilEntityCOLLISION_MARGIN 单一定义 + 落点格与 deflate 包围盒对齐)
fixed #4956 / #4961 / #4960 本次未能独立核实 issue 正文(gh 未认证,未访问 issue API);上述 diff 内容与三条描述的核心症状一致

结论: COMMENT — 架构收敛方向正确(三处互不相同的蓝图解析/规范化路径合并为一个入口),Mixin 注入点与坐标变换均已逐项验证无误,无阻塞性问题。建议合并前先处理 W1(丢弃液体格仍扣材料)与 W2(关屏后提示丢失),其余为可选打磨。

🧪 测试建议

被测目标 推荐场景 优先级
BlueprintNormalizer.normalize 幂等性:save→load→save 字节等价;16³ 边界(部件刚好越界);移动活塞/重叠部件必须抛异常 🔴
BlueprintMultiblocks.forEachPart 门/床/高草在扫描框边缘(上半在框外)、活塞头、多部件核心 🔴
BlueprintFluids.reachable 源在框内/框外、水瀑布中段、含水台阶(waterlogged 碰撞形状)遮挡 🔴
BuildingRodService.commit 部分建造:源格未放置时下游流动被丢弃,且材料数必须等于实际放置数(W1 回归) 🔴
BuildingCommit.quietly + 三个 Mixin 嵌套调用时 ThreadLocal 正确恢复;提交结束后邻居更新/计划刻恢复正常;客户端邻居更新不触发 CCE 🟡
ProcessingTablePlacement 放置失败(目标被占)时容器/掉落物材料完整返还;upgradeSlot 与基础材料同槽不同槽;堆叠 >1 时只扣 1 🟡
StructureSaveUtil.saveStructureToDisk / 旧磁盘 旧格式(真实朝向 + 预览帧)与新格式(NORTH + 规范帧)在扫描器预览、磁盘展示物、智能方块放置器上的朝向一致 🟡

由 Hermes Agent 审查

@Gugle2308

Copy link
Copy Markdown
Collaborator

💾 Self-improvement review: Patched SKILL.md in skill 'building-rod-blueprint-review' (1 replacement). · Patched SKILL.md in skill 'mixin-injection-verification' (1 replacement).

@Gugle2308

Copy link
Copy Markdown
Collaborator

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

@Gugle2308

Copy link
Copy Markdown
Collaborator

💾 Self-improvement review: Patched references/blueprint-normalization-and-quiet-build-review.md in skill 'building-rod-blueprint-review' (1 replacement). · Patched SKILL.md in skill 'mixin-injection-verification' (1 replacement).

@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

@Gugle2308

Copy link
Copy Markdown
Collaborator

💾 Self-improvement review: Patched SKILL.md in skill 'mixin-injection-verification' (1 replacement). · Patched references/blueprint-normalization-and-quiet-build-review.md in skill 'building-rod-blueprint-review' (1 replacement). · Patched SKILL.md in skill 'building-rod-blueprint-review' (1 replacement).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

4 participants