Files
zijunchiang 5581cbe05d feat(scene): 场景选择与物理落地 + 整包发布(T-WIN-012/013/014)
T-WIN-013:API 升级与场景选择
- 契约快照同步到 rest-api 0.5.0 / data-models 0.7.0 / database 0.4.0
- catalog_types.gd 新增 SceneConfig(物理/环境/出生点/相机)与 Scene;
  CatalogBundle 增加 scenes[];from_dict 按契约 7.1 再收敛一次
  (缺项默认、越界夹紧、非法枚举回退),与服务端 normalizeSceneConfig 同规则
- 新增 src/scene/scene_runtime.gd:GLB 载入 -> 碰撞体(mesh 三角网 /
  auto 命名约定 *_col、*_colonly / none 不兜底)-> 场景级重力(Area3D
  SPACE_OVERRIDE_REPLACE,不改全局 ProjectSettings)-> 风(每物理帧
  apply_central_force,阵风正弦叠加,支持 local 坐标系)-> 环境光与雾
  -> 出生点与相机(follow/fixed/orbit);无碰撞体时兜底地面
- CatalogStore 增加 scenes/default_scene/find_scene/ensure_scene_cached/
  fetch_thumbnail(场景缓存带 sha256 指纹,避免换包后仍用旧 GLB)
- 主界面改为 2x2 四个选择器(曲目/动作/模型/场景)+ 场景参数面板
  (缩略图 + 重力/摩擦/弹性/碰撞体/风摘要)
- 游戏界面载入场景并落地物理,角色落在出生点;场景缺失/下载失败/
  解析失败一律回退内置空场景并提示,不阻塞开始跟练

T-WIN-012:「关于」清单展示当前版本号
- 版本唯一来源为 project.godot 的 application/config/version(v0.2.0)
- about_manifest() 输出版本/引擎/契约/协议/地址/隐私清单;
  无头测试无 autoload,读取 AppConfig 走 get_node_or_null 容错
- Credits 的单个 CONTRACT_VERSION 常量改为 CONTRACT_VERSIONS 字典
  (六项契约各自独立递增),并双向核对 contracts/VERSION

T-WIN-014:发布必须是单个完整包
- build/package-release.sh 重写:只产出单个 zip + SHA256SUMS,
  清理历史 .partN,超限时告警而非回退分卷;新增源产物与解压后完整性
  自检(PE 头 MZ / pck 魔数 GDPC / exe+pck 同目录同名)与体积-上限对比
- deploy/proxy 相关的 Gitea IIS 256MB 上限说明见 opendance-web

测试:tests/test_scene_config.gd(12 例)+ tests/test_about.gd(4 例);
无头测试 687 通过 / 0 失败(10 个套件),verify.sh 全部通过
2026-09-17 00:45:23 +08:00

88 lines
3.4 KiB
GDScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
extends TestCase
## T-WIN-010:开源声明一致性与完整性
const Credits = preload("res://src/ui/credits.gd")
## 文档 §8.2 模板中的最低 10 项
const REQUIRED_NAMES := [
"MediaPipe", "Three.js", "@pixiv/three-vrm", "Assimp", "Godot Engine",
"godot-vrm", "NestJS", "TypeORM", "OkHttp", "bvh",
]
func test_credits_cover_documented_minimum_set() -> void:
var names: Array = []
for entry in Credits.ENTRIES:
names.append(str(entry["name"]))
for required in REQUIRED_NAMES:
ok(names.has(required), "文档要求的开源项目「%s」已声明" % required)
ok(Credits.entry_count() >= 10, "声明条目不少于文档要求的 10 项", "实际 %d" % Credits.entry_count())
func test_every_entry_has_license_and_source_link() -> void:
for entry in Credits.ENTRIES:
var name := str(entry["name"])
ne(str(entry["license"]), "", "%s 有许可证" % name)
var url := str(entry["url"])
ok(url.begins_with("https://"), "%s 的源链接为 https" % name, url)
ne(str(entry["usage"]), "", "%s 注明了用途" % name)
func test_known_licenses_are_correct() -> void:
var expected := {
"MediaPipe": "Apache License 2.0",
"Godot Engine": "MIT",
"Assimp": "BSD-3-Clause",
"OkHttp": "Apache License 2.0",
"bvh": "MIT",
}
for entry in Credits.ENTRIES:
var name := str(entry["name"])
if expected.has(name):
eq(str(entry["license"]), expected[name], "%s 的许可证正确" % name)
func test_bbcode_contains_all_entries_and_no_smpl() -> void:
var text := Credits.to_bbcode()
for entry in Credits.ENTRIES:
contains(text, str(entry["name"]), "BBCode 含 %s" % str(entry["name"]))
contains(text, str(entry["url"]), "BBCode 含 %s 的链接" % str(entry["name"]))
contains(text, "SMPL", "BBCode 明确声明未使用 SMPL")
contains(text, "第三方开源项目声明", "BBCode 含声明标题")
for key in Credits.CONTRACT_VERSIONS:
contains(text, "%s v%s" % [key, Credits.CONTRACT_VERSIONS[key]], "BBCode 含 %s 契约版本" % key)
func test_plain_text_export_is_parseable() -> void:
var text := Credits.to_plain_text()
var lines := text.split("\n")
eq(lines.size(), Credits.entry_count(), "纯文本导出行数等于条目数")
for line in lines:
var parts := line.split(" | ")
eq(parts.size(), 3, "每行三段:名称 | 许可证 | 链接")
func test_contract_versions_match_snapshot() -> void:
# contracts/VERSION 是唯一来源;本端 README/关于页/THIRD_PARTY 都必须与之一致
var file := FileAccess.open("res://contracts/VERSION", FileAccess.READ)
if file == null:
ok(false, "无法读取 contracts/VERSION 快照")
return
var content := file.get_as_text()
file.close()
# 六项各自独立递增,逐项核对(不能用单个常量)
for key in Credits.CONTRACT_VERSIONS:
contains(content, "%s: %s" % [key, Credits.CONTRACT_VERSIONS[key]], "契约快照 %s 版本一致" % key)
# 反向核对:快照里的每一项都必须在代码里有对应常量,避免新增契约漏同步
for line in content.split("\n"):
var trimmed := line.strip_edges()
if trimmed == "" or trimmed.begins_with("#"):
continue
var parts := trimmed.split(":")
eq(parts.size(), 2, "VERSION 行格式为 name: version(%s)" % trimmed)
if parts.size() == 2:
var name := parts[0].strip_edges()
var version := parts[1].strip_edges()
eq(Credits.version_of(name), version, "契约快照新增项 %s 已同步到 Credits" % name)