Files
opendance-windows/build/package-release.sh
T
zijunchiang 14ee5f7ec9 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。
2026-09-17 03:59:29 +08:00

170 lines
7.6 KiB
Bash
Executable File
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.
#!/bin/bash
# ============================================================
# OpenDance Studio —— Windows 客户端发布打包(T-WIN-014)
#
# 产物(文档 §5.3 / §5.7):
# opendance-windows-vX.Y.Z.zip ← **单个完整包,禁止 .partN 分卷**
# SHA256SUMS ← 裸文件名,下载目录内 sha256sum -c 直接可用
#
# 包内结构:
# opendance-windows-vX.Y.Z/
# OpenDance.exe
# OpenDance.pck
# THIRD_PARTY.md
# README.txt README.md
# contracts/
#
# 为什么强调"单个完整包":本项目的 Gitea 前置 IIS 默认
# maxAllowedContentLength = 30,000,000 字节(≈28.6 MiB),
# 30.5 MB / 40 MB 的上传实测直接 HTTP 413。当时的应对是把整包拆成
# zip.part0/1/2(每卷 13 MiB)——这正是"分卷有问题"的根因:
# 用户拿到的是无法直接解压的碎片,还要自己拼接。
# 现在改为:整包上传;若超过上限则**直接报错退出**,并提示运维放宽
# IIS/ARR 上限(做法见 opendance-web/deploy/proxy/README.md),
# 绝不静默退回分卷。
#
# 用法:bash build/package-release.sh [版本号]
# ============================================================
set -euo pipefail
PROJECT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
cd "$PROJECT_DIR"
VERSION="${1:-$(sed -n 's/^version:[[:space:]]*//p' project.yaml | head -1)}"
VERSION="${VERSION:-0.2.0}"
NAME="opendance-windows-v${VERSION}"
OUT_DIR="$PROJECT_DIR/dist-release"
STAGE="$OUT_DIR/$NAME"
# Gitea 前置 IIS 的实测上传上限(文档 §5.7 实测结论)
UPLOAD_LIMIT_BYTES=30000000
log() { printf '\033[1;34m[package]\033[0m %s\n' "$*"; }
warn() { printf '\033[1;33m[warn]\033[0m %s\n' "$*" >&2; }
die() { printf '\033[1;31m[error]\033[0m %s\n' "$*" >&2; exit 1; }
# ---- 0. 版本号一致性(文档 §11.2:产物名 / tag / 界面展示必须一致)----
bash "$PROJECT_DIR/build/check-version.sh" "$VERSION" || die "版本一致性校验失败,先统一 project.godot / project.yaml / 发布版本号"
EXE="$PROJECT_DIR/build/windows/OpenDance.exe"
PCK="$PROJECT_DIR/build/windows/OpenDance.pck"
[ -f "$EXE" ] || die "未找到 $EXE,请先执行 bash build/export-windows.sh release"
[ -f "$PCK" ] || die "未找到 $PCK,请先执行 bash build/export-windows.sh release"
# ---- 1. 源产物自检:PE 头 + pck 魔数 ----
MAGIC=$(head -c 2 "$EXE" | od -An -tx1 | tr -d ' \n')
[ "$MAGIC" = "4d5a" ] || die "$EXE 不是合法的 Windows PE 文件(头 $MAGIC)"
PCK_MAGIC=$(head -c 4 "$PCK" | tr -d '\0')
[ "$PCK_MAGIC" = "GDPC" ] || die "$PCK 不是合法的 Godot 资源包(头 '$PCK_MAGIC')"
log "源产物校验通过:exe PE 头 MZ | pck 头 GDPC"
# ---- 2. 整理产物 ----
log "整理产物到 $STAGE …"
rm -rf "$STAGE"
mkdir -p "$STAGE"
cp "$EXE" "$STAGE/OpenDance.exe"
cp "$PCK" "$STAGE/OpenDance.pck"
cp THIRD_PARTY.md README.txt "$STAGE/"
if [ -f README.md ]; then cp README.md "$STAGE/"; fi
cp -r contracts "$STAGE/contracts"
# ---- 3. 打包(单个完整包) ----
ZIP="$OUT_DIR/$NAME.zip"
# 清理历史分卷,避免 old .partN 被误当成本次产物上传
rm -f "$OUT_DIR/$NAME.zip".part* "$OUT_DIR/$NAME.zip" "$OUT_DIR/SHA256SUMS"*
# 压缩方式:默认 deflate(Windows 资源管理器可直接解压)。
# ZIP_METHOD=lzma 时改用 LZMA —— 包体从约 38 MB 降到约 26 MB,可绕过
# 「Gitea 站点 IIS 的 maxAllowedContentLength = 30,000,000 字节」这道闸
# (见 opendance-web/deploy/proxy/README.md 第九节)。
# **代价**:Windows 10 的资源管理器不支持 LZMA(method 14) 的 zip,用户必须用
# 7-Zip / WinRAR / PeaZip 解压(Win11 24H2+ 起资源管理器原生支持 7z/zip 变体,
# 但本项目未在 Windows 上实测)。因此只有在 IIS 上限确实无法放开时才用 LZMA。
ZIP_METHOD="${ZIP_METHOD:-deflate}"
log "生成单个完整包 $NAME.zip(压缩方式:$ZIP_METHOD)…"
case "$ZIP_METHOD" in
deflate)
( cd "$OUT_DIR" && zip -qr "$NAME.zip" "$NAME" )
;;
lzma)
command -v 7z >/dev/null 2>&1 || die "ZIP_METHOD=lzma 需要 7z(Debian/Ubuntu: apt install p7zip-full)"
( cd "$OUT_DIR" && rm -f "$NAME.zip" && 7z a -tzip -mm=LZMA -mx=9 "$NAME.zip" "$NAME" >/dev/null )
;;
*)
die "未知 ZIP_METHOD=$ZIP_METHOD(可选:deflate / lzma)"
;;
esac
# LZMA 包额外做一次完整性测试与解压自检(zip/unzip 对 method 14 支持不一致)
if [ "$ZIP_METHOD" = "lzma" ]; then
7z t "$ZIP" >/dev/null || die "LZMA 包完整性测试失败(7z t)"
log "LZMA 包完整性测试通过(7z t)"
fi
# ---- 4. 完整性自检:解压后必须含 exe + pck(同目录)且 exe 仍是合法 PE ----
CHECK_DIR=$(mktemp -d)
trap 'rm -rf "$CHECK_DIR"' EXIT
if [ "$ZIP_METHOD" = "lzma" ]; then
7z x -y -o"$CHECK_DIR" "$ZIP" >/dev/null
else
unzip -q "$ZIP" -d "$CHECK_DIR"
fi
[ -f "$CHECK_DIR/$NAME/OpenDance.exe" ] || die "包内缺少 OpenDance.exe"
[ -f "$CHECK_DIR/$NAME/OpenDance.pck" ] || die "包内缺少 OpenDance.pck(必须与 exe 同目录)"
[ -f "$CHECK_DIR/$NAME/README.txt" ] || die "包内缺少 README.txt"
[ -f "$CHECK_DIR/$NAME/THIRD_PARTY.md" ] || die "包内缺少 THIRD_PARTY.md"
[ -d "$CHECK_DIR/$NAME/contracts" ] || die "包内缺少 contracts/ 契约快照"
CHECK_MAGIC=$(head -c 2 "$CHECK_DIR/$NAME/OpenDance.exe" | od -An -tx1 | tr -d ' \n')
[ "$CHECK_MAGIC" = "4d5a" ] || die "解压后的 OpenDance.exe 不是合法 PE 文件(头 $CHECK_MAGIC)"
CHECK_PCK=$(head -c 4 "$CHECK_DIR/$NAME/OpenDance.pck" | tr -d '\0')
[ "$CHECK_PCK" = "GDPC" ] || die "解压后的 OpenDance.pck 不是合法 Godot 资源包"
log "整包完整性自检通过(解压后 exe + pck 同目录,PE/GDPC 头均合法)"
# pck 与 exe 必须同名同目录,否则 Godot 找不到资源
[ "$(basename "$CHECK_DIR/$NAME/OpenDance.exe" .exe)" = "$(basename "$CHECK_DIR/$NAME/OpenDance.pck" .pck)" ] \
|| die "exe 与 pck 主文件名不一致,导出产物不可运行"
# ---- 5. SHA256SUMS(裸文件名,下载目录内可直接校验) ----
( cd "$OUT_DIR" && sha256sum "$NAME.zip" > SHA256SUMS )
log "已生成 $OUT_DIR/SHA256SUMS"
# ---- 6. 体积与上传上限对比 ----
SIZE_BYTES=$(stat -c %s "$ZIP")
SIZE_HUMAN=$(du -h "$ZIP" | cut -f1)
log "包体 $SIZE_HUMAN($SIZE_BYTES 字节)| Gitea/IIS 实测上限 $UPLOAD_LIMIT_BYTES 字节"
if [ "$SIZE_BYTES" -gt "$UPLOAD_LIMIT_BYTES" ]; then
warn "整包超过当前 Gitea 前置 IIS 的上传上限,上传会返回 HTTP 413。"
warn "请让运维放宽上限后重传(做法见 opendance-web/deploy/proxy/README.md):"
warn " IIS requestFiltering/requestLimits@maxAllowedContentLength = 268435456"
warn " ARR maxRequestBytes >= 268435456"
warn " Gitea app.ini [attachment] MAX_SIZE >= 256MB"
warn " nginx(若前置)client_max_body_size 256m;"
warn "本脚本**不会**回退为 .partN 分卷——分卷包无法直接解压,是历史缺陷。"
warn "若暂时无法放开 IIS 上限,可用 ZIP_METHOD=lzma 重跑本脚本:包体约 26 MB 可绕过 30 MB 闸,"
warn "但 Windows 10 资源管理器不能直接解压 LZMA zip,必须用 7-Zip / WinRAR(README 中已注明)。"
else
log "低于上限,可直接作为 Release 资产上传。"
fi
echo ""
echo "产物:"
echo " $ZIP"
echo " $OUT_DIR/SHA256SUMS"
if ( cd "$OUT_DIR" && sha256sum -c SHA256SUMS --status ); then
echo " sha256 校验:OK"
else
die "sha256 自校验失败"
fi
echo ""
if [ "$ZIP_METHOD" = "lzma" ]; then
7z l "$ZIP" | tail -14
else
unzip -l "$ZIP" | sed -n '3,14p'
fi
echo ""
echo "分发:上传 $NAME.zip 与 SHA256SUMS 两个资产;用户下载后"
echo " sha256sum -c SHA256SUMS && unzip $NAME.zip 即可直接运行 OpenDance.exe。"