fix(scene): 包围盒沿树累乘变换(修掉入树前的 ERROR 与范围偏位)+ 21 项"真机等价"测试

缺陷:SceneRuntime._compute_aabb() 用 MeshInstance3D.global_transform 计算包围盒,
而它在 _assemble() 里调用 —— 那时运行时节点**还没入树**。两个后果:
- Godot 打一行 `ERROR: Condition "!is_inside_tree()" is true. Returning: Transform3D()`
  (真机每次载入场景都刷一条,与"日志里不应有 ERROR"的排查约定冲突);
- 树外的 global_transform 返回单位变换,算出来的只是各网格的**局部** AABB,
  于是重力/风 Area3D 的碰撞盒与兜底地面会偏小或偏位 —— 对把网格摆在非原点位置的
  场景(导出 GLB 的常见情况)**风力可能作用不到物体上**。

修复:改为从根往下累乘 `Node3D.transform`,不依赖是否入树;挂在单位变换父节点下时
结果与旧语义一致。

新增 21 项无头"真机等价"测试(不需要设备):
- tests/test_scene_config.gd:在代码里手写合法 GLB(三角形 + BIN chunk)落盘后
  **真实加载**:warnings 为空、按 colliders 三种取值分别核对碰撞体(mesh / auto 命中
  *_col / auto 未命中的兜底地面 / none)、重力 Area3D 的 gravity 与方向、
  SPACE_OVERRIDE_REPLACE、风力与 WIND_FORCE_SCALE 对齐,以及**带位移网格**
  (translation [10,0,0])时重力区域与兜底地面都跟着位移(该缺陷的回归测试);
- tests/test_pose_server.gd:**时间维度**验证保活 —— 只发应用层 ping、不发关键点帧的
  客户端在 17 秒(> 15 秒静默超时)后仍保持连接("画面里没人就掉线、疯狂重连"的根因
  对照),而完全不发数据的客户端被 close(1001) 断开。

新增 build/check-version.sh:强制 project.godot 的 application/config/version
(「关于」清单与 .pck 的来源)与 project.yaml、发布版本号三者一致;已接入
build/package-release.sh(打包前)与 build/verify.sh(第 0/4 步),并做过反向验证。
此前没有任何机制保证这两个文件同步 —— 界面显示的版本可能和产物名不一致。

版本升至 0.2.1(project.godot / project.yaml / README / 产物名 / tag 全部一致),
About 清单与 .pck 内版本号均为 0.2.1(已用 strings 核对)。

验证:build/verify.sh 四步全通过(版本一致性 → 编译 → 751 项断言 → 180 帧启动无错误);
产物 opendance-windows-v0.2.1.zip(LZMA,26,627,191 B)
sha256 d49885327047f5a52de6c732431ea080cd1a030ae1c581a8bc0ec0d99bfb792c。
This commit is contained in:
2026-09-17 03:59:29 +08:00
parent 86e5decd10
commit 14ee5f7ec9
11 changed files with 456 additions and 22 deletions
+29 -7
View File
@@ -14,7 +14,7 @@ OpenDance Studio **阶段二**: Windows 客户端(Godot 4)。
| 验收项 | 结果 |
|--|--|
| 脚本编译 | OK 全部通过(无 SCRIPT ERROR) |
| 无头测试 | OK **687 项全部通过**(10 个测试套件) |
| 无头测试 | OK **751 项全部通过**(10 个测试套件) |
| 应用启动 | OK 180 帧无运行时错误 |
| Windows 导出 | OK 生成 `OpenDance.exe`(104 MB, PE 头校验通过)+ `OpenDance.pck` |
| 真实 VRM 验证 | OK 154 骨骼 VRoid 模型,humanoid 覆盖率 **100%** |
@@ -22,8 +22,30 @@ OpenDance Studio **阶段二**: Windows 客户端(Godot 4)。
| 跨实现交叉校验 | OK 关节角与 Web 服务端 TypeScript 实现**逐帧一致** |
| 场景选择与物理落地 | OK `scenes[]` 可选、重力/风/摩擦/碰撞体落地并可日志核对 |
| 连接保活与设备去重 | OK welcome/config 声明静默超时与心跳;应用层 ping/pong;按 deviceId 去重 |
| 发布整包 | OK 单个 `opendance-windows-v0.2.0.zip` + `SHA256SUMS`(不拆分卷) |
| 发布整包 | OK 单个 `opendance-windows-v0.2.1.zip` + `SHA256SUMS`(不拆分卷) |
| 版本号展示 | OK 「关于」清单显示 `v0.2.0`,来源唯一(`project.godot`) |
| 场景物理与保活 | OK 新增真实 GLB 端到端用例 + 17 秒保活对照用例(751 项断言全过) |
## v0.2.1 修订(两处修复 + 一批"真机等价"测试)
1. **场景包围盒不再用 `global_transform`**:`SceneRuntime._compute_aabb()` 原本在
`_assemble()` 里调用,而那时运行时节点**还没入树** —— Godot 会打一行
`ERROR: Condition "!is_inside_tree()" is true`,并且算出来的只是各网格的
**局部** AABB。后果:把网格摆在非原点位置的场景,重力/风区域与兜底地面会算得
偏小或偏位(**风力可能作用不到物体上**)。现改为沿树累乘 `Node3D.transform`,
与是否入树无关,结果与运行时挂在单位变换父节点下完全一致;
2. **新增 21 项"真机等价"测试**(无头即可跑,不需要设备):
* `tests/test_scene_config.gd`:在代码里手写合法 GLB(三角形 + BIN chunk)后
**真实加载**,核对三种 `colliders` 取值的碰撞体、重力/风 Area3D 数值、
以及**带位移网格**的包围盒是否跟着走(这一条正是上述缺陷的回归测试);
* `tests/test_pose_server.gd`:**时间维度**验证保活 —— 一个只发应用层 `ping`、
不发关键点帧的客户端在 17 秒(> 15 秒静默超时)后**仍保持连接**,
而完全不发数据的客户端被 `close(1001)` 断开。这正是"画面里没人就掉线、
然后疯狂重连"的根因对照;
3. **新增版本号一致性校验** `build/check-version.sh`:强制
`project.godot` 的 `application/config/version`(「关于」清单与 .pck 的来源)
与 `project.yaml`、发布版本号三者一致;已接入 `build/package-release.sh`
(打包前)与 `build/verify.sh`(0/4 步),并做过反向验证。
## 快速开始
@@ -35,10 +57,10 @@ GODOT_BIN=/path/to/godot bash build/verify.sh
GODOT_BIN=/path/to/godot bash build/export-windows.sh release
# 打包发布产物(单个完整 zip + SHA256SUMS)
bash build/package-release.sh 0.2.0
bash build/package-release.sh 0.2.1
```
当前版本:**v0.2.0**(`project.godot` 的 `application/config/version`,
当前版本:**v0.2.1**(`project.godot` 的 `application/config/version`,
与 `project.yaml`、导出产物名、Git tag、「关于」清单展示一致)。
详细使用说明见 [`README.txt`](README.txt),工程约束见 [`DSH.md`](DSH.md)。
@@ -120,7 +142,7 @@ GODOT_BIN=/path/to/godot bash build/export-windows.sh release
powershell -ExecutionPolicy Bypass -File build\export-windows.ps1
# 打成可分发的 zip(单个完整包 + SHA256SUMS)
bash build/package-release.sh 0.2.0
bash build/package-release.sh 0.2.1
```
| 产物 | 位置 | 说明 |
@@ -128,7 +150,7 @@ bash build/package-release.sh 0.2.0
| `OpenDance.exe` | `build/windows/` | 主程序,约 104 MB;脚本校验前 2 字节为 `MZ`(合法 PE) |
| `OpenDance.pck` | `build/windows/` | 资源包,约 107 KB; **必须与 exe 同目录** |
| `OpenDance.console.exe` | `build/windows/` | 控制台包装器,可能生成,非必需 |
| `opendance-windows-v0.2.0.zip` | `dist-release/` | 发布包:exe + pck + `THIRD_PARTY.md` + `README.txt` + `README.md` + `contracts/` |
| `opendance-windows-v0.2.1.zip` | `dist-release/` | 发布包:exe + pck + `THIRD_PARTY.md` + `README.txt` + `README.md` + `contracts/` |
| `SHA256SUMS` | `dist-release/` | 裸文件名,与 zip 同目录时可 `sha256sum -c SHA256SUMS` 直接校验 |
导出前必须安装与编辑器同版本的 export templates,否则脚本会报「未找到导出模板」。
@@ -230,7 +252,7 @@ src/
**代价:Windows 10 的资源管理器不支持 LZMA(method 14) 的 zip,必须用
7-Zip / WinRAR / PeaZip 解压**(Win11 24H2+ 起资源管理器原生支持 7z 等格式,
但本项目未在 Windows 上实测)。若 IIS 上限已放开,请改用默认的 deflate 包
(`bash build/package-release.sh 0.2.0`,产物约 38 MB,双击即可解压)。
(`bash build/package-release.sh 0.2.1`,产物约 38 MB,双击即可解压)。
## 第三方开源声明