Repository navigation
Fix scaled cube outline seams (1.21.11) 修复缩放几何的轮廓接缝 - #265
Conversation
- 为选择几何增加每格坐标单位参数,保留默认方块坐标调用方式 - 按尺度换算接缝距离与投影容差,保留薄层几何和部分可见线段 - 覆盖缩放、严格阈值、模型浮点边界与相机变换回归
🌿 Roseau API Breaking Change Report
|
Gugle2308
left a comment
There was a problem hiding this comment.
结论:审查通过。三份文件与 #264(1.21.8)在 head 上逐字节相同,容差换算的区分正确。1.21.11 比 #263/#264 多出一处运行期构造 SelectionGeometry 的调用点,已确认它不构成缺陷。
本次审查对应 head 38c21f25(dev/1.21.11 @ 1da1a858),3 文件 +91/−17,与 API 的 changed_files=3 / additions=91 / deletions=17 和 grep -c "^diff --git"=3 一致;三个文件的 index <old>..<new> 与实际 blob 对得上(461c450e8..b9838477b / 720e24d3c..ee6be8e8f / 2a9b5efb0..d546072d3)。state=open、draft=false、merged=false;CI build / build ✅;除 Roseau 报告(cube ✅ 0 breaking)外无人工评论。
✅ 一、与 #264 的关系:head 上三文件逐字节相同
在 git 树层面对 265 head 与 264 head 做 diff:
OutlineVisibility.java IDENTICAL
SelectionGeometry.java IDENTICAL ← 与 #264 相同,已是 jspecify 版
OutlineVisibilityTest.java IDENTICAL
1.21.8 与 1.21.11 的 module.cube/geometry 包七个文件全部逐字节相同(ConvexShape / OutlineBuilder / OutlineCache / OutlineVisibility / PackedOutline / SelectionGeometry / package-info),所以 #264 与 #265 是同一份改动落在结构相同的两条线上,两 PR 的 patch-diff 归一化后也完全一致(同 md5 0857c90e…)。
七线分组维持上一轮结论:
#262 (1.21.1) base=ee3f6d12e→a3ddb8ab9 (jetbrains @Nullable)
#263 (1.21.4) 同上
#264~#268 720e24d3c→ee6be8e8f (jspecify @Nullable)
✅ 二、容差换算的划分逐行核对正确
| 位置 | 语义 | 应缩放 | 实测 |
|---|---|---|---|
OutlineVisibility.java:28-29 |
OFFSET/EPSILON × unitsPerBlock |
几何单位 | 已乘 ✓ |
:92、:109 abs(a) <= distanceEpsilon |
plane·(point−camera) |
几何单位 | 已换算 ✓ |
low/high = min∓epsilon、clipShape 的 allowance |
与 normal·segment.start() 同量纲 |
几何单位 | 用 epsilon ✓ |
:214 Interval.valid() = max−min > EPSILON |
线段参数 t ∈ [0,1] | 不缩放 | 原值 ✓ |
:189 merge 的 next.min ≤ cur.max + EPSILON |
参数域 | 不缩放 | 原值 ✓ |
:145 append 的 high−low ≤ EPSILON |
参数域 | 不缩放 | 原值 ✓ |
:111 direction > EPSILON |
归一化向量点积(无量纲) | 不缩放 | 原值 ✓ |
:101 side.lengthSqr() > 0.5 |
归一化成功与否 | 无量纲 | 原值 ✓ |
若把参数域或余弦容差一并乘缩放,scale=128 时会把有效区间判无效、把近平共面误判为左右覆盖 —— 这一划分是本 PR 的成败点,结论正确。阈值语义从绝对 0.1/16 提升为「0.1/16 × 每格单位数」,在方块坐标系下保持不变。
测试 :142-159 用 assertEquals(offset >= 0.1d/16, covers(...)) 复刻相对阈值作期望,覆盖 6 档偏移 × 0.5/1/128 三倍率并复核相机逆变换;:162-173 用 128 倍验证部分线段保留;:176-181 覆盖 0/-1/NaN/+∞。
✅ 三、1.21.11 多出的一处运行期构造点:已核实不构成缺陷
// CubeHighlightEvents.java:39-40
PackedOutline fallback = segments > SelectionGeometry.MAX_OUTLINE_SEGMENTS
? new SelectionGeometry(List.of(ConvexShape.box(target.bounds()))).fallbackOutline() : null;这是线段超限时的「整块包围盒」降级路径,每帧可能构造一次 SelectionGeometry。三点核实后判定无害:
- 只取
fallbackOutline()(SelectionGeometry:57返回PackedOutline.of(edges),不带 visibility),forView在PackedOutline.forView里遇visibility == null直接返回自身 ⇒ 接缝逻辑与unitsPerBlock完全不参与; - 即便走
OutlineBuilder.build,单 shape 时OutlineVisibility.build的i<j配对循环无组合 ⇒any=false⇒shapes传List.of()、forView首行早退,epsilon无消费方; - 该几何恒为 scale=1,与
target.bounds()的真实尺度一致(bounds 本身就是方块坐标)。
⇒ 不需要为本 PR 补 unitsPerBlock 参数。只是提示:若将来把缩放引入主路径,这处「按 bounds 新建 scale=1 几何」会与主路径口径不同 —— 但因只画包围盒,语义上仍正确。
⚠️ 四、库内无生产调用方传入缩放,标题所述修复在库内没有可修现场
265 head 全树构造点(git grep "new SelectionGeometry("):
ModelSelections.java:120 new SelectionGeometry(shapes) // 1 参 → scale=1(唯一喂给 CubeSelection 的主路径)
CubeHighlightEvents.java:40 new SelectionGeometry(List.of(box(...))) // 1 参 → scale=1(超限降级)
module.test/PortVerification.java:76,78 new SelectionGeometry(List.of(...)) // 1 参 → scale=1
OutlineVisibilityTest.java:147,167,179 2 参(新增测试,唯二传 scale 处)
全树 scaling( 只出现在新增测试(:146、:166)与无关的 FlexibleTestScreen:155。ModelSelections(:32 的 shared 键、:114-123 的 intern)仍是 1 参;CubeModelDecoder 把模型坐标 /16.0 归一到方块坐标 ⇒ 实际几何一律 unitsPerBlock == 1。
真实交付是「让下游接入方能把缩放烘焙进几何并保持相对阈值」。建议在描述中点名接入方,或标注「为后续接入做准备」,避免日后按标题回溯时产生「为什么没效果」的疑问。
⚠️ 五、ModelSelections.shared 的 intern 键不含缩放
// ModelSelections.java:32
private final Map<List<ConvexShape>, SelectionGeometry> shared = new HashMap<>();
// :114-123
SelectionGeometry existing = this.shared.get(shapes); // 键只有 shapes 列表
SelectionGeometry geometry = new SelectionGeometry(shapes); // 恒 scale=1
this.shared.put(geometry.shapes(), geometry);List<ConvexShape> 走值相等(ConvexShape.equals),键按内容匹配。今天 intern 恒传 1 参,无影响;但新公开构造器把「带缩放几何」变成可达输入 —— 一旦将来有人把缩放几何送进 intern(最自然的接入方式),第二个不同 scale 的请求会静默复用 scale=1 实例,接缝阈值退回绝对值且无任何告警。
建议 intern(List<ConvexShape>, double unitsPerBlock) 并入键(如 record GeometryKey(List<ConvexShape>, double)),或在 intern 上方注明「只接受 block 坐标几何」。附正面确认:OutlineCache.ready 是 LinkedHashMap<SelectionGeometry, …>(:20)、pending 是 IdentityHashMap(:21),而 SelectionGeometry 未覆写 equals/hashCode(grep 计数 0)⇒ 缓存按身份做键,同 shapes 不同 scale 的两个实例不会串味。
💡 六、其余(非阻塞)
OutlineBuilder的四个缩放常量未随之调整(:18-21的GEOMETRY_EPSILON/LINE_EPSILON/SAMPLE_DISTANCE/MERGE_EPSILON;该文件里unitsPerBlock引用数 = 0)。它们属于「棱线生成/合并」侧的绝对几何单位阈值,scale=128 时换算回方块空间变紧 128 倍(1e-7 → 7.8e-10block)。新增测试在 128 倍下实测通过(covers(outline, seam)为真 ⇒ 棱线确实生成了),当前是经验安全而非不变量保证。建议加注释说明「本类容差为绝对几何单位、不随unitsPerBlock缩放」。- 拾取侧容差不随缩放变化:
SelectionGeometry.clip的1.0E-9/1.0E-12/1.0E-10(:82、:84-85、:92、:105-111)保持原值,经SelectionPart逆变换后世界空间等效容差随缩放放大。属既有行为、本 PR 未改,但既然确立了「几何可处于任意缩放」,建议在unitsPerBlock的 javadoc(:27-31)补后半句「不影响射线拾取精度」——作者已写了「只影响轮廓接缝容差」的前半句。 - 参数校验顺序变化:2 参构造器把
unitsPerBlock校验(:33)放在shapes校验(:37)之前,两参数同时非法时抛缩放错误。无害,仅记录。 unitsPerBlock()为包私有(:51-52,无修饰符)而类是public:外部(AnvilCraft)能传值但读不回,SelectionPart也无承载字段,无法自检「几何缩放与变换矩阵是否匹配」。若预期外部接入,考虑公开或提供SelectionPart侧校验入口。- 测试可补两处:①「同 shapes、不同
unitsPerBlock不共享实例」锁住 §五;②Double.MIN_VALUE/1e300下inflate(offset)的边界行为(当前只校验finite && > 0)。
✅ 七、测试执行链路确认
1.21.11 与 1.21.8 同属「16 行 module.cube/build.gradle」形态(1.21.4 是 293 行),接线完整:
:15sourceSets.test.java.setSrcDirs(['src/regressionTest/java'])、:11-13test { useJUnitPlatform() }、:1-5JUnit 5 (junit-bom:5.10.2);:8neoForge { addModdingDependenciesTo(sourceSets.test) };module.gradle未禁用test(enabled = false只作用于machete),默认build → check → test成立;gradle/scripts/ci.gradle:21ciBuild依赖:${target.path}:build⇒ 新增 3 个测试确实在 CI 中执行,与build / build✅ 相互印证。
estimatedBytes 从 160 增至 168(SelectionGeometry:47)、从 64 增至 72(OutlineVisibility:83),与新增一个 double 字段一致(+8 字节)。这两个数值同时被 OutlineCache(:43/47/49/69/76/82/85)与 MAX_GEOMETRY_BYTES(ModelSelections:28)的预算判定消费,因此 +8 是必要的精度修正。
验证边界
未编译、未运行 Gradle(Cube 模块依赖 MC/JOML 运行时)。结论基于 head 源码逐行核对 + 1.21.11/1.21.8 两条 base 的 blob 与全包内容对账 + 七线 patch-diff 归一化比对 + 匿名 API 状态/check-runs。§四「无生产消费者」由本仓库全树 new SelectionGeometry( 与 scaling( grep 得出;若接入点在 AnvilCraft(另一仓库),该判断需相应调整——请作者确认预期接入方。
为 cube 选择几何增加每格坐标单位参数,使放大后的薄层几何按实际尺寸隐藏微小接缝。保留原有默认调用方式,并同步换算投影距离容差。
已通过本版本 cube 模块测试和 JAR 构建,覆盖严格阈值、模型浮点边界、相机变换与部分线段保留。