Skip to content

1.21.1 Blueprint editing and shared previews 完善结构蓝图编辑与共享预览并修复红石及实体交互 - #6128

Merged
Gu-ZT merged 1 commit into
Anvil-Dev:dev/1.21/1.6from
WhereisFff:codex/1.21-blueprint-preview-6127
Nov 15, 2026
Merged

Gu-ZT merged 1 commit into
Anvil-Dev:dev/1.21/1.6from
WhereisFff:codex/1.21-blueprint-preview-6127

Conversation

@WhereisFff

Copy link
Copy Markdown
Contributor

将 #6127 的功能提交 4766d9c30abcffefefd490929f06982fcb74e4c0 完整移植到 dev/1.21/1.6(Minecraft 1.21.1)。

  • 为扫描仪添加方块选择、JEI 标记格、facing 轮换、单个替换、完整状态批量替换、撤回和扫描仪相对区域裁剪/扩展,调整磁盘界面、overlay 布局及长文件名悬停滚动。
  • 将扫描仪、智能放置器及磁盘预览接入砧库共享渲染,支持缩放、左键旋转、右键平移、点击音效、范围框和 75% 蓝色扫描效果;接入带连线的只读 GUI 浮窗,处理事件遮挡及 tooltip 对侧布局。
  • 为板条箱、大型板条箱、潜影容器和超维存储站保存库存、流体、容量及合成状态快照,供手册和扫描仪共享预览。
  • 将藿香改为可选集成并取消捆绑,适配 1.21.1 的渲染、注册、NBT 和存储接口;使用 AnvilLib 2.0.0+snapshot.689 和 Ageratum 0.0.1+build.151。
  • 补齐红石导线六面短拐角模型、信号传递与邻居更新,修复高级比较器窗口模式记忆恢复。
  • 修复大红按钮、物品检测器及磁化节点随活塞移动的行为,按实际接触面定位下落方块碰撞目标并修正速度阈值,提升三类溜槽抗爆性并保留金属音效。

验证:

  • ./gradlew.bat compileJava build -I build/port-style.gradle portCheckstyle --console=plain 通过;改动文件 Checkstyle 零告警,全仓库检查仅有未改动文件的 15 条既有告警。
  • ./gradlew.bat -I build/port-tests.gradle runGameTestServer --console=plain 和添加 -PportWithHandbook 的运行各通过 50 项本地 GameTest,覆盖蓝图编辑、存储快照、可选手册加载、六面红石转角、活塞与碰撞行为。
  • 安装及不安装藿香两种环境的 runData 均通过;仅保留与本次功能有关的生成资源。
  • git diff --check、git diff --cached --check 通过;成品仅内置砧库,无藿香捆绑和本地测试文件。
  • 游戏内画面和鼠标操作尚未实测。本地验证脚本及 GameTest 未提交。

- 为结构扫描仪添加选块、JEI 标记格、facing 轮换、单个及完整状态批量替换、撤回和蓝图区域裁剪扩展
- 调整磁盘界面切换与 overlay 布局,支持导入长名称悬停滚动及扫描仪范围预览
- 将扫描仪、智能方块放置器和磁盘预览迁移至砧库,统一缩放、左键旋转、右键平移及 75% 蓝色扫描效果
- 接入带连线的只读 GUI 浮窗和存储快照,避免事件穿透及磁盘预览与 tooltip 重叠
- 将藿香改为可选集成并取消捆绑,适配 1.21.1 的渲染、注册与存储接口,升级砧库及藿香依赖
- 补齐六面红石导线短拐角模型、信号传递与邻居更新,修复高级比较器记忆恢复
- 支持大红按钮、物品检测器及磁化节点随活塞移动,修正下落方块碰撞目标与速度阈值
- 提升三类溜槽抗爆性并保留金属音效
Copilot AI balanced review requested due to automatic review settings November 14, 2026 22:16

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)。#6127 到 dev/1.21/1.6 的端口适配面(ItemStack.OPTIONAL_STREAM_CODEC、BlockPos.CODEC、9 参 blit、IGhostIngredientScreen、getStructureBlockEntityData、Entity.collide 注入、AbstractMultiPartBlock#getMainPartPos)逐处对得上,未发现崩溃级路径;CI build / checkstyle 均 success(已核对 check-runs)。建议合入前处理 ⚠️1、⚠️2,并对 ⚠️3、⚠️4 给出结论或测试证据;其余为清理/确认项。

仓库内容与 PR 描述按不可信数据处理,本次未运行游戏(作者也注明画面/鼠标未实测)。Diff 覆盖:PR 的 77 个文件已全部核对(Java 逐文件、生成资源抽查、overlay.png 尺寸实测)。

已核实

  • 红石短拐角资源链:RedstoneWireBlockStateGenerator 现在对 6 个附着方向 × 4 个索引生成 CORNER_SP;生成物 = blockstate 24 个 corner_sp 条目(48 处字符串命中)+ 24 个模型文件(新增 20 + 既有 4 个水平 _0),与 datagen 源一一对应。
  • 转角信号与邻居更新:getCornerSignal/hasCornerConnection/notifyCornerTargets/neighborChangedAroundSupport 的改名调用点全部同步(RedstoneWireNetworkManager、BlockEventListener、reattach、SignalGetterMixin),axis.ordinal() 去重覆盖 12 个对角位置;SignalGetterMixin 仍是 Math.max 追加语义。
  • 活塞 + 磁化节点:PistonBaseBlockMixin 在 moveBlocks 内包裹 PistonStructureResolver#getToPush,@Local(argsOnly=true) Level 与 1.21.1 签名匹配;节点 tick 在目标格是 MOVING_PISTON && !isSourcePiston() 时用 getMovedState() 判活(不会被代理方块误杀),moveWithPiston 同时同步支撑格与实体位置。
  • 下落方块碰撞定位:1.21.1 Entity.move 只调用一次 collide;mixin 的轴序 |x|<|z| ? {Y,Z,X} : {Y,X,Z} 与 1.21.1 Entity.collideWithShapes 字节码一致(先 Y,再按 Math.abs 比较决定 Z/X 先后),BlockCollisions 5 参构造 + pos.immutable() 正确。
  • 高级比较器:loadAdditional 里的 getBlockState() 返回构造期缓存的 blockState 字段(1.21.1 BlockEntity.getBlockState 字节码为 aload_0; getfield dqh.f; areturn,不读 level),重载期不会 NPE;state = POWERED != outputInvert ? HIGH : LOW 与 isOutputting() 恒等,onLoad 计划刻 1 tick 重算;tick 删除的重复 updateBlockAndNeighbours 由 update(...) 末尾执行,changed 短路保证幂等。
  • 离屏预览:RenderTarget.clear(boolean) 内部先 _bindWrite(true)、末尾 unbindWrite()(1.21.1 客户端 jar 反汇编确认),因此 setClearColor → clear → bindWrite(true) 不会误清主帧缓冲;PreviewRenderState 保存/恢复 framebuffer、viewport、scissor、depth/color mask、blend、雾、3 个 shader 纹理,submitNative 的状态收放顺序正确。
  • 扫描后处理:scan_preview 的预乘混合(one/1-srcalpha)与 StructurePreviewEffects.blit 的反预乘 + ScanOpacity 一致;shader.clear() 在 finally 中。
  • TriStateButton 的 16 → 48:不改变采样 UV(yOffset 与 texHeight*3 同步放大 3 倍,UV 仍是 0 / ⅓ / ⅔),属无害改动,不是回归。
  • 蓝本 tick 坐标:buildCachedSnapshot 的 world - origin + result.offset() 与 ScannerDiskNormalizer/BlueprintNormalizer 的规范化帧一致(四种朝向 + 倒置逐一代入推演),不会把计划刻映射到错误方块;BlueprintTicks.restore 还有类型二次校验。
  • 存储预览/手册:StorageStructurePreview 用主部件位置取快照 NBT(非主部件在 captureBlockEntity 提前返回,不写 key,两边一致);StoragePreviewSnapshot 的容量常量(2048 / 65536 / 1024 / MAX)与 StorageType 对得上;overlay.png 实测 65×40,与两处 9 参 blit 区域一致;新增 5 个 lang key 在 ScreenLang/en_us/en_ud/zh_cn 同步。
  • ageratum 可选化:所有 dev.anvilcraft.resource.ageratum 引用都落在客户端门控/@Integration/指南渲染路径内(AnvilCraftRecipeComponentFactories 仅被 AnvilCraftClient 的 isLoaded 分支引用,AgeratumUtil 只被 markdown 组件使用,PortalConversionCategory 已去掉 ageratum 依赖);mods.toml 的 [[dependencies."${mod_id}"]] 写在 [mc-publish] 之后仍是根级表(TOML 表头是绝对路径,合法),ageratum_version 已加入 ProcessResources 替换。
  • 溜槽与移动通知:CHUTE/SIMPLE_CHUTE/SIMPLE_MAGNETIC_CHUTE 改为 END_STONE 后覆写 METAL 音效,MAGNETIC_CHUTE/OVERFLOW_CHUTE 经 initialProperties(ModBlocks.CHUTE/MAGNETIC_CHUTE) 继承,5 个溜槽抗爆一致;ItemDetectorBlock.notifyMoved 重算探测范围。

⚠️ 建议处理

  1. StoragePreviewSnapshot.read 的 getOrThrow(以及 captureBlockEntity 的 encode):read(约 :123)对结构文件里的 anvilcraft:storage_preview 直接 CODEC.parse(...).getOrThrow(),StorageStructurePreview.create 没有捕获;一旦物品/流体来自已卸载的模组、count 为 0、或旧/新 schema 缺 items/capacity,打开该结构的手册/扫描仪存储预览会抛 DataResult.Error(客户端崩溃)。captureBlockEntity(约 :110)的 encode 也在 scanNextLayer 的服务端 tick 路径上用了 getOrThrow。建议都改成 resultOrPartial(...).orElseGet(() -> empty(type))(或 flatMap)+ 一条 WARN。
  2. 智能放置器在蓝图模式下每帧重载结构:SmartBlockPlacerScreen.getOrCreateCachedPreviewLevelLike(约 :1320)每帧调用 StructureLoadUtil.loadStructureFromDiskForPreview → BlueprintNormalizer.load 的 LoadKey 以整个 CompoundTag 为键,record 相等性走 CompoundTag 的值语义(1.21.1 CompoundTag.hashCode() = tags.hashCode(),深层遍历整份结构 NBT;maximumSize(32) 一旦淘汰还会整份重解析),随后 StructureData.fromSnapshot 又复制一遍全部方块条目;另外 renderDisplayedBlock(约 :910)每帧 new LevelLike + StructurePreviewScene.of(icon)(键是新对象,CACHE 必不命中 ⇒ 每帧重建 StructureTemplate + StructureSandboxFactory 沙盒)。结构越大、蓝本带 NBT 时越明显,建议在 Screen 内按 STRUCTURE_DISK_DATA(file+uuid)缓存 StructureData/snapshot,图标按 BlockState 缓存 scene。
  3. 编辑后保存的方块状态朝向与未编辑保存不一致(需确认):对原始扫描做替换时,StructureScannerFiles.editBlueprint 会把快照旋转到 scanner 预览帧(StructureBlueprintEdit.rotate(snapshot, rotation),rotation 恰为 facingPlayer(scannerDir, SOUTH) = ScannerDiskNormalizer 的逆),保存时 StructureDiskData.direction 固定 NORTH;而放置侧 StructureLoadUtil.loadStructureFromDisk 对未编辑磁盘施加 facingPlayer(dir, SOUTH)、对编辑后磁盘施加 NONE —— 位置旋转相消,但该 loader 只旋转位置、方块状态原样使用,于是“编辑后保存”的文件状态被旋转过、“未编辑保存”的文件状态是 canonical。两者放置出来的朝向(楼梯/机器正面等)可能不同。建议用 GameTest 对账“编辑一个方块后保存”与“不编辑直接保存”,断言位置与状态都一致;若不一致,说明保存侧应把状态旋转回 canonical(或在 saveImportedStructure 记录真实 direction)。
  4. 碰撞速度阈值边界:FallingBlockCollisionEventListener:56 由 config > speed → return 改为 speed <= config → return,爆炸条件从 speed >= 阈值 变成 speed > 阈值;默认 16 时恰好 16 不再爆炸,而 AnvilCraftServerConfig:65 的注释仍写 “minimum … explode”、FallingBlockCollisionEventListener:66 的配方门仍是 speed < recipe.speed()(含端点)。请统一三处语义(要么改回 <,要么同步注释与配方门说明)。#6127 同一处也是这个改动,建议两线一起定。

💡 可选清理/确认

  • StructureDiskPreviewSupport 的 PENDING_PREVIEW_DATA / receiveStructureData / parsePreviewNbt 无任何调用方(真实回填走 StructureDiskResponsePacket → StructureLoadUtil.cacheStructureNbt),clearCache() 也无人调用(会话级缓存在登出时不清);建议删除或接线。
  • AnvilCraftMixinPlugin.hasAgeratum 在本分支没有对应 mixin:mixin 包下没有 client/Handbook* 类,mixins.json 也没有任何 ageratum mixin,shouldApplyMixin 的该分支永不命中(不影响功能,但与 #6127 的意图不符)。
  • 编辑入口与磁盘面板互斥:blueprintVisible = hasDisk && (imported || scanComplete),而选择/替换/撤回都要求 !blueprintVisible;常规“插盘→扫描→保存”流程里看不到替换按钮,需要先取出磁盘再编辑。请确认这是预期的操作流(若是,建议在手册/描述里写明)。
  • DiskItemRenderer:40 的末参从 blueprint 改成 suppressFoil 后仍传 structure;同时 scan_preview_item 着色器已删,磁盘图标上的扫描效果消失——确认是否有意(若否,末参应传 false)。
  • StructureScannerEditPacket 无服务端节流:每次编辑都会重建/规范化并压缩整份蓝图回传,客户端 isBusy 不是服务端限频;建议按玩家加冷却(RedstoneWirePowerRequestPacket 式先例)。
  • 建议保留/补一条 #4325 场景的回归测试(窗口模式:输入在区块卸载期间变化后重载),因为 loadAdditional 现在信任存档 POWERED 而不再用重采样输入重算。
  • 三个溜槽硬度由 5.0(IRON_BLOCK)变为 3.0(END_STONE),描述只提到抗爆与音效;若是有意可忽略,否则用 .properties(p -> p.explosionResistance(9)) 保留原硬度。

声称核对

声称 结论
#6127 功能完整移植到 1.21.1 ✅ 逐文件核对,API 适配正确
build + portCheckstyle 通过 ✅ CI build/checkstyle success(等价门禁)
含/不含藿香两套 runData 通过 无法离线复现(脚本未提交);生成资源与 datagen 源抽查一致 ⚠️
50 项 GameTest(含 -PportWithHandbook) 无法核实:CI 无 gametest job,测试未提交(作者自述)
成品仅内置砧库、无藿香捆绑 ✅ dependencies.gradle 已改为 compileClasspath(transitive=false)+runtimeClasspath,无 api/jarJar
游戏内画面/鼠标未实测 与本次未覆盖项一致(FBO 预览、输入层、tooltip 对侧布局需实机验证)

未覆盖

  • 游戏内渲染与输入:StructurePreviewScene 的 FBO 合成/范围框/缩放平移旋转、StructureGuiPreview 浮窗、tooltip 对侧布局、drawScrolling 手感(作者已注明未实测)。
  • AnvilLib 2.0.0+snapshot.689 的 StructureGui*/IntegrationManager 运行时行为(本机无该 artifact;GuideEventListener 的 COMMON @Integration 装载路径按仓库既有 CLIENT/DATA 先例推断)。
  • 大型存储快照的实际包体/存档体积;多人并发;Iris/Sodium 兼容。
  • 编辑后保存/放置的坐标系只在源码层推演,未跑 GameTest 复现(即 ⚠️3 的对账项)。

@Gu-ZT
Gu-ZT merged commit 8ae4b1c 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.

4 participants