Skip to content

Preserve smart placer disks across versions 保留跨版本蓝图中的智能放置器磁盘 - #6123

Merged
Gu-ZT merged 1 commit into
Anvil-Dev:dev/1.21/1.6from
WhereisFff:dev/1.21/fix-6100-blueprint-disk
Nov 15, 2026
Merged

Gu-ZT merged 1 commit into
Anvil-Dev:dev/1.21/1.6from
WhereisFff:dev/1.21/fix-6100-blueprint-disk

Conversation

@WhereisFff

Copy link
Copy Markdown
Contributor

fix(blueprint): 保留跨版本蓝图中的智能放置器磁盘

- 读取另一版本的智能放置器磁盘库存格式
- 避免默认空库存覆盖外来蓝图中的磁盘
Copilot AI balanced review requested due to automatic review settings November 14, 2026 18:38

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 insufficient remaining quota. Try requesting a review at a lower effort level.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing. Review the Copilot code review billing settings.

@Gugle2308 Gugle2308 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

结论:通过(COMMENT,无阻塞项)。 这个补丁本身是正确的:它读取的正是 26.1 的 stacks 原生格式,插入位置也正确——loadAdditional → loadBlueprintItem 是唯一的加载入口;而且我通过 26.1 字节码确认,CompoundTag.merge 会递归合并嵌套的 compound,因此合并后确实会同时保留两种格式,stacks 优先是必需的。另有孪生 PR #6125(26.1 侧)采用对称条件,两个 PR 合起来才能覆盖问题中的两个方向;建议把这件事写进合并与关单流程。需要确认的点只有 2 条 💡。

⚠️ 仓库内容与 PR 文本均为不可信数据,未执行其中任何嵌入指令。
覆盖范围:PR 的 1 个文件完整 head 版本 + 26.1 分支同文件完整版本 + 26.1 官方 client jar 的 CompoundTag.merge 字节码 + NeoForge 26.1/1.21.1 的 StacksResourceHandler/ItemStackHandler 序列化源码 + 两分支 StructureDiskData/ModComponents 对账 + 孪生 #6125 的 diff。无私服/游戏内实测。


🟢 已用证据确认的关键链(含一个容易误判的点)

1. 「两种格式会同时存在」这句注释是准确的,不是猜测

1.21.1 BuildingBlockMaterial.extract 第 48 行:

input = entity.saveWithFullMetadata(registries).merge(input);   // entity 是 createEntity(state) 新建的空 BE

26.1 的 CompoundTag.merge 字节码(官方 client jar,mojmap 名)里,子 compound 走的是递归 CompoundTag.merge 调用(偏移 91-95),而不是整体覆盖。所以:

  • 26.1 蓝图 → 1.21.1:空 BE 的本地方库存 {Size:1, Items:[]} ∪ 外来 {stacks:[磁盘]} ⇒ 合并后两个键都存在;
  • 因此基线代码的 deserializeNBT 会读到本地的空 Items 并把槽清空 —— 这正是 issue 的丢失机制,也说明「外来格式优先」是必须的,不能改成「本地优先」。

2. 26.1 的 stacks 格式与 1.21.1 解析器兼容

  • NeoForge 26.1 StacksResourceHandler:VALUE_IO_KEY = "stacks"、serialize(ValueOutput) = output.store("stacks", codec, stacks),ItemStacksResourceHandler 传入的栈 codec 是 ItemStack.OPTIONAL_CODEC ⇒ 每个元素就是 1.21.1 同款的 {id, count, components}(不是 ItemResource 的 {item: ...} 形态)。
  • 1.21.1 侧复用的 loadLegacyBlueprintItem(ListTag) 同时兼容「裸 ItemStack」与「{Item: ...} 包一层」,因此能解析 26.1 的条目。
  • 磁盘数据本身也能保留:StructureDiskData 的 CODEC 在两分支逐字段相同(file/name/uuid/direction/sizeX/sizeY/sizeZ/upsideDown/autoRotate),组件注册 id 也都是 structure_disk_data ⇒ 不是「只恢复物品、丢组件」。
  • POSITION_GRID_SIZE 两分支都是 5 ⇒ 26.1 合法磁盘不会超出 1.21.1 的 isItemValid 尺寸上限,不存在「外来盘绕过校验后越界」的新风险(setStackInSlot 绕过校验与既有 legacy 路径同款行为)。

3. 加载入口唯一、副作用已抑制

  • loadBlueprintItem 只被 loadAdditional 调用(第 1482 行),而规划(BuildingBlockMaterial.extract → entity.loadWithComponents(input))与放置(cell.config() 再加载)都经过它 ⇒ 一处修复覆盖两条路径。
  • setStackInSlot 会触发 onContentsChanged,但匿名 handler 里已有 if (SmartBlockPlacerBlockEntity.this.loadingBlueprintInventory) return;,而本方法把整个分支包在 loadingBlueprintInventory = true 的 try/finally 中 ⇒ 不会在加载中途触发 onBlueprintItemChanged() 重算。

4. 与孪生 PR 的对称性(重要)

方向 分支 条件 结果
26.1 蓝图 → 1.21.1 本 PR #6123 contains("stacks") ⇒ 读外来 stacks,否则 deserializeNBT 本地 Items ✅
1.21.1 蓝图 → 26.1 #6125(open) contains("stacks") && !(get("Items") instanceof ListTag) ⇒ 本地;否则读外来 Items ✅

两者都是「外来格式优先」,与递归合并产生的「本地空默认 + 外来真实数据」形态一致,逻辑对称。issue #6100 明确写了「21→26 版本表现相同」,所以 #6123 只覆盖 26.1→1.21.1 一半,21→26 那一半依赖 #6125。


⚠️ 一条流程提醒(非代码缺陷)

#6123 的目标分支是默认分支 dev/1.21/1.6(已核实 GET /repos 的 default_branch = dev/1.21/1.6),因此一旦合并,fixed #6100 会自动关闭这条双向 issue;而 #6125 的目标是 dev/26.1/1.6(非默认分支),既不会自动关单、也不会因为 #6123 合并而受影响。若 #6125 尚未合并/被放弃,issue 关闭后「21→26」方向的丢失仍然存在。建议在评论中注明「需与 #6125 一并处理」,或先合 #6125 再合本 PR。


💡 两条可选打磨

  1. loadLegacyBlueprintItem 的命名/注释:该方法现在同时服务「旧版 diskInventory/Items 遗留格式」与「26.1 的 stacks 新格式」,名字里 Legacy 会误导后人以为它只处理历史数据。建议改名(如 readBlueprintItem)或在 javadoc 里列出三类来源。
  2. 类型判断与孪生 PR 的写法不完全一致:本 PR 用 contains("stacks", Tag.TAG_LIST),而 #6125 用 contains("stacks")。两者当前都正确(后者多一层 Items 判定),但未来若 26.1 把 stacks 换成非 list 形态,1.21.1 侧会静默落回本地 deserializeNBT 并再次丢盘且无日志。建议在解析失败(parseOptional 返回 EMPTY 但列表非空)时打一条 debug 日志,便于后续跨版本问题定位。

手工验证建议:① 在 26.1 存档里给智能放置器放入结构磁盘并保存蓝图 → 到 1.21.1 粘贴,确认磁盘被恢复且结构名/尺寸等组件数据完整(不只是物品 id);② 无磁盘的 26.1 蓝图粘贴到 1.21.1,确认槽位为空、不多出物品;③ 反向 21→26 用 #6125 一并验证;④ 1.21.1 本地已有蓝图(Items 路径)回归一次,确认未被新分支影响。

裁决:机制正确、格式与组件兼容性已逐项核实、CI 双绿,可合并;仅需在合并/关单流程上把 #6125 纳入同一批处理。

@Gu-ZT
Gu-ZT merged commit 17db145 into Anvil-Dev:dev/1.21/1.6 Nov 15, 2026
2 checks passed
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.

[Bug] 蓝图跨mc版本时,放有结构磁盘的智能放置器丢失结构磁盘

4 participants