================================================================
OpenDance Studio -- Windows 客户端 v0.2.0  使用说明
================================================================

摄像头跳舞评分系统的核心体验端：接收 Android 辅助 App 通过 WebSocket
推送的 33 点骨骼关键点，驱动 VRM 角色，并与 Web 服务端下发的参考动作
做实时 DTW 评分。

本客户端只接收关键点坐标，不接收、不存储任何视频画面。

--
一、快速开始
--

1. 解压后得到：
     OpenDance.exe       主程序
     OpenDance.pck       资源包（必须与 exe 同目录）
     README.txt          本文件
     README.md           同内容 Markdown 版
     THIRD_PARTY.md      开源声明
     contracts/          契约快照（只读；客户端不直连数据库）

2. 先启动 Web 管理服务端（opendance-web），确保能访问其 API。

3. 双击 OpenDance.exe 启动。

4. 在主界面确认「服务端地址」（默认 http://127.0.0.1:3000），
   点击「保存并测试」；顶部应显示「服务端正常 | DB...」。

5. 点击「刷新目录」，左侧会出现已发布的曲目、动作、模型与场景。

6. 在 Android 手机上启动「OpenDance 辅助 App」，填入本机显示在
   主界面上的接收地址（形如 ws://<本机局域网地址>:8765/pose）并连接。
   连接成功后主界面会提示「已连接 N 台设备」。

7. 依次选择曲目 -> 动作 -> 模型 -> 场景，点击「开始跟练」。
   场景可以留空不选：服务端没有可用场景时会自动回退到内置空场景，
   界面会提示但不影响开始跟练。

--
二、初次部署（从零跑起来）
--

本节面向第一次拿到源码、要从零把客户端跑起来的人；只运行已打包好的
OpenDance.exe 的用户看第一节即可。

1. 前置条件

   - 操作系统：Windows 10/11(x86_64)。开发与导出可在 Windows 或 Linux。
   - Godot 4.7.x 标准版（GDScript）。不需要 .NET / C# 版。
   - 渲染后端为 GL Compatibility，运行需 OpenGL 3.3 级别的显卡与驱动。
   - 导出模板：仅打包导出时需要，必须与编辑器完全同版本。
   - 磁盘：编辑器 + 导出模板数百 MB；导出产物 exe 约 104 MB + pck 约 107 KB。
   - 网络：能访问 Web 服务端 API（默认 TCP 3000）；与手机同一局域网，
     并放行本端 TCP 8765 入站。

2. 获取代码

   git clone https://gitea.kasugano.cn/zijunchiang/opendance-windows
   cd opendance-windows

3. 编辑器内首次运行

   - Godot 项目管理器 -> 导入 -> 选择 project.godot。
   - 首次导入会执行资源导入（生成 .godot/），可能等待数十秒到数分钟；
     不要在导入中途关闭编辑器。
   - 主场景已配置为 res://scenes/main.tscn，按 F5 运行。
   - 首次运行会生成：
       %APPDATA%\Godot\app_userdata\OpenDance Studio\opendance.cfg
       %APPDATA%\Godot\app_userdata\OpenDance Studio\logs\godot.log

4. 配置服务端地址

   主界面顶部「服务端地址」填好后点「保存并测试」，配置字段名为 api_base_url:

     http://<服务器地址>:3000      <- 你们自己部署的 Web 服务端地址(不是被脱敏的域名)
     http://192.0.2.10:3000

   注意：客户端只访问 API 端口（默认 3000）；管理端页面在管理端口
   （默认 3001），客户端不使用。保存后点「刷新目录」。

5. 与另两端的联通

   - Android 辅助 App -> 本端 WebSocket：本端是服务端，默认监听
     0.0.0.0:8765，路径 /pose，子协议 opendance.pose.v1。Android 端填写
     本端主界面显示的「接收地址」，形如 ws://<本机局域网地址>:8765/pose。
     本端可在 opendance.cfg 改 listen_host / listen_port / ws_subprotocol,
     改后点「重新连接接收服务」生效。
   - Web 服务端：需先在服务端发布曲目 / 动作 / 模型，动作还须完成关键点
     预处理，客户端才有可选内容。

6. 打包导出

   # Linux（推荐）
   GODOT_BIN=/path/to/godot bash build/export-windows.sh release

   # Windows（兜底）
   powershell -ExecutionPolicy Bypass -File build\export-windows.ps1

   产物在 build/windows/: OpenDance.exe（约 104 MB, PE 头 MZ 校验通过）
   + OpenDance.pck（约 107 KB，必须与 exe 同目录）；可能附带
   OpenDance.console.exe。

   打成发布包：

     bash build/package-release.sh 0.2.0

   得到 dist-release/ 下两个资产：

     opendance-windows-v0.2.0.zip     <- 单个完整包，禁止 .partN 分卷
     SHA256SUMS                       <- 裸文件名，可直接 sha256sum -c

   包里含 OpenDance.exe、OpenDance.pck、THIRD_PARTY.md、README.txt、
   README.md、contracts/。打包脚本会解压自检（exe + pck 必须同目录、
   exe 的 PE 头为 MZ、pck 魔数为 GDPC）并打印包体与上传上限的对比。

   注意：本项目 Gitea 前置 IIS 的默认上传上限是 30,000,000 字节
   （约 28.6 MiB），超过会返回 HTTP 413。这时不要改成分卷，
   请让运维放宽上限（做法见 opendance-web/deploy/proxy/README.md）。

7. 自检清单

   1) 一键验证：GODOT_BIN=/path/to/godot bash build/verify.sh
      预期末行「验证全部通过」。
   2) 无头测试：$GODOT --headless --path . --script res://tests/run_tests.gd
      预期「== 结果：687 通过 / 0 失败 ==」与「全部通过」（缺 VRM 素材或
      服务端不可达时相关用例跳过，数字会减少）。
   3) 启动冒烟：$GODOT --headless --path . --quit-after 180
      预期无 SCRIPT ERROR / ERROR:，退出码 0。
   4) 日志：%APPDATA%\Godot\app_userdata\OpenDance Studio\logs\godot.log
      预期无 SCRIPT ERROR。
   5) 服务端联通：主界面点「保存并测试」后顶部显示「服务端正常 | DB ...」。

8. 部署相关常见问题

   Q: 模型加载失败：缺少骨骼
   A: 模型无 Skeleton3D，或骨骼命名不在映射表内；换用标准 VRM(VRoid
      Studio 导出）。人形覆盖率低于 60% 会提示「骨骼覆盖偏低」。

   Q: 连不上服务端 / 显示「服务端不可达」
   A: 确认 Web 服务端已启动，api_base_url 指向 http://<服务器地址>:3000
      （不要填管理端口 3001）；访问 http://<服务器地址>:3000/health 应返回 200。

   Q: 导出失败：未找到导出模板
   A: 安装与编辑器同版本的 export templates。Linux 放
      ~/.local/share/godot/export_templates/<版本>.stable/;
      Windows 放 %APPDATA%\Godot\export_templates\<版本>.stable\。

   Q: 接收服务启动失败（端口 8765 可能被占用）
   A: 改 opendance.cfg 的 listen_port 后点「重新连接接收服务」，
      并同步修改 Android 端填写的接收地址。

--
三、界面说明
--

主界面
  - 四个选择器（2x2 栅格）：曲目 / 动作（仅列出已完成预处理的动作）/
    模型（VRM 优先）/ 场景（GLB + 物理参数）
  - 服务端地址：可修改并即时测试
  - 接收地址：Android 端要连接的 WebSocket 地址
  - 「刷新目录」重新拉取已发布资源（含场景）
  - 底部左侧展示所选动作的来源信息（来源类型、名称、作者、许可、链接）
  - 底部中间展示所选场景的缩略图与物理参数摘要
    （重力 / 摩擦 / 弹性 / 碰撞体来源 / 风）；未选场景时说明将使用内置空场景

游戏界面
  - 左侧 3D 视图：VRM 角色落在场景出生点并跟随关键点实时动作，
    相机按场景配置取景（follow 跟随 / fixed 固定 / orbit 环绕）
  - 场景物理在本端落地：重力（Area3D 覆盖，不改全局 ProjectSettings）、
    风（每物理帧施加风力，阵风按正弦叠加）、地面摩擦与弹性、
    GLB 碰撞体（mesh 三角网 / auto 命名约定 *_col、*_colonly）、环境光与雾
  - 右侧 HUD：实时得分、等级、连击、动作进度、连接状态、来源信息、场景参数

结算界面
  - 等级（S/A/B/C/D）、平均分与最终分、动作完成度、最高单帧、最长连击
  - 「再来一次」/「返回主菜单」/「开源声明」

关于页面
  - 「清单」逐行显示：客户端版本（vX.Y.Z）/ 运行引擎 / 契约版本 /
    接收协议 / 接收地址 / 服务端地址 / 隐私说明
  - 版本号唯一来源是 project.godot 的 application/config/version，与
    project.yaml、导出产物名、Git tag、界面展示完全一致
  - 完整可滚动的第三方开源项目声明

--
四、配置文件
--

首次运行会在以下位置生成配置文件，可直接用文本编辑器修改：

  Windows: %APPDATA%\Godot\app_userdata\OpenDance Studio\opendance.cfg

可配置项：

  api_base_url      Web 服务端地址(默认 http://127.0.0.1:3000)
  listen_host       WebSocket 监听地址(默认 0.0.0.0)
  listen_port       WebSocket 监听端口(默认 8765)
  ws_subprotocol    子协议(默认 opendance.pose.v1)
  dtw_band          DTW 带宽，单位帧（默认 15 ~ 0.5 秒抖动容忍）
  score_tolerance   评分容差：平均每步代价达到该值即 0 分(默认 0.25)
  mirror_preview    镜像预览

--
五、防火墙与网络
--

本客户端需要接受 Android 设备的入站连接：

  - Windows 防火墙需放行 OpenDance.exe 的 **TCP 8765** 入站
  - 手机与电脑需在同一局域网
  - 手机端填写主界面显示的「接收地址」

若端口被占用，可修改 opendance.cfg 中的 listen_port 后重启。

--
六、评分说明
--

- 每帧特征 = 33 点 x (x,y,z) + 9 个关节角余弦 = 108 维
  （与 Web 服务端预处理产物、Android 端推流结构完全一致）
- 置信度低于 0.5 的关键点不参与代价计算，避免遮挡导致误判
- 采用带约束 DTW(|i-j| <= band)对齐，能吸收一定的节奏快慢差异
- 得分 = clamp(1 - 平均代价 / 容差, 0, 1) x 100，并做指数平滑
- 等级：S >= 95, A >= 85, B >= 70, C >= 55, D 其余

--
七、从源码构建
--

前置：Godot 4.7.x + 对应版本的 export templates

  # Linux 上直接导出 Windows 可执行文件（推荐）
  GODOT_BIN=/path/to/godot bash build/export-windows.sh release

  # Windows 上兜底导出
  powershell -ExecutionPolicy Bypass -File build\export-windows.ps1

产物位于 build/windows/: OpenDance.exe + OpenDance.pck
（脚本会校验产物存在且为合法 PE 文件）

运行测试：

  GODOT=/path/to/godot
  $GODOT --headless --path. --import
  $GODOT --headless --path. --script res://tests/run_tests.gd
  $GODOT --headless --path. --quit-after 180

--
八、目录结构
--

  project.godot            工程配置（autoload / 渲染 / 窗口）
  export_presets.cfg       导出预设（必须在项目根目录）
  project.yaml             任务清单与状态
  DSH.md                   本项目 DSH 执行约束
  tasks/                   单任务说明书(T-WIN-001 ~ 015)
  contracts/               只读契约快照(来源 opendance-web；六项契约各自独立版本)
  scenes/main.tscn         根节点
  src/autoload/            AppConfig / CatalogStore / PoseReceiver / ScoreService
  src/net/                 239 字节编解码、WebSocket 服务、REST 客户端
  src/model/               VRM 加载、humanoid 骨骼映射
  src/anim/                关键点 -> 骨骼重定向
  src/scene/               场景实例化与物理落地(重力/风/碰撞/环境/机位)
  src/score/               特征提取、DTW、评分规则
  src/ui/                  主界面 / 游戏界面 / 结算 / 关于 / 来源展示 / 场景参数
  tests/                   无头测试框架与用例
  build/                   导出脚本

--
九、常见问题
--

Q: 主界面显示「服务端不可达」
A: 检查 Web 服务端是否已启动，以及「服务端地址」是否正确（含端口）。

Q: 目录里没有可用的动作
A: 动作必须先在管理端完成「预处理」（BVH -> 关键点序列）并「审核通过」，
   才会出现在客户端。

Q: 模型加载失败 / 动作不完整
A: 游戏界面会显示「人形覆盖率」。低于 60% 说明模型的骨骼命名不被识别，
   请换用标准 VRM(VRoid Studio 导出)模型。

Q: 连上了手机但分数一直是 0
A: 确认手机端已开始推流；主界面的「查看接收状态」会显示累计帧数与丢帧数。

Q: 手机端反复重连 / 「已连接」数忽大忽小
A: 本端有 15 秒静默超时（契约 v0.2.0 1.1），并在 welcome/config 里声明
   silentTimeoutMs=15000 与 heartbeatIntervalMs=5000；Android 端会按后者发
   应用层 ping。若仍频繁断开，用「查看接收状态」看每台设备的状态与断开原因
   （close code）：1001 表示本端主动踢人或服务重启，0/1006 表示网络抖动。
   同一设备的重复连接会按 deviceId 去重（旧连接以 1000 关闭，对端不重连），
   所以「已连接 N 台」显示的是去重后的设备数，不是连接数。

Q: 选场景时提示「场景缺少 GLB 文件」或「已回退内置空场景」
A: 服务端该场景没有可下载的 GLB（转换失败或未发布）。这不影响开始跟练，
   会使用内置空场景与默认物理参数；请让管理员在管理端「场景管理」重新上传。

Q: 场景里的角色一直往下掉
A: 场景没有可用碰撞体且配置为 colliders=auto/mesh。本端会自动生成兜底地面
   （日志会记录「已生成兜底地面」）；若场景显式配置 colliders=none，则按场景
   作者意图不生成任何碰撞体，此时角色不会被地面接住。

Q: 关于页面的开源声明
A: 与 THIRD_PARTY.md、contracts/open-source-credits.md 三处保持一致。

--
十、许可
--

本客户端代码以 MIT 许可发布。第三方开源项目声明见 THIRD_PARTY.md。
未使用 SMPL 模型及其衍生拓扑，统一采用 MediaPipe 33 点拓扑。
