Skip to content

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

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

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

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
space-select ✅ Compatible 0
font ✅ Compatible 0
util ✅ Compatible 0
explosion ✅ Compatible 0
rpc ✅ 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 e7e8207 into Anvil-Dev:dev/1.21.11 Nov 14, 2026
1 check passed

@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 #279 已在本次审查执行前被合并(squash e7e8207e,与 dev/1.21.11 tip 一致,合并树与 head 61e5ecc4 完全相同);这是同一改动的第 5 条线(1.21.1 / 1.21.4 / 1.21.11 / 26.1 / 26.2),我在 1.21.11 官方混淆 jar + client_mappings 上逐条复核了关键语义,未发现本 PR 引入的阻塞缺陷;同时把五条线的差异矩阵补全了——只有 1.21.1 线有距离哨兵,其余四条都没有。

一、合并态与五线关系

判据 结果
state / merged / merged_at closed / true / 2026-11-14T11:13:13Z
merge_commit_sha e7e8207e30259ba6f29e04f44d4ebfdc8a6b3b5c,与 ls-remote dev/1.21.11 相同
合并树 vs head git diff pr279h pr279b 为空 ⇒ 进主干的就是 61e5ecc4
规模 7 文件 +194/−11,与 API 计数一致;payload 里的 diff 覆盖完整
head CI build / build ✅(total_count: 1)
既有评论 仅 Roseau API 报告 1 条,无内容级审查
与其他线的关系 CubeSelection.java / CubeSelectionRules.java / CubePicking.java / CubeModelEvents.java 在 1.21.11 与 26.1 上逐字节相同;CubeHighlightEvents 仅差行宽取值 API,ModelSelections 仅差包移动

二、在 1.21.11 上核对过的语义(混淆 jar + 官方 mappings)

  1. 包优先级方向正确。 MultiPackResourceManager(obf bas)的 listPacks() 返回构造器里 List.copyOf 存下的同一个列表(bas.d),构造器按列表顺序把包 push 进 FallbackResourceManager(obf baq);baq 的 getResourceStack 从 size()-1 倒序取、末尾 Lists.reverse ⇒ 索引升序 = 低→高,CubeSelectionRules.java:43 的升序排序 + 顺序 merge 与 README「从低到高逐项合并」一致。

  2. 目录参数校验存在且方向相同。 bas.a(Ljava/lang/String;)V(checkTrailingDirectoryPath)的字节码是「endsWith("/") 为真才抛 IllegalArgumentException」⇒ 传 "anvillib"(无尾斜杠)合法。1.21.11 已带该校验,与 1.21.4 一致,比 1.21.1 更严格——下游若按旧习惯传 "anvillib/" 会直接抛,值得在库文档里写一句。

  3. 规则读的是本轮包集。 ReloadableResourceManager(obf baw)的 createReload 顺序为「close 旧 resources → new bas → putfield baw.c → 派发」⇒ ModifyBakingResult 期间 listPacks() 与 listResourceStacks() 看到同一批新包,packs.indexOf(sourcePackId()) 与栈顺序同源。

  4. 逐帧链路成立(本线走 LocalPlayer 钩子)。 调用链为 GameRenderer.pick(float)(hob.a(F)V,调用方只有 Minecraft.tick() 与 GameRenderer.renderLevel)→ LocalPlayer.raycastHitResult(float, Entity)(全 jar 唯一调用方就是前者)→ LocalPlayer.pick(Entity,D,D,F) → 被重定向的 Entity.pick ⇒ CubePicking.pick 每帧一次,第 2 个提交的 beginFrame 一定早于描边提取。

  5. Identifier.fromNamespaceAndPath 仍校验。 amo.a(String,String) → amo.d → e/f 两级校验与 1.21.4/26.x 同构,所以 CubeSelectionRules.java:66 用一次性 Identifier 校验 namespace 键在本线有效;非法键仍让整份文件不生效,与 README 一致。

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

三、跟进项

⚠️ 1. 五条线里只有 1.21.1 有距离哨兵(现在可以定论了)

CubePicking.java:38-42(本 PR,与 1.21.4 / 26.1 / 26.2 相同):

context.nearest = block;
context.distance = start.distanceToSqr(block.getLocation());

1.21.1 线同名方法 :38-43 多三行:

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

影响不只是变量复用:Entity.pick 的返回值本身也是被重定向过的点,第三方返回远处/子空间坐标时,本线会从 start 到该坐标逐格遍历整段射线,每格再跑 (2r+1)³ 次 getBlockState,且每帧一次;context.distance 同时失去「不超过射线长度」的上界。既然五条线里只有 dev/1.21.1 有这段守卫,建议明确取舍:要么把它补到其余四条线(注释可直接沿用),要么从 1.21.1 回退——当前状态是同一份库在不同 MC 版本上行为不一致,最难排查。

⚠️ 2. 预算截断完全静默(五条线通病)

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.11 官方混淆 client.jar 与 client_mappings 反汇编(obf:bas=MultiPackResourceManager、baq=FallbackResourceManager、baw=ReloadableResourceManager、amo=Identifier、hob=GameRenderer、gfj=Minecraft、hnh=LocalPlayer)+ 与其余四个孪生 PR 的逐文件比对 + 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 #279 已合并(squash e7e8207e,与 dev/1.21.11 tip 一致,合并树与 head 61e5ecc4 完全相同),此前评论区只有 Roseau 的 API 报告;本次补做内容级复核,未发现本 PR 引入的阻塞缺陷,唯一实质跟进项是六条版本线里只有 1.21.1 带 CubePicking 的距离哨兵。

一、合并态与范围

判据 结果
state / merged / merged_at closed / true / 2026-11-14T11:13:13Z
merge_commit_sha e7e8207e30259ba6f29e04f44d4ebfdc8a6b3b5c = dev/1.21.11 tip
合并树 vs head 空 diff ⇒ 进主干的就是 61e5ecc4
规模 7 文件 +194/−11,与 API 计数一致,diff 覆盖完整
head CI build / build ✅
既有评论 仅 Roseau API 报告(`cube

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

  1. 包优先级方向正确。 MultiPackResourceManager(obf bas)的 listPacks() 返回构造器 List.copyOf 存下的同一列表(bas.d),构造器按列表顺序 push 进 FallbackResourceManager(obf baq);baq.getResourceStack 从 size()-1 倒序取、末尾 Lists.reverse ⇒ 索引升序 = 低→高,CubeSelectionRules.java:43 的升序排序 + 顺序 merge 与 README 一致。
  2. 目录参数合法。 bas.a(String)V(checkTrailingDirectoryPath)只在路径 endsWith("/") 时抛 ⇒ 传 "anvillib" 正确;六条线行为一致,可写进文档(路径不带尾斜杠)。
  3. 规则取本轮包集。 ReloadableResourceManager(baw)的 createReload 顺序为 close 旧 → new bas → putfield baw.c → 派发,因此 listPacks() 与 listResourceStacks() 同一批包。
  4. 逐帧链路成立(本线走 LocalPlayer 钩子)。 链为 GameRenderer.pick(float)(hob.a(F)V,调用方只有 Minecraft.tick() 与 GameRenderer.renderLevel = hob.b(Lgez;)V)→ LocalPlayer.raycastHitResult(全 jar 唯一调用方是前者)→ LocalPlayer.pick(Entity,D,D,F) → 被重定向的 Entity.pick ⇒ CubePicking.pick 每帧一次,beginFrame 早于描边提取。
  5. Identifier.fromNamespaceAndPath 仍校验。 amo.a(String,String) → amo.d → e/f 两级校验 ⇒ CubeSelectionRules.java:66 的 namespace 键校验在本线有效。
  6. 其余结论与同批 #276/#277/#278/#280/#281 相同:规则与几何成对发布、install 先写 rules 再重算、三种模式四消费点收敛、exclude 优先、整份文件校验后替换、公开面零增长。

三、唯一实质跟进项:六线对比,距离哨兵只在 1.21.1

版本线 PR distanceToHit 上界
1.21.1 #276 ✅ 有
1.21.4 #277 ❌ 无
1.21.8 #278 ❌ 无
1.21.11 #279(本 PR) ❌ 无(CubePicking.java:38-39 直接赋值)
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.11 官方混淆 client.jar 与 client_mappings 反汇编(bas/baq/baw/amo/hob/gfj/hnh)+ 与同批 #276 / #277 / #278 / #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