Repository navigation
Add data-driven cube selection for 1.21.8 为1.21.8添加数据驱动的模型选取与描边 - #278
Conversation
- 支持按命名空间和方块配置精确模型选取、仅模型描边及原版模式 - 按资源包优先级逐项合并规则,并在模型重载完成时同步应用规则与几何 - 保留动态部件和程序排除接口,分离描边与精确选取入口并限制邻格补扫范围 - 补充资源配置格式、覆盖顺序及 KubeJS 整合包接入说明
🌿 Roseau API Breaking Change Report
|
- 在跳过精确选取前刷新客户端帧缓存,避免仅描边模式冻结动态部件 - 保留嵌套射线调用的缓存保护及超出精确选取距离时的原版行为
Gugle2308
left a comment
There was a problem hiding this comment.
结论:PR #278 已在本次审查执行前被合并(squash fdadb621,与 dev/1.21.8 tip 一致,合并树与 head 2870ee8a 完全相同);这是同一改动的第 6 条线,我在 1.21.8 官方混淆 client.jar 与 client_mappings 上复核了关键语义,未发现本 PR 引入的阻塞缺陷;六条线横向对比后,只有 1.21.1 带距离哨兵,建议明确取舍。
一、合并态与范围
| 判据 | 结果 |
|---|---|
| state / merged / merged_at | closed / true / 2026-11-14T11:13:05Z |
| merge_commit_sha | fdadb621d54738db44a64289d1a50597df0c0137,与 ls-remote dev/1.21.8 相同 |
| 合并树 vs head | git diff pr278h pr278b 为空 ⇒ 进主干的就是 2870ee8a |
| 规模 | 7 文件 +194/−11,与 API 计数一致(changed_files=7 / additions=194 / deletions=11),diff 覆盖完整 |
| head CI | build / build ✅(total_count: 1) |
| 既有评论 | 仅 Roseau API 报告 1 条,无内容级审查 |
二、在 1.21.8 上核对过的语义(混淆 jar + 官方 mappings)
-
包优先级方向正确。
MultiPackResourceManager(obfaxh)的listPacks()返回构造器里List.copyOf存下的同一个列表(axh.d),构造器按列表顺序把包push进FallbackResourceManager(obfaxf);axf.getResourceStack从size()-1倒序取、末尾Lists.reverse⇒ 索引升序 = 低→高,CubeSelectionRules.java:43的升序排序 + 顺序merge与 README「从低到高逐项合并」一致。 -
目录参数校验存在且方向正确。
axh.a(String)V(checkTrailingDirectoryPath)的字节码是「endsWith("/")为真才抛IllegalArgumentException」⇒ 传"anvillib"(无尾斜杠)合法。至此六条线(1.21.1 / 1.21.4 / 1.21.8 / 1.21.11 / 26.1 / 26.2)该行为完全一致,可以放心写进库文档:路径不带尾斜杠。 -
规则读的是本轮包集。
ReloadableResourceManager(obfaxl)的createReload顺序为「close 旧resources→new axh→putfield axl.c→ 派发」⇒ModifyBakingResult期间listPacks()与listResourceStacks()看到同一批新包,packs.indexOf(sourcePackId())与栈顺序同源。 -
逐帧链路成立。
GameRenderer.pick(float)(gxb.a(F)V)的调用方只有Minecraft.tick()(fue.t)与GameRenderer.renderLevel(gxb.a(Lftu;)V)⇒ 每帧一次,第 2 个提交的beginFrame前移一定早于描边提取,仅描边模式不再冻结动态部件。 -
其余结论与同批 #276/#277/#279/#280/#281 相同:规则与几何成对发布(
CubeModelEvents.java:22-24/:29)、install先写rules再重算(CubeSelection.java:128-131)、三种模式四个消费点收敛(target仅 MODEL、outlineTargetMODEL+OUTLINE、extendsBlock仅 MODEL、active()=pickingActive)、exclude优先于配置、整份文件校验通过后才替换、公开面零增长(与 Roseau「0 breaking」一致)。
三、六线横向对比:距离哨兵只有 1.21.1 有
| 版本线 | PR | CubePicking 的 distanceToHit 上界 |
位置 |
|---|---|---|---|
| 1.21.1 | #276 | ✅ 有 | :38-43 |
| 1.21.4 | #277 | ❌ 无 | :38-39 直接赋值 |
| 1.21.8 | #278(本 PR) | ❌ 无 | 同上 |
| 1.21.11 | #279 | ❌ 无 | 同上 |
| 26.1 | #280 | ❌ 无 | 同上 |
| 26.2 | #281 | ❌ 无 | 同上 |
1.21.1 那段做的事:Entity.pick 的返回若被第三方模组重定向到远处或子空间坐标(注释点名的 Sable 场景),先在 start.distanceToSqr(end) + 1e-7 处兜底返回原版结果。另外五条线缺这层兜底,会把这个坐标直接喂给 BlockGetter.traverseBlocks(start, block.getLocation(), …) 逐格遍历整段射线(每格再跑 (2r+1)³ 次 getBlockState),且每帧一次;context.distance 同时失去「不超过射线长度」的上界。
建议二选一,避免同一份库在不同 MC 版本上行为不一致:把这三行补到其余五条线(注释可直接沿用),或者在六条线的对应位置都加注释说明它针对的模组场景与触发条件,防止将来被当成冗余代码清掉。
四、其他跟进
ModelSelections.java 的 MAX_STATES = 32768 / MAX_GEOMETRY_BYTES = 16 MiB 超限时只做 unsupported++,而 CubeSelection.statistics() 全仓无调用者。README 新推的正是 namespace 级配置("namespaces": {"minecraft": "model"} 这类整包开启),撞上上限的表现是「一部分方块仍走原版行为」且没有任何日志。建议在 CubeModelEvents.apply 里当 unsupportedStates > 0 打一条一次性 warn。
细节建议:
- README 69–70 行连续两个空行(
### Config 模块在 71 行)。 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.8 官方混淆 client.jar 与 client_mappings 反汇编(obf:axh=MultiPackResourceManager、axf=FallbackResourceManager、axl=ReloadableResourceManager、gxb=GameRenderer、fue=Minecraft)+ 与同批 #276 / #277 / #279 / #280 / #281 的逐文件比对 + head CI。观感类结论(描边与动态部件是否跟手、outline 手感、F3+T 热换包)静态无法替代实机,建议按 model / outline / vanilla 三档各测一次,并覆盖「整包设成 model 触发预算」与「装带子空间坐标的重定向类模组」两种边界。
Gugle2308
left a comment
There was a problem hiding this comment.
结论:PR #278 已合并(squash fdadb621,与 dev/1.21.8 tip 一致,合并树与 head 2870ee8a 完全相同),此前评论区只有 Roseau 的 API 报告;本次补做内容级复核,未发现本 PR 引入的阻塞缺陷,唯一实质跟进项是六条版本线里只有 1.21.1 带 CubePicking 的距离哨兵。
一、合并态与范围
| 判据 | 结果 |
|---|---|
| state / merged / merged_at | closed / true / 2026-11-14T11:13:05Z |
| merge_commit_sha | fdadb621d54738db44a64289d1a50597df0c0137 = dev/1.21.8 tip |
| 合并树 vs head | 空 diff ⇒ 进主干的就是 2870ee8a |
| 规模 | 7 文件 +194/−11,与 API 计数一致,diff 覆盖完整 |
| head CI | build / build ✅ |
| 既有评论 | 仅 Roseau API 报告(`cube |
二、已验证的关键语义(1.21.8 官方混淆 client.jar + client_mappings 反汇编)
- 包优先级方向正确。
MultiPackResourceManager(obfaxh)的listPacks()返回构造器List.copyOf存下的同一列表(axh.d),构造器按列表顺序 push 进FallbackResourceManager(obfaxf);axf.getResourceStack从size()-1倒序取、末尾Lists.reverse⇒ 索引升序 = 低→高,CubeSelectionRules.java:43的升序排序 + 顺序merge与 README 一致。 - 目录参数合法。
axh.a(String)V(checkTrailingDirectoryPath)只在路径endsWith("/")时抛 ⇒ 传"anvillib"正确;六条线该行为一致,可写进文档(路径不带尾斜杠)。 - 路径过滤跨 namespace 命中。
FileToIdConverter.fileToId用prefix.length() + 1反推,反证返回的 id 带anvillib/前缀 ⇒:37的equals(PATH)命中任意 namespace 下的同名文件。 - 规则取本轮包集。
ReloadableResourceManager(axl)的createReload顺序为 close 旧 → newaxh→putfield axl.c→ 派发。 - 逐帧链路成立。
GameRenderer.pick(float)(gxb.a(F)V)的调用方只有Minecraft.tick()(fue.t)与GameRenderer.renderLevel(gxb.a(Lftu;)V)⇒ 每帧一次,beginFrame前移早于描边提取。 - 其余结论与同批 #276/#277/#279/#280/#281 相同:规则与几何成对发布、
install先写rules再重算、三种模式四消费点收敛、exclude优先、整份文件校验后替换、公开面零增长。
三、唯一实质跟进项:六线对比,距离哨兵只在 1.21.1
| 版本线 | PR | distanceToHit 上界 |
|---|---|---|
| 1.21.1 | #276 | ✅ 有 |
| 1.21.4 | #277 | ❌ 无 |
| 1.21.8 | #278(本 PR) | ❌ 无(CubePicking.java:38-39 直接赋值) |
| 1.21.11 | #279 | ❌ 无 |
| 26.1 | #280 | ❌ 无 |
| 26.2 | #281 | ❌ 无 |
1.21.1 的守卫处理「Entity.pick 返回被第三方模组重定向到远处/子空间坐标」(注释点名 Sable):先在 start.distanceToSqr(end) + 1e-7 处兜底返回原版结果。其余五条线会把该坐标直接喂给 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。- 💡 README 69–70 行连续两个空行(
### Config 模块在 71 行)。 - 💡
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 已更),下游若做渲染/拾取判断需知会。
五、验证边界
未执行 Gradle 构建、runClient 或 JUnit;结论来自静态读码 + 三点 diff 对账(7 文件,与 API 计数逐项一致)+ 1.21.8 官方混淆 client.jar 与 client_mappings 反汇编(axh/axf/axl/gxb/fue)+ 与同批 #276 / #277 / #279 / #280 / #281 的逐文件比对 + head CI。观感类结论(描边跟手度、outline 手感、F3+T 热换包)静态无法替代实机,建议按 model / outline / vanilla 三档各测一次,并覆盖「整包设成 model 触发预算」与「装带子空间坐标的重定向类模组」两种边界。
feat(cube): 支持资源包配置模型选取与描边
fix(cube): 保持仅描边模式的动态几何逐帧更新