From 4d8707cf4e787a90195ac25770334636fc7d7993 Mon Sep 17 00:00:00 2001 From: Ding Yuntian <1491671119@qq.com> Date: Thu, 18 Jun 2026 14:35:03 +0800 Subject: [PATCH] =?UTF-8?q?docs(save):=20=E8=A1=A5=E5=85=85=E7=9E=AC?= =?UTF-8?q?=E8=B7=B3=E8=8A=82=E7=82=B9=E4=B8=8E=E5=AD=98=E6=A1=A3=E8=BE=B9?= =?UTF-8?q?=E7=95=8C=E8=AE=BE=E8=AE=A1=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- Docs/Yarn维修节点类型规范.md | 156 ++++++++++++++++++++++++++--------- Docs/存档系统设计方案.md | 4 + Docs/存档系统需求.md | 2 +- 3 files changed, 120 insertions(+), 42 deletions(-) diff --git a/Docs/Yarn维修节点类型规范.md b/Docs/Yarn维修节点类型规范.md index b54771115..02570bf7b 100644 --- a/Docs/Yarn维修节点类型规范.md +++ b/Docs/Yarn维修节点类型规范.md @@ -14,22 +14,24 @@ ## 1. 节点类型与跳转权限 -| 类型 | 标签 | 职责 | 跳转权限 | 内容限制 | -| ------------- | ------------- | ------------ | ----------------- | ------------------------------------- | -| `start` | `start` | 引擎入口 | 仅单出口 `<>` | 无叙事文本,仅做环境初始化与跳转 | -| `init` | `init` | 变量声明与初始状态 | 仅单出口 `<>` | 仅 `<>` / `<>` / 全局参数初始化 | -| `center` | `center` | 阶段调度中枢 | 可多出口 `<>` | 仅按 `$gameStage` 分发,无文本、无选项 | -| `content` | `content` | 阶段内容节点 | 通常单出口 | 可含叙事文本、局部选项、小游戏指令 | -| `performance` | `performance` | 原子化线性演出节点 | 单出口 | timeline、cutscene 等,禁止选项 | -| `event` | `event` | C# 调用的事件响应入口 | 单/多出口 `<>` | 仅轻量路由,禁止大段叙事 | -| `function` | `function` | 纯指令封装 | **禁止 `<>`** | 仅 Command,无文本;命名加 `_Func` 后缀 | -| `end` | `end` | 维修结束/收尾 | 单出口 | 可含少量结束演出,最终必须 `<>` | +| 类型 | 标签 | 职责 | 跳转权限 | 内容限制 | +| ------------- | ------------- | ------------ | ----------------- | ------------------------------------------------------ | +| `start` | `start` | 引擎入口 | 单出口 `<>` | 无叙事文本;负责最小环境初始化,并 `<>` 调用 `init` 后跳转到 `Center` | +| `init` | `init` | 变量声明与初始状态 | 无出口 | 仅 `<>` / `<>` / 全局参数初始化;本身不跳转 | +| `center` | `center` | 阶段调度中枢 | 可多出口 `<>` | 仅按 `$gameStage` 分发,无文本、无选项 | +| `content` | `content` | 阶段内容节点 | 通常单出口 | 可含叙事文本、局部选项、小游戏指令 | +| `performance` | `performance` | 原子化线性演出节点 | 单出口 | timeline、cutscene 等,禁止选项 | +| `event` | `event` | C# 调用的事件响应入口 | 单/多出口 `<>` | 仅轻量路由,禁止大段叙事 | +| `function` | `function` | 纯指令封装 | **禁止 `<>`** | 仅 Command,无文本;命名加 `_Func` 后缀 | +| `end` | `end` | 维修结束/收尾 | 单出口 | 可含少量结束演出,最终必须 `<>` | 附加标记(可附加到任何类型): - `deprecated`:已废弃节点,运行时不可达。 - `wip`:待编辑/占位节点,运行时不可达。 +- `no_save`:该节点**不可作为保存边界**。即使节点类型通常允许保存(如 `content`),附加此标签也表示此处不应触发保存。 +- **瞬跳节点**:见 [§8 瞬跳节点与存档边界](#8-瞬跳节点与存档边界)。所有瞬跳节点均不可作为保存边界。 --- @@ -64,15 +66,17 @@ tags: start <> <> -<> +<> +<> === ``` **约束清单:** -- 固定命名为 `Start`,标签 `start`。 +- 整个项目的开始阶段固定命名为 `Start`,标签 `start`。 +- 单个yarn脚本的开始阶段不能命名为`Start`,但标签为`start`。 - 不写叙事文本、不声明变量、不含选项。 -- 仅做最小必要的环境初始化,然后跳转到 `init`。 +- 仅做最小必要的环境初始化。 --- @@ -80,6 +84,8 @@ tags: start 集中声明维修流程所需变量,并设置初始全局参数。与梦境规范中的 `InitParams` 属于同一类型,只是节点名可按项目习惯选择 `VarsInit` 或 `数据初始化`。 +`init` 节点本身**不包含任何跳转出口**,由 `Start` 节点通过 `<>` 调用;执行完毕后控制流自动返回 `Start`,再由 `Start` 统一跳转到 `Center`。 + ```yarn title: VarsInit tags: init @@ -95,8 +101,6 @@ tags: init // 小游戏相关状态 <> <> - -<> === ``` @@ -104,7 +108,7 @@ tags: init - 标签 `init`,固定命名为 `VarsInit`(或统一使用 `数据初始化`)。 - 仅包含 `<>`、`<>`、`<>` 等初始化指令。 -- 禁止叙事文本、选项、`<>` 到非 `center` 节点。 +- 禁止叙事文本、选项和任何 `<>`。 - 同一 project 内,`init` 节点的命名必须一致。 --- @@ -140,6 +144,7 @@ tags: center - 仅按 `$gameStage` 做 `if` 分发,不写叙事文本、不含选项。 - 维修终止条件统一在此处理(如 `$gameStage == 999` 时跳转到 `end`)。 - 是同一 project 内**唯一**应该读取 `$gameStage` 的节点。 +- **瞬跳节点**:`Center` 只做阶段分发,进入后立刻 `<>` 到 `StageN` 等目标,不向玩家停留;**不得作为存档边界**(tag 上已属禁止保存类型,编写时勿把可存逻辑写在此节点)。 --- @@ -181,6 +186,7 @@ hs: 医——生——! #line:0bade9e - 阶段末尾通常做两件事:设置 `$gameStage`、跳回 `Center`。 - 允许内部嵌套局部选项,但选项应服务于当前阶段内容,不做跨阶段跳转。 - 不应读取 `$gameStage` 做复杂分发(这是 `center` 的职责)。 +- **瞬跳 content**:若节点内无台词、无选项、进入后仅做 `<>` / 条件判断并立刻 `<>`(如 `UF检查状态`),属于瞬跳节点,须附加 `no_save`,不得依赖默认的 content 可存语义。详见 [§8](#8-瞬跳节点与存档边界)。 --- @@ -203,9 +209,9 @@ tags: performance - 标签 `performance`。 - **禁止分支选项**,必须单出口。 +- **禁止叙事文本、角色台词与旁白**; - 保存点只能出现在 `performance` 节点的**开始之前**或**结束之后**,节点内部不允许保存。 -- 可包含 timeline 播放、镜头运动、动画演出等线性指令。 -- 不宜包含需要玩家选择的选项或小游戏交互。 +- 仅包含 timeline 播放、镜头运动、动画演出等线性指令。 --- @@ -278,7 +284,7 @@ tags: function ### 3.8 end 节点 -维修流程的收尾节点,负责结束演出并触发下一段 Yarn。 +维修流程的收尾节点,负责结束当前脚本。 ```yarn title: End @@ -297,9 +303,9 @@ me: 今天就到这里吧。 #line:xxxxxxxx **约束清单:** -- 标签 `end`。 +- 标签 `end`,建议同时附加 `no_save`:维修流程已结束,控制权即将交还 C#,通常不应作为保存边界。 - 可含少量结束演出与收尾对话。 -- 最终必须调用 `<>`,将控制权交还 C#。 +- 可能跳回center,也可能进入<> - 不要在一个维修脚本里设置多个 `end` 节点,除非剧情明确需要分支结局。 --- @@ -307,10 +313,16 @@ me: 今天就到这里吧。 #line:xxxxxxxx ## 4. 控制流图 ``` -Start ──<>──> VarsInit / 数据初始化 +Start ──<>──> VarsInit / 数据初始化 + │ │ + │ │(自动返回 Start) + │ ▼ + │ Start + │ │ + ▼ │ +Center ◀─────────────────────┘ │ - ▼ -Center ──<>──> Stage1(content/performance 入口) + ├──<>──> Stage1(content/performance 入口) │ │ │ ├── content 子节点 ── ... │ │ @@ -338,32 +350,94 @@ Center ──<>──> Stage1(content/performance 入口) ## 6. 快速检查表 -| 检查项 | start | init | center | content | performance | event | function | end | -| ------------------ | ----- | ----- | ------ | ------- | ----------- | ----- | -------- | ----------------- | -| 是否包含叙事文本? | 禁止 | 禁止 | 禁止 | 允许 | 允许(演出文本) | 禁止 | 禁止 | 允许(少量) | -| 是否包含选项? | 禁止 | 禁止 | 禁止 | 允许 | 禁止 | 禁止 | 禁止 | 禁止 | -| 是否有 `<>`? | 仅一个出口 | 仅一个出口 | 可多出口 | 通常一个出口 | 单出口 | 可有 | 禁止 | 最终 `<>` | -| 是否修改 `$gameStage`? | 禁止 | 可初始化 | 禁止 | 允许 | 禁止 | 尽量避免 | 禁止 | 禁止 | -| 是否被 C# 调用? | 否 | 否 | 否 | 否 | 否 | 是 | 否 | 否 | -| 是否可作为保存边界? | 否 | 否 | 否 | 否 | 是(仅开头/结尾) | 否 | 否 | 是 | +| 检查项 | start | init | center | content | performance | event | function | end | +| ------------------ | ----- | ---- | ------ | ------- | ------------------------ | ------------------- | -------- | ----------------- | +| 是否包含叙事文本? | 禁止 | 禁止 | 禁止 | 允许 | 禁止 | 禁止 | 禁止 | 允许(少量) | +| 是否包含选项? | 禁止 | 禁止 | 禁止 | 允许 | 禁止 | 禁止 | 禁止 | 禁止 | +| 是否有 `<>`? | 仅一个出口 | 禁止 | 可多出口 | 通常一个出口 | 单出口 | 可有 | 禁止 | 最终 `<>` | +| 是否修改 `$gameStage`? | 禁止 | 可初始化 | 禁止 | 允许 | 禁止 | 尽量避免 | 禁止 | 禁止 | +| 是否被 C# 调用? | 否 | 否 | 否 | 否 | 否 | 是 | 否 | 否 | +| 是否可作为保存边界? | 否 | 否 | 否(瞬跳) | 是(**瞬跳 content 除外**,须 `no_save`) | 仅开头/结尾(节点本身建议 `no_save`) | 否(可附加 `no_save` 强调) | 否 | 否(建议 `no_save`) | --- -## 7. 废弃与占位节点 +## 7. 附加标记 -- 废弃或待编辑节点必须附加 `deprecated` 或 `wip` 标签。 -- 任何活跃节点不得 `<>` 到 `deprecated` / `wip` 节点。 -- 任何 C# 代码不得调用 `deprecated` / `wip` 节点。 -- 建议:`deprecated` 用于已废弃的旧节点,`wip` 用于尚未完成的占位节点。 +- `deprecated`:已废弃节点,运行时不可达。 +- `wip`:待编辑/占位节点,运行时不可达。 +- `no_save`:该节点不可作为保存边界,运行时经过此处不应触发保存。 + +### 7.1 `no_save` 使用场景 + +`no_save` 用于显式声明某节点处**不允许保存**,常用于以下情况: + +- `end` 节点:维修流程已结束,控制权即将交还 C#,通常附加 `no_save`。 +- `performance` 节点:演出期间不能保存,建议在 `tags:` 中附加 `no_save`。 +- 关键 `event` 节点:事件路由节点通常不保存,可附加 `no_save` 强调。 +- **瞬跳 `content` 节点**:无玩家可感知停留、进入后立即跳转的路由/状态检查节点(如 `UF检查状态`),必须附加 `no_save`。完整定义与排查清单见 [§8](#8-瞬跳节点与存档边界)。 +- 特殊 `content` 节点:极少数剧情上明确不希望保存的 `content` 节点,可附加 `no_save` 覆盖默认可保存语义。 + +任何活跃节点不得 `<>` 到 `deprecated` / `wip` 节点,也不得在标记为 `no_save` 的节点处触发自动保存。 --- -## 8. 设计原则 +## 8. 瞬跳节点与存档边界 -- `**start` 负责启动**:最小初始化 + 跳转到 `init`。 -- `**init` 负责配置**:所有变量声明集中管理。 -- `**center` 负责调度**:打开 `center` 即可一览整个维修流程阶段。 +### 8.1 定义 + +**瞬跳节点**:进入后**不向玩家展示可感知内容**(无台词、无选项、无需要玩家推进的对话行),在同一轮 Yarn 执行中**很快**通过 `<>` 离开,或仅承担路由 / 变量写入 / 阶段切换的节点。 + +典型特征(满足多数即可视为瞬跳): + +- 节点体无角色台词、无 `->` 选项; +- 仅有 `<>` + `<>` + `<>`,或少量 `<>` 后立即跳转; +- 玩家不会在屏幕上「停」在这个节点完成一次交互。 + +### 8.2 与存档的关系 + +**所有瞬跳节点均不得作为存档边界。** 原因: + +1. **语义**:存档点应对应玩家能感知的进度位置;瞬跳节点只是控制流中转,不是叙事/玩法上的「停点」。 +2. **实现**:瞬跳节点常在同一帧内连跳(如 `content` → `end` → `Center` → `start`);若在瞬跳节点触发保存,锚点容易漂移或落到 `start` / `center` 等错误节点(参见 `UF检查状态` → `Stage3` 一类问题)。 + +### 8.3 按 tag 的默认策略 + +| 类型 | 是否瞬跳 | 是否可存 | 说明 | +| ---- | -------- | -------- | ---- | +| `start` | 是 | 否 | tag 已禁止 | +| `init` | 是 | 否 | tag 已禁止 | +| **`center`** | **是** | **否** | **阶段调度,仅分发 `<>`;编写与排查时明确视为瞬跳** | +| `function` | 是 | 否 | tag 已禁止 | +| `event` | 多为瞬跳 | 否 | tag 已禁止;路由型 event 一律不可存 | +| `end` | 多为瞬跳 | 否 | 建议 `end no_save` | +| `performance` | 否(演出中) | 否 | 节点本身不可存;边界在演出前后 | +| **`content`** | **视内容而定** | **仅非瞬跳 content 可存** | 有台词/选项/玩家停留 → 可存;纯路由 → **须 `no_save`** | + +### 8.4 维修脚本中的常见瞬跳 content(待排查) + +以下模式在现有脚本中已出现或容易出现,**应加 `no_save` 或改写为不可触发的保存路径**(全项目逐步排查,非一次性改完): + +- `*检查状态`、`*状态`:条件满足后立刻 `<>` 到结束/下一阶段(如 `UF检查状态`、`视觉检查状态` 在 `$isFinished*==true` 分支); +- 阶段 `StageN` 入口若 tag 为 `start`:已禁止,勿改为 `content` 除非有真实停点; +- 任何「只写 `$gameStage` 并跳 `Center` / `结束*`」的短节点。 + +### 8.5 编写与审查 checklist + +- [ ] 该节点玩家是否会看到对话或做出选择?若否 → 瞬跳 → **不可存**,加 `no_save`。 +- [ ] 是否为 `Center` 或等价调度节点?→ **不可存**。 +- [ ] 进入后是否在**同一轮控制流**内连跳多个节点?→ 链上所有节点都不应单独成为存档边界;可存点应落在链**之后**第一个玩家会停住的 `content` 上。 +- [ ] 新加 `content` 节点时,默认「可存」;仅当确认有玩家停点时才省略 `no_save`。 + +> **TODO(脚本排查)**:对 `Assets/Yarn/FP/` 下各 project 扫描瞬跳 `content` 节点,补 `no_save` 或调整跳转结构。优先级可参考存档验证工具中误报节点(如 Peipei `UF检查状态`)。 + +--- + +## 9. 设计原则 + +- `**start` 负责启动**:最小初始化 + `<>` 调用 `init` + 唯一 `<>` 到 `Center`。 +- `**init` 负责配置**:所有变量声明集中管理;无跳转出口,执行完毕后返回 `Start`。 +- `**center` 负责调度**:打开 `center` 即可一览整个维修流程阶段;**瞬跳、不可存**。 - `**content` 负责内容**:阶段之间的叙事、选项、小游戏交互隔离,便于单独调整。 - `**performance` 负责原子化演出**:timeline、cutscene 等必须完整播放,保存边界清晰。 - `**event` 负责桥接**:把 C# 事件翻译成 Yarn 内部跳转,不掺杂叙事。 diff --git a/Docs/存档系统设计方案.md b/Docs/存档系统设计方案.md index 4394923dd..337a91a49 100644 --- a/Docs/存档系统设计方案.md +++ b/Docs/存档系统设计方案.md @@ -105,6 +105,8 @@ - **落点时机**:P3 可存点判定通过后(当前 P1:`SnapshotCapture` 在进入节点写档时捕获 `GetCurrentNodeContext()`)。 +- **瞬跳节点(规范层,待脚本排查 + 实现补强)**:凡进入后不向玩家停留、仅作路由/阶段切换的节点,均不得作为存档边界。维修流程中 **`center` 明确属于瞬跳**;`start` / `init` / `event` / `end` 等 tag 已在 `SavePointEvaluator` 黑名单。部分 **`content` 瞬跳节点**(如 `UF检查状态`)须 Yarn 侧标 `no_save`,详见 [Yarn 维修节点类型规范 §8](Yarn维修节点类型规范.md#8-瞬跳节点与存档边界)。另:若判定通过后在 settle 帧内 Yarn 已连跳,锚点 nodeName 可能漂移——属实现层已知问题,与瞬跳规范一并处理。 + - **重入方式**:读档后 `SnapshotRestore.RestoreAnchor` → `StartDialogue(节点名)`。 @@ -475,6 +477,8 @@ P7 横切 - 各深度维修是否支持阶段存档的逐个清单(P5)。 +- **维修 Yarn 瞬跳 `content` 节点**:按 [Yarn 维修节点类型规范 §8.4](Yarn维修节点类型规范.md#84-维修脚本中的常见瞬跳-content待排查) 全项目补 `no_save`(Peipei `UF检查状态` 等优先)。 + - 全局 / 跨周目数据与单局存档的边界划分。 - 截图的具体规格(P2)。 diff --git a/Docs/存档系统需求.md b/Docs/存档系统需求.md index 9ae636e67..7ddf5844f 100644 --- a/Docs/存档系统需求.md +++ b/Docs/存档系统需求.md @@ -32,7 +32,7 @@ 分情况讨论: -1. **诊所内维修**:仅在诊所中的对话和插线维修时保存;每个角色各自的深度维修过程中**不保存**。但深度维修可能会记录一些**阶段终点状态**,以处理"多段深度维修中间穿插诊所对话"的情况。 +1. **诊所内维修**:仅在诊所中的对话和插线维修时保存;每个角色各自的深度维修过程中**不保存**。但深度维修可能会记录一些**阶段终点状态**,以处理"多段深度维修中间穿插诊所对话"的情况。维修 Yarn 的节点类型与**瞬跳节点**规则见 [Yarn 维修节点类型规范 §8](Yarn维修节点类型规范.md#8-瞬跳节点与存档边界):`center` 及所有瞬跳节点不可存;默认可存的 `content` 若仅为路由/状态检查,须标 `no_save`。 2. **诊所外对话**(天桥、酒吧、诊室外等):每个节点都保存。 3. **梦境状态**:情况较复杂,此时 Yarn 结构遵循 [Yarn 节点类型规范](Yarn节点类型规范.md)。在这种情况下,`hub` 节点与 `linear` 节点保存,`detour` 节点与 `function` 节点不保存。