# 导出与部署契约

## 导出入口

UI：“导出剧情”→“客户端剧情包”→勾“客户端包包含引用的媒体”→生成并下载。CLI 在编辑器安装目录运行：

```sh
python studio.py --workspace "REPO_PATH" validate "PROJECT_ID"
python studio.py --workspace "REPO_PATH" export "PROJECT_ID" --kind runtime
```

输出包括 absolutePath；此可选 CLI 的结果保存在本机仓库 `.studio/exports/`；0.4 浏览器导出直接下载 / 写入所选 ZIP，服务器不留存。`--config-only` 只生成配置，已有媒体必须真实存在，不能用于首次全量交付。`--kind project` 导出一个章节的可编辑目录，不自动捆绑其他章节源工程。

源码 `src/repository.py` 的 dependencies/export 是当前权威：依赖按 jumpNodes 的跨章引用递归收集，同名变量定义不一致、缺失素材、无入口或缺失跳转点会阻止 runtime 导出。

## 输出路径

| 内容 | ZIP 内路径 |
| --- | --- |
| 清单 | manifest.json，format=story-studio/runtime-export，chapterIds、includeMedia、editorVersion |
| 局部章节列表 | StreamingAssets/GameProduceFiles/Configs/ChapterList.json |
| 各章配置 | StreamingAssets/GameProduceFiles/Configs/ChaptersData/<chapterId>.json |
| 合并变量数组 | StreamingAssets/GameProduceFiles/Configs/Variables/Variables.json |
| 普通媒体 | StreamingAssets/GameProduceFiles/EditoData/Chapters/<chapterId>/<guid>.<ext> |
| 封面 | StreamingAssets/GameProduceFiles/GameResources/stories/ChapterImages/ChapterThumbnails/<chapterId>_chapterthumbnails.<ext> |

保留 `EditoData` 拼写和小写 `stories`。工程内相同 GUID 同时用作封面和剧情图片时，导出把相关引用都映射到该规范封面路径，只输出一份。不要再手工补一份旧 GUID 路径当作正确修复。

当前客户端优先探测 PNG 封面，正式封面优先真正 PNG 文件。导出保留其他图片原编码和扩展名；只改后缀不是转码。`thumbnailPath` 和 `jsonFilePath` 以 `GameProduceFiles/...` 开头，运行时内容根路径另加一次。

## 全局配置合并

导出的 ChapterList 是 `{"chapters":[...]}`，仅包含本次依赖闭包。获取服务器完整版本，以 chapterId 为键更新明确发布的条目，追加新章，保留原列表排序及无关条目、顶层设置。对于同 ID 的已发布条目，保留原有未知字段并检查其意义；当前导出不带 packToLocal，不应为远程新章随意加 true。

Variables 导出为数组，以 name 去重。线上若使用对象包裹变量数组，保留实际结构；相同名称、不同定义是设计冲突，需确认默认值/范围及已有存档影响，不能简单选新值覆盖。

媒体引用静态验收时，配置相对路径 `R` 对应 ZIP `StreamingAssets/R`，服务器 `<内容根>/R`。含媒体包里实际文件必须存在且路径区分大小写。config-only 则报告依赖既有媒体的假设，并按已有环境验证。

## 当前站点背景（不是通用默认目标）

此前用户手工部署站点：`https://renzhe2.lp20.cn`。用户提供的内容根为 `/home/ubuntu/nginx/website/renzhe2/remote/StreamingAssets/`。URL 前缀为 `/StreamingAssets/`，URL 不需要包含文件系统中的 `remote`。

历史章 ID 为 `chapter-001-restore-test` 和 `memory-album`；新练习使用自己的实际 ID。这些信息仅帮助识别已知环境，不构成未来所有任务的上传授权，也不替代当前配置检查。

上传顺序通常是媒体→章节/变量→章节列表，保持其他文件；已有版本目录切换机制时可按环境统一切换。准备旧文件备份和回滚清单。若旧新版同路径媒体内容不同，逐文件覆盖会出现混合版本窗口，报告这一风险并采用环境支持的发布机制。

## 典型验证

- 章节可见需要新列表实际被读取，isHidden、isLocked、requiredChapterIds 等符合预期。前端缓存和 CDN 可保留旧文件。
- 404：核对完整 URL、大小写、章节 ID、扩展名、是否漏传媒体、StreamingAssets 是否重复一层。
- 200 不能播放：响应 Content-Type/内容是否真实媒体，文件是否完整，视频编码与 Range 服务是否兼容。
- 回忆锁定：奖励 key、登记 key、卡片条件及线上变量定义应一致；用户游戏存档和编辑器试走独立。
- 返回异常：必须从回忆录卡片进入回放来测返回来源；多段回放遵循上一视频链。
- 真广告、真实用户持久化没有测试时明确列为未测，不能凭模拟广告完成推断上线可用。
