Skip to content

Add data-driven cube selection for 1.21.1 为1.21.1添加数据驱动的模型选取与描边 - #276

Merged
PigeonNian merged 2 commits into
Anvil-Dev:dev/1.21.1from
WhereisFff:codex/cube-data-1.21.1
Nov 14, 2026
Merged

PigeonNian merged 2 commits into
Anvil-Dev:dev/1.21.1from
WhereisFff:codex/cube-data-1.21.1

Conversation

@WhereisFff

@WhereisFff WhereisFff commented Nov 14, 2026 •

Copy link
Copy Markdown
Contributor

feat(cube): 支持资源包配置模型选取与描边

  • 支持按命名空间和方块配置精确模型选取、仅模型描边及原版模式
  • 按资源包优先级逐项合并规则,并在模型重载完成时同步应用规则与几何
  • 保留动态部件和程序排除接口,分离描边与精确选取入口并限制邻格补扫范围
  • 补充资源配置格式、覆盖顺序及 KubeJS 整合包接入说明

fix(cube): 保持仅描边模式的动态几何逐帧更新

  • 在跳过精确选取前刷新客户端帧缓存,避免仅描边模式冻结动态部件
  • 保留嵌套射线调用的缓存保护及超出精确选取距离时的原版行为

- 支持按命名空间和方块配置精确模型选取、仅模型描边及原版模式
- 按资源包优先级逐项合并规则,并在模型重载完成时同步应用规则与几何
- 保留动态部件和程序排除接口,分离描边与精确选取入口并限制邻格补扫范围
- 补充资源配置格式、覆盖顺序及 KubeJS 整合包接入说明
- 在跳过精确选取前刷新客户端帧缓存,避免仅描边模式冻结动态部件
- 保留嵌套射线调用的缓存保护及超出精确选取距离时的原版行为
@Gugle2308

Gugle2308 commented Nov 14, 2026 •

Copy link
Copy Markdown

🌿 Roseau API Breaking Change Report

Module Status Breaking Changes
codec ✅ Compatible 0
collision ✅ Compatible 0
cube ✅ Compatible 0
config ✅ Compatible 0
integration ✅ Compatible 0
moveable-entity-block ✅ Compatible 0
network ✅ Compatible 0
rendering ✅ Compatible 0
font ✅ Compatible 0
explosion ✅ Compatible 0
rpc ✅ Compatible 0
space-select ✅ Compatible 0
util ✅ Compatible 0
math ✅ Compatible 0
multiblock ✅ Compatible 0
recipe ✅ Compatible 0
registrum ✅ Compatible 0
sync ✅ Compatible 0
ui ✅ Compatible 0
wheel ✅ Compatible 0
main ✅ Compatible 0

Full CSVs: see the Artifacts section of this workflow run.

@PigeonNian
PigeonNian merged commit 95c30b1 into Anvil-Dev:dev/1.21.1 Nov 14, 2026
1 check passed
PigeonNian pushed a commit to Anvil-Dev/AnvilCraft that referenced this pull request Nov 14, 2026
* feat(cube): 接入资源包驱动的模型选取与描边

- 将方块命名空间启用和选取排除名单迁移至统一资源配置,保留现有方块的默认模式
- 使整机与动态模型描边遵守统一模式及运行时排除,保留预览几何和方块实体部件排除配置
- 补充资源包覆盖顺序、旧配置迁移和 KubeJS 接入说明
- 配套 Anvil-Dev/AnvilLib#276 的资源规则,依赖发布前使用本地构建联调

* style(cube): 统一模型描边条件的缩进

* build(deps): 更新砧库模型选取依赖

- 将砧库及关联模块更新至 2.0.0+snapshot.682,使用已发布的资源包模型选取与描边功能
- 同步最低依赖版本与配置文档,完成铁砧工艺的数据驱动模型接入

@Gugle2308 Gugle2308 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

结论:PR #276 已在合并后被审查(squash 95c30b13,与 dev/1.21.1 tip 一致,合并树与 head 076385c9 完全相同);本次补做内容级复核,未发现本 PR 引入的阻塞缺陷;横向对比五条版本线后可以看到,本线是唯一带有距离哨兵的线,建议保留,并把这段守卫补到其余四条线。

一、合并态与范围

判据 结果
state / merged / merged_at closed / true / 2026-11-14T11:12:42Z
merge_commit_sha 95c30b13e01f1e5d03507bf3f7fcfdef32ddf261,与 ls-remote dev/1.21.1 相同
合并树与 head 的对比 git diff pr276h2 pr276m 的输出为空,说明进主干的正是 076385c9
规模 7 个文件 +193/−11,与 API 的 changed_files=7 / additions=193 / deletions=11 一致,diff 覆盖完整
head CI build / build ✅(total_count: 1;仓库只有这一项检查)
既有评论 仅 Roseau API 报告 1 条(`cube

二、已在 1.21.1 上核对过的语义

  1. 资源包优先级方向正确。 MultiPackResourceManager(obf atx)的 listPacks() 返回构造器里 List.copyOf 存下的同一个列表,构造器按列表顺序把包 push 进各 namespace 的 FallbackResourceManager(obf atv);atv.getResourceStack 从 size()-1 倒序取、末尾 Lists.reverse,因此按索引升序排列就等于按优先级从低到高排列;CubeSelectionRules.java:43 按优先级升序排序后再顺序 merge,这与 README「从低到高逐项合并」一致。

  2. 目录参数校验存在且方向正确。 1.21.1 也有 checkTrailingDirectoryPath(atx.a(String)V),字节码含义是只有 endsWith("/") 为真时才抛 IllegalArgumentException;因此传入 "anvillib"(无尾斜杠)是合法的,传入 "anvillib/" 才会抛异常。这一点在 1.21.1、1.21.4、1.21.11、26.1、26.2 五条线上完全一致,可以放心写进库文档。

  3. 路径过滤能命中任意 namespace。 FileToIdConverter.fileToId 用 path.substring(prefix.length() + 1, len - ext) 反推,反证 listResourceStacks 返回的 id 带 anvillib/ 前缀,所以 CubeSelectionRules.java:37 的 id.getPath().equals("anvillib/cube_selection.json") 能命中 assets/<任意 ns>/anvillib/cube_selection.json。

  4. 规则读的是本轮包集。 ReloadableResourceManager(obf aub)的 createReload 顺序为:close 旧 resources,然后 new atx,再执行 putfield,最后派发;因此 ModifyBakingResult 期间 listPacks() 与 listResourceStacks() 看到的是同一批新包。

  5. 逐帧链路成立。 GameRenderer.pick(float)(ges.b(F)V)的调用方只有 Minecraft.tick()(fgo.t)与 GameRenderer.renderLevel(ges.a(Lfgf;)V),因此每帧一次;第 2 个提交的 beginFrame 前移一定早于描边提取,仅描边模式不再冻结动态部件。

  6. 其余结论: 规则与几何成对发布(CubeModelEvents.java:22-24、:29)、install 先写 rules 再重算(CubeSelection.java:128-131)、三种模式在四个消费点收敛(target 仅 MODEL、outlineTarget MODEL+OUTLINE、extendsBlock 仅 MODEL、active()=pickingActive)、exclude 优先于配置、公开面零增长(与 Roseau「0 breaking」一致)、README 新增 12 条陈述逐条对得上代码。

三、五线横向对比(本线独有:距离哨兵)

本批 #276 / #277 / #279 / #280 / #281 是同一改动的五条线,我逐条比对过 head 实现:

线 PR distanceToHit 上界守卫 说明
1.21.1 #276(本 PR) ✅ 有(CubePicking.java:38-43) 唯一带守卫的线
1.21.4 #277 ❌ 无 CubePicking.java:38-39 直接赋值
1.21.11 #279 ❌ 无 同 26.x 实现,逐字节相同
26.1 #280 ❌ 无 同上
26.2 #281 ❌ 无 同上

本线这段守卫做的事情是:当 Entity.pick 的返回被第三方模组重定向到远处或子空间坐标时(注释点名的 Sable 场景),先在 start.distanceToSqr(end) + 1e-7 处兜底返回原版结果。其余四条线缺这层兜底,因此会把这个坐标直接交给 BlockGetter.traverseBlocks(start, block.getLocation(), …) 逐格遍历整段射线,每格还要跑 (2r+1)³ 次 getBlockState,并且每帧一次;同时 context.distance 也失去了「不超过射线长度」的上界。

建议二选一,避免将来在本线被当成冗余代码清掉:把这三行补到其余四条线(注释可直接沿用),或者在五条线的对应位置都加注释,说明它依赖的模组场景与触发条件。

四、其他跟进

⚠️ 预算截断完全静默(五条线通病):ModelSelections.java 的 MAX_STATES = 32768 / MAX_GEOMETRY_BYTES = 16 MiB 超限时只做 unsupported++,而 CubeSelection.statistics() 全仓无调用者。README 新推的正是 namespace 级配置("namespaces": {"minecraft": "model"} 这类整包开启),撞上上限的表现是「一部分方块仍走原版行为」且没有任何日志。建议在 CubeModelEvents.apply 里当 unsupportedStates > 0 打一条一次性 warn。

细节建议:

  • README 68–69 行连续两个空行(### Config 模块 在 70 行)。
  • packs.indexOf(...) 的 -1 分支(CubeSelectionRules.java:39):命不中时该源被排成最低优先级(静默降级),建议 Math.max(0, …) 或 debug 日志。
  • load() 的异常边界(CubeSelectionRules.java:35、:37 在逐文件 try 之外):listPacks() / listResourceStacks() 抛 RuntimeException 会穿出 ModifyBakingResult 监听器并让整次模型重载失败,外部资源包引发的问题应退化成 EMPTY。
  • 公开重载 install(Snapshot)(CubeSelection.java:133)不重置 rules,第三方重装快照时会沿用上一轮包规则,建议 javadoc 注明。
  • extendsBlock 热路径(CubeSelection.java:193-196):新增的 mode() 每格做一次注册表反查 + 4 次 map 查询,而 extended 只在 install 时按 MODEL 过滤过(命中即必为 MODEL),可把廉价判断前移。
  • active() / isEnabled() 语义收窄(签名不变、javadoc 已更),下游若用它做渲染/拾取判断需要知会。

五、验证边界

未执行 Gradle 构建、runClient 或 JUnit;结论来自:静态读码 + 三点 diff 对账(7 文件,与 API 计数逐项一致)+ 1.21.1 官方混淆 client.jar 与 client_mappings 反汇编(obf:atx=MultiPackResourceManager、atv=FallbackResourceManager、aub=ReloadableResourceManager、ges=GameRenderer、fgo=Minecraft)+ 与同批 #277 / #279 / #280 / #281 的逐文件比对 + head CI。观感类结论(描边与动态部件是否跟手、outline 手感、F3+T 热换包)静态无法替代实机,建议按 model / outline / vanilla 三档各测一次,并覆盖「整包设成 model 触发预算」与「装带子空间坐标的重定向类模组」两种边界。

@Gugle2308 Gugle2308 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

结论:PR #276 已合并(squash 95c30b13,与 dev/1.21.1 tip 一致,合并树与 head 076385c9 完全相同),评论区此前只有 Roseau 的 API 报告、没有内容级审查;本次补做复核,未发现本 PR 引入的阻塞缺陷,结论只有一条实质跟进项:六条版本线里只有本线带 CubePicking 的距离哨兵。

一、合并态与范围

判据 结果
state / merged / merged_at closed / true / 2026-11-14T11:12:42Z
merge_commit_sha 95c30b13e01f1e5d03507bf3f7fcfdef32ddf261 = dev/1.21.1 tip
合并树 vs head 空 diff ⇒ 进主干的就是 076385c9(含第 2 个提交)
规模 7 文件 +193/−11,与 API changed_files=7 / additions=193 / deletions=11 一致,diff 覆盖完整
head CI build / build ✅
既有评论 仅 Roseau API 报告(`cube

二、已验证的关键语义(1.21.1 官方混淆 client.jar + client_mappings 反汇编)

  1. 包优先级方向正确。 MultiPackResourceManager(obf atx)的 listPacks() 返回构造器 List.copyOf 存下的同一列表;FallbackResourceManager(obf atv)的 getResourceStack 从 size()-1 倒序取、末尾 Lists.reverse ⇒ 索引升序 = 低→高,CubeSelectionRules.java:43 的升序排序 + 顺序 merge 与 README 一致。
  2. 目录参数合法。 1.21.1 也有 checkTrailingDirectoryPath,只在路径 endsWith("/") 时抛 ⇒ 传 "anvillib" 正确;该行为在六条线上完全一致(可写进文档:路径不带尾斜杠)。
  3. 路径过滤跨 namespace 命中。 FileToIdConverter.fileToId 用 prefix.length() + 1 反推,反证 listResourceStacks 返回的 id 带 anvillib/ 前缀 ⇒ :37 的 equals(PATH) 命中 assets/<任意 ns>/anvillib/cube_selection.json。
  4. 规则取本轮包集。 ReloadableResourceManager(aub)的 createReload 顺序为 close 旧 → new → putfield → 派发。
  5. 逐帧链路成立。 GameRenderer.pick(float)(ges.b(F)V)的调用方只有 Minecraft.tick() 与 GameRenderer.renderLevel ⇒ 每帧一次,beginFrame 前移早于描边提取。
  6. 发布原子性 / 容错:CubeModelEvents.java:22-24 / :29 成对暂存与发布;install 先写 rules 再按新规则重算(CubeSelection.java:128-131);merge 全量校验后才返回新 record,异常时保留低优先级规则(:56-77);exclude 在 mode() 首行短路(:111-114)。
  7. 公开面零增长:CubeSelectionRules 与 Mode 包私有、两个 install/isEnabled/mode 重载包私有,与 Roseau「0 breaking」一致;README 新增 12 条陈述逐条对得上代码。

三、唯一实质跟进项:六条线里只有本线有距离哨兵

版本线 PR distanceToHit 上界
1.21.1 #276(本 PR) ✅ 有(CubePicking.java:38-43)
1.21.4 #277 ❌ 无
1.21.8 #278 ❌ 无
1.21.11 #279 ❌ 无
26.1 #280 ❌ 无
26.2 #281 ❌ 无

本线代码:

double distanceToHit = start.distanceToSqr(block.getLocation());
// Sable 等模组可能返回子空间存储坐标,不能从玩家位置跨坐标空间逐格补扫。
if (!(distanceToHit <= start.distanceToSqr(end) + 1.0E-7)) return vanilla;

其余五条线会把这个坐标直接喂给 BlockGetter.traverseBlocks(start, block.getLocation(), …) 逐格遍历整段射线(每格再跑 (2r+1)³ 次 getBlockState),且每帧一次;context.distance 同时失去「不超过射线长度」的上界。建议:把三行补到其余五条线(注释可直接沿用),或在各线对应位置加注释固化其触发场景,避免被当成冗余清掉。

四、其他建议

  • ⚠️ 预算截断静默(六线通病):MAX_STATES = 32768 / MAX_GEOMETRY_BYTES = 16 MiB 超限只 unsupported++,而 CubeSelection.statistics() 全仓无调用者;namespace 级配置最容易撞上,表现为「一部分方块仍走原版行为」且无日志。建议在 CubeModelEvents.apply 里 unsupportedStates > 0 时打一条一次性 warn。
  • 💡 packs.indexOf(...) 的 -1(CubeSelectionRules.java:39):命不中会被排成最低优先级(静默降级),可 Math.max(0, …) 或 debug 日志。
  • 💡 load() 的异常边界(:35、:37 在逐文件 try 之外):listPacks()/listResourceStacks() 抛 RuntimeException 会穿出监听器、让整次模型重载失败,外部资源包引发的问题应退化成 EMPTY。
  • 💡 公开重载 install(Snapshot)(CubeSelection.java:133)不重置 rules,第三方重装快照会沿用上一轮包规则,建议 javadoc 注明。
  • 💡 extendsBlock 热路径(CubeSelection.java:193-196):mode() 每格多一次注册表反查 + 4 次 map 查询,而 extended 命中即必为 MODEL,可把廉价判断前移。
  • 💡 active() / isEnabled() 语义收窄(签名不变、javadoc 已更),下游若用它做渲染/拾取判断需知会。
  • 💡 README 68–69 行连续两个空行(### Config 模块 在 70 行)。

五、验证边界

未执行 Gradle 构建、runClient 或 JUnit;结论来自静态读码 + 三点 diff 对账(7 文件,与 API 计数逐项一致)+ 1.21.1 官方混淆 client.jar 与 client_mappings 反汇编 + 与同批 #277 / #278 / #279 / #280 / #281 的逐文件比对 + head CI。观感类结论(描边跟手度、outline 手感、F3+T 热换包)静态无法替代实机,建议按 model / outline / vanilla 三档各测一次,并覆盖「整包设成 model 触发预算」与「装带子空间坐标的重定向类模组」两种边界。

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