# 第三篇：导出、配置合并与手工部署

[教程总入口](../README.md) · 上一篇：[动作、奖励与回忆录](02-actions-and-memories.md)

本篇部署的是**游戏使用的客户端剧情包**，不是 STORY STUDIO 编辑器网站。0.4 编辑器发行包为纯静态网站；游戏剧情包则按已有内容服务目录上传。

## P01 从独立回忆录导出双章节包

1. 保存主线副本和独立回忆录，分别“检查剧情”，处理错误。
2. 当前切到 `tutorial-album`，点击“导出剧情”。
3. 选择“客户端剧情包”，勾“客户端包包含引用的媒体”，生成并下载。
4. 解压检查根目录 `manifest.json` 的 `chapterIds`，应包含 `tutorial-album` 和实际主线副本（例如 `tutorial-001-copy`）。

导出会递归收集**跨章跳转指向的依赖**，不是自动导出仓库所有章节。这里从回忆录导出，是因为回忆录跳转到主线；只从主线导出通常不会包含没有被主线引用的回忆录章。

如果不同章节定义了同名但默认值等内容不同的变量，导出会报冲突。先确定哪个定义正确，再统一；不要随手删掉其中一份来绕过错误。

**验收**：清单包含两个预期章节，媒体随包提供。建议回复：`双章节客户端包已导出`。

## P02 给两章设置封面并重新导出

1. 分别进入两个工程，导入正式 PNG 封面。练习可暂用已导入图片，正式上线应使用有意义的封面。
2. 左侧“当前章节”旁的 `•••` 打开“章节设置”。
3. 选择“章节封面”，核对章节 ID、显示名称、简介。
4. 为便于首次验收，关闭“初始锁定”和“隐藏章节”，清空不需要的前置章节；正式业务需求另行配置。
5. 保存两章，再从独立回忆录重新导出包含媒体的客户端包。

章节列表字段多少不能单独判断包是否正确。当前导出会补齐默认字段，如预览循环、静音、音量、分辨率、广告解锁等，并生成 `jsonFilePath`；应使用这次导出的实际条目，保留既有全局字段，避免手写几项旧配置代替新输出。

**验收**：两章 `thumbnailPath` 有值，包内各有对应封面文件。建议回复：`封面已设置并重新导出`。

## P03 理解包内目录，合并全局配置

典型目录（以实际 `manifest.json` 为准）：

```text
manifest.json
README.txt
StreamingAssets/
  GameProduceFiles/
    Configs/
      ChapterList.json
      ChaptersData/<chapterId>.json
      Variables/Variables.json
    EditoData/Chapters/<chapterId>/<素材GUID>.<扩展名>
    GameResources/stories/ChapterImages/ChapterThumbnails/
      <chapterId>_chapterthumbnails.png
```

`EditoData` 是现有协议路径的实际拼写，不要改成 EditorData；`stories` 必须小写。配置内资源路径通常从 `GameProduceFiles/...` 开始，客户端会加上 `StreamingAssets`，不要重复加两次。

先从服务器取得当前全量配置，备份到仓库外的交付目录，再在本地准备合并结果：

| 文件 | 合并方式 |
| --- | --- |
| ChapterList.json | 按 `chapters[]` 中的 `chapterId` 查找。新章追加；同 ID 仅更新本次明确发布的章节条目。保留其他章节、排序和全局设置；原条目的未知字段先保留并核对语义。 |
| Variables/Variables.json | 按变量 `name` 合并。导出为数组；若服务器采用外层对象，保留实际外层结构。已有同名变量定义相同则复用，不同则先确认设计后统一。 |
| ChaptersData/*.json | 使用本次导出的对应章节 JSON，保留其他章节文件。 |

本包 `ChapterList.json` 只列本章及依赖。**不能用这份局部列表直接覆盖线上全量列表**，否则其他章节会从列表消失。也不要直接用局部变量数组覆盖线上全部变量。

配置合并后检查：章节 ID 唯一、两章跳转目标存在、回忆跳转点存在、同名变量定义一致、每个媒体路径都有文件。仅改显示名称不会自动改章节 ID；发布后随意改 ID 会影响跨章引用和已有进度。

**验收**：已准备可审阅的完整合并文件，并能看到修改了哪些章节和变量。建议回复：`发布配置已合并`。

## P04 手工上传到现有站点

此前站点为 `https://renzhe2.lp20.cn`，用户提供的内容根目录为：

```text
/home/ubuntu/nginx/website/renzhe2/remote/StreamingAssets/
```

这只是当前站点的已知映射；部署到别处前先确认 Nginx 的真实内容根目录，不要把此路径当作所有服务器的固定值。

1. 保留线上旧配置与同路径旧媒体备份，准备可回滚版本。
2. 将包中 `StreamingAssets/` **内部内容**按相对目录合入服务器上述目录。避免产生 `StreamingAssets/StreamingAssets/`。
3. 先上传引用媒体，再上传对应章节 JSON 和合并后的变量配置，最后更新合并后的章节列表。不要删除其他章节。
4. 正式服务若已有发布目录切换机制，可在完整目录准备好后统一切换，减少混合版本窗口。

此前两个章节封面对应地址是：

```text
https://renzhe2.lp20.cn/StreamingAssets/GameProduceFiles/GameResources/stories/ChapterImages/ChapterThumbnails/chapter-001-restore-test_chapterthumbnails.png
https://renzhe2.lp20.cn/StreamingAssets/GameProduceFiles/GameResources/stories/ChapterImages/ChapterThumbnails/memory-album_chapterthumbnails.png
```

新的 tutorial 工程应使用自己的章节 ID，不要沿用上面旧文件名。Linux 区分大小写，`Stories` 和 `stories` 是两个不同目录；服务器原版使用小写，导出及配置应一致使用小写，不必为此把原版目录改名。

**验收**：章节文件和引用媒体已上传，配置路径与实际目录一致。建议回复：`章节文件和素材已上传`。

## P05 刷新客户端并验收

“上传成功”不等于“自动显示新章”。客户端必须读到合并后的章节列表，章的隐藏/锁定/前置条件允许展示，配置和资源路径必须能访问。缓存/CDN 也可能让旧列表暂时继续生效。

1. 打开线上客户端，刷新并在网络面板确认读取的是新章节列表。必要时临时禁用浏览器缓存或刷新对应 CDN 文件。
2. 确认两章可见，封面可加载；若章不可见，先检查 `isHidden`、前置章节及解锁配置。
3. 进入主线分别走两条分支、汇合、动作成功和失败、失败重试。
4. 验证真实广告取消/失败不发奖，完成只发一次；真实广告不可用时记录未验收，不用编辑器模拟结果代替。
5. 打开独立回忆录，验证未解锁禁用、已解锁回放、跨章返回。
6. 重新进入游戏检查奖励与回忆状态持久化。要测首玩，应使用明确的测试账号或游戏支持的存档重置方式；不要清空正式用户进度。

**验收**：逐项记录真实客户端通过、失败或未测。建议回复：`客户端完整流程正常`（仅在实际均通过后）。

## P06 按报错定位问题

| 现象 | 优先检查 |
| --- | --- |
| 封面请求 404 | 从 Network 复制完整 URL，对照包内文件名、章节 ID、扩展名和小写 `stories`；两个章都要绑定封面再重新导出。 |
| JPG 有文件，但先报 PNG 404 | 当前客户端会探测封面候选，优先 PNG。建议正式封面导入真正的 PNG；不要只改扩展名伪装编码。确认最终显示和最终成功响应。 |
| 章节可见但视频 404 | 是否上传媒体、是否取消了包含媒体、是否重复套 StreamingAssets、是否改错 EditoData 拼写。 |
| URL 返回 200 仍不能播放 | 查看响应是否实际媒体而非 HTML fallback、文件字节是否完整、浏览器支持的编码/音轨与服务 Range 响应是否正常。 |
| 原有章节消失 | 是否以局部导出列表覆盖了全量列表；用备份恢复后按 ID 重新合并。 |
| 回忆一直锁定 | 奖励、登记、卡片是否用相同变量名，线上 Variables 是否已合并，奖励是否真正完成。 |
| 跨章找不到目标 | 目标 chapterId、jumpPointId 是否仍有效，是否从含依赖的回忆录导出并上传了目标章。 |
| 每次领取都加分 | 已领取条件、持久变量定义是否正确；是否反复清除测试存档。 |
| 视频继续播放到片尾才失败 | 这是当前动作失败机制；需要更短的动作片段来配合节奏。 |
| 清空编辑器试走后，线上仍是已领取 | 两套存档独立，这是正常现象。 |

修改路径应优先修正工程/导出源，再生成包和合并配置，避免只手改服务器导致下一次导出又覆盖回旧路径。

## P07 保存协作版本与交付记录

版本控制保存的是章节工程及教程、skills，不是依靠 runtime ZIP 继续编辑。

在章节仓库目录中，保存并退出编辑后，检查和提交**本次确实修改的范围**，例如：

```sh
git status --short
git add chapters/tutorial-001-copy chapters/tutorial-album
git diff --cached --stat
git commit -m "Add action training and cross-chapter memory album"
```

首次提交仓库工程时，还需包含 `story.repository.json`、`.gitignore`、`.gitattributes`。媒体使用 Git LFS，换机器要拉取实际 LFS 内容。先处理 JSON/节点 ID/变量等语义冲突，再试走，不要靠全部选择一方掩盖断链。

记录发布包文件名、编辑器版本、Git 提交、涉及章节 ID、服务器上传时间、客户端验收结果与回滚位置。推送前需已有团队远程仓库及权限；本地提交不会自动发布到服务器，也不会自动推送 Git。

使用 [学习记录模板](../learning-record.md) 记录本次交付；需要 Codex 辅助时参见 [skill 教程](../skills-guide.md)。
