docs(save): 补充瞬跳节点与存档边界设计说明
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+104
-30
@@ -15,9 +15,9 @@
|
||||
|
||||
|
||||
| 类型 | 标签 | 职责 | 跳转权限 | 内容限制 |
|
||||
| ------------- | ------------- | ------------ | ----------------- | ------------------------------------- |
|
||||
| `start` | `start` | 引擎入口 | 仅单出口 `<<jump>>` | 无叙事文本,仅做环境初始化与跳转 |
|
||||
| `init` | `init` | 变量声明与初始状态 | 仅单出口 `<<jump>>` | 仅 `<<declare>>` / `<<set>>` / 全局参数初始化 |
|
||||
| ------------- | ------------- | ------------ | ----------------- | ------------------------------------------------------ |
|
||||
| `start` | `start` | 引擎入口 | 单出口 `<<jump>>` | 无叙事文本;负责最小环境初始化,并 `<<detour>>` 调用 `init` 后跳转到 `Center` |
|
||||
| `init` | `init` | 变量声明与初始状态 | 无出口 | 仅 `<<declare>>` / `<<set>>` / 全局参数初始化;本身不跳转 |
|
||||
| `center` | `center` | 阶段调度中枢 | 可多出口 `<<jump>>` | 仅按 `$gameStage` 分发,无文本、无选项 |
|
||||
| `content` | `content` | 阶段内容节点 | 通常单出口 | 可含叙事文本、局部选项、小游戏指令 |
|
||||
| `performance` | `performance` | 原子化线性演出节点 | 单出口 | timeline、cutscene 等,禁止选项 |
|
||||
@@ -30,6 +30,8 @@
|
||||
|
||||
- `deprecated`:已废弃节点,运行时不可达。
|
||||
- `wip`:待编辑/占位节点,运行时不可达。
|
||||
- `no_save`:该节点**不可作为保存边界**。即使节点类型通常允许保存(如 `content`),附加此标签也表示此处不应触发保存。
|
||||
- **瞬跳节点**:见 [§8 瞬跳节点与存档边界](#8-瞬跳节点与存档边界)。所有瞬跳节点均不可作为保存边界。
|
||||
|
||||
---
|
||||
|
||||
@@ -64,15 +66,17 @@ tags: start
|
||||
<<init_actor 地铁医生 左边>>
|
||||
<<show_actor 地铁医生>>
|
||||
|
||||
<<jump VarsInit>>
|
||||
<<detour VarsInit>>
|
||||
<<jump Center>>
|
||||
===
|
||||
```
|
||||
|
||||
**约束清单:**
|
||||
|
||||
- 固定命名为 `Start`,标签 `start`。
|
||||
- 整个项目的开始阶段固定命名为 `Start`,标签 `start`。
|
||||
- 单个yarn脚本的开始阶段不能命名为`Start`,但标签为`start`。
|
||||
- 不写叙事文本、不声明变量、不含选项。
|
||||
- 仅做最小必要的环境初始化,然后跳转到 `init`。
|
||||
- 仅做最小必要的环境初始化。
|
||||
|
||||
---
|
||||
|
||||
@@ -80,6 +84,8 @@ tags: start
|
||||
|
||||
集中声明维修流程所需变量,并设置初始全局参数。与梦境规范中的 `InitParams` 属于同一类型,只是节点名可按项目习惯选择 `VarsInit` 或 `数据初始化`。
|
||||
|
||||
`init` 节点本身**不包含任何跳转出口**,由 `Start` 节点通过 `<<detour>>` 调用;执行完毕后控制流自动返回 `Start`,再由 `Start` 统一跳转到 `Center`。
|
||||
|
||||
```yarn
|
||||
title: VarsInit
|
||||
tags: init
|
||||
@@ -95,8 +101,6 @@ tags: init
|
||||
// 小游戏相关状态
|
||||
<<declare $salesTurnIndex=0>>
|
||||
<<declare $knobFailCount=0>>
|
||||
|
||||
<<jump Center>>
|
||||
===
|
||||
```
|
||||
|
||||
@@ -104,7 +108,7 @@ tags: init
|
||||
|
||||
- 标签 `init`,固定命名为 `VarsInit`(或统一使用 `数据初始化`)。
|
||||
- 仅包含 `<<declare>>`、`<<set>>`、`<<set_global_param>>` 等初始化指令。
|
||||
- 禁止叙事文本、选项、`<<jump>>` 到非 `center` 节点。
|
||||
- 禁止叙事文本、选项和任何 `<<jump>>`。
|
||||
- 同一 project 内,`init` 节点的命名必须一致。
|
||||
|
||||
---
|
||||
@@ -140,6 +144,7 @@ tags: center
|
||||
- 仅按 `$gameStage` 做 `if` 分发,不写叙事文本、不含选项。
|
||||
- 维修终止条件统一在此处理(如 `$gameStage == 999` 时跳转到 `end`)。
|
||||
- 是同一 project 内**唯一**应该读取 `$gameStage` 的节点。
|
||||
- **瞬跳节点**:`Center` 只做阶段分发,进入后立刻 `<<jump>>` 到 `StageN` 等目标,不向玩家停留;**不得作为存档边界**(tag 上已属禁止保存类型,编写时勿把可存逻辑写在此节点)。
|
||||
|
||||
---
|
||||
|
||||
@@ -181,6 +186,7 @@ hs: 医——生——! #line:0bade9e
|
||||
- 阶段末尾通常做两件事:设置 `$gameStage`、跳回 `Center`。
|
||||
- 允许内部嵌套局部选项,但选项应服务于当前阶段内容,不做跨阶段跳转。
|
||||
- 不应读取 `$gameStage` 做复杂分发(这是 `center` 的职责)。
|
||||
- **瞬跳 content**:若节点内无台词、无选项、进入后仅做 `<<set>>` / 条件判断并立刻 `<<jump>>`(如 `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#,通常不应作为保存边界。
|
||||
- 可含少量结束演出与收尾对话。
|
||||
- 最终必须调用 `<<NextYarn>>`,将控制权交还 C#。
|
||||
- 可能跳回center,也可能进入<<NextYarn>>
|
||||
- 不要在一个维修脚本里设置多个 `end` 节点,除非剧情明确需要分支结局。
|
||||
|
||||
---
|
||||
@@ -307,10 +313,16 @@ me: 今天就到这里吧。 #line:xxxxxxxx
|
||||
## 4. 控制流图
|
||||
|
||||
```
|
||||
Start ──<<jump>>──> VarsInit / 数据初始化
|
||||
Start ──<<detour>>──> VarsInit / 数据初始化
|
||||
│ │
|
||||
│ │(自动返回 Start)
|
||||
│ ▼
|
||||
│ Start
|
||||
│ │
|
||||
▼ │
|
||||
Center ◀─────────────────────┘
|
||||
│
|
||||
▼
|
||||
Center ──<<jump>>──> Stage1(content/performance 入口)
|
||||
├──<<jump>>──> Stage1(content/performance 入口)
|
||||
│ │
|
||||
│ ├── content 子节点 ── ...
|
||||
│ │
|
||||
@@ -339,31 +351,93 @@ Center ──<<jump>>──> Stage1(content/performance 入口)
|
||||
|
||||
|
||||
| 检查项 | start | init | center | content | performance | event | function | end |
|
||||
| ------------------ | ----- | ----- | ------ | ------- | ----------- | ----- | -------- | ----------------- |
|
||||
| 是否包含叙事文本? | 禁止 | 禁止 | 禁止 | 允许 | 允许(演出文本) | 禁止 | 禁止 | 允许(少量) |
|
||||
| ------------------ | ----- | ---- | ------ | ------- | ------------------------ | ------------------- | -------- | ----------------- |
|
||||
| 是否包含叙事文本? | 禁止 | 禁止 | 禁止 | 允许 | 禁止 | 禁止 | 禁止 | 允许(少量) |
|
||||
| 是否包含选项? | 禁止 | 禁止 | 禁止 | 允许 | 禁止 | 禁止 | 禁止 | 禁止 |
|
||||
| 是否有 `<<jump>>`? | 仅一个出口 | 仅一个出口 | 可多出口 | 通常一个出口 | 单出口 | 可有 | 禁止 | 最终 `<<NextYarn>>` |
|
||||
| 是否有 `<<jump>>`? | 仅一个出口 | 禁止 | 可多出口 | 通常一个出口 | 单出口 | 可有 | 禁止 | 最终 `<<NextYarn>>` |
|
||||
| 是否修改 `$gameStage`? | 禁止 | 可初始化 | 禁止 | 允许 | 禁止 | 尽量避免 | 禁止 | 禁止 |
|
||||
| 是否被 C# 调用? | 否 | 否 | 否 | 否 | 否 | 是 | 否 | 否 |
|
||||
| 是否可作为保存边界? | 否 | 否 | 否 | 否 | 是(仅开头/结尾) | 否 | 否 | 是 |
|
||||
| 是否可作为保存边界? | 否 | 否 | 否(瞬跳) | 是(**瞬跳 content 除外**,须 `no_save`) | 仅开头/结尾(节点本身建议 `no_save`) | 否(可附加 `no_save` 强调) | 否 | 否(建议 `no_save`) |
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 7. 废弃与占位节点
|
||||
## 7. 附加标记
|
||||
|
||||
- 废弃或待编辑节点必须附加 `deprecated` 或 `wip` 标签。
|
||||
- 任何活跃节点不得 `<<jump>>` 到 `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` 覆盖默认可保存语义。
|
||||
|
||||
任何活跃节点不得 `<<jump>>` 到 `deprecated` / `wip` 节点,也不得在标记为 `no_save` 的节点处触发自动保存。
|
||||
|
||||
---
|
||||
|
||||
## 8. 设计原则
|
||||
## 8. 瞬跳节点与存档边界
|
||||
|
||||
- `**start` 负责启动**:最小初始化 + 跳转到 `init`。
|
||||
- `**init` 负责配置**:所有变量声明集中管理。
|
||||
- `**center` 负责调度**:打开 `center` 即可一览整个维修流程阶段。
|
||||
### 8.1 定义
|
||||
|
||||
**瞬跳节点**:进入后**不向玩家展示可感知内容**(无台词、无选项、无需要玩家推进的对话行),在同一轮 Yarn 执行中**很快**通过 `<<jump>>` 离开,或仅承担路由 / 变量写入 / 阶段切换的节点。
|
||||
|
||||
典型特征(满足多数即可视为瞬跳):
|
||||
|
||||
- 节点体无角色台词、无 `->` 选项;
|
||||
- 仅有 `<<if>>` + `<<set>>` + `<<jump>>`,或少量 `<<wait>>` 后立即跳转;
|
||||
- 玩家不会在屏幕上「停」在这个节点完成一次交互。
|
||||
|
||||
### 8.2 与存档的关系
|
||||
|
||||
**所有瞬跳节点均不得作为存档边界。** 原因:
|
||||
|
||||
1. **语义**:存档点应对应玩家能感知的进度位置;瞬跳节点只是控制流中转,不是叙事/玩法上的「停点」。
|
||||
2. **实现**:瞬跳节点常在同一帧内连跳(如 `content` → `end` → `Center` → `start`);若在瞬跳节点触发保存,锚点容易漂移或落到 `start` / `center` 等错误节点(参见 `UF检查状态` → `Stage3` 一类问题)。
|
||||
|
||||
### 8.3 按 tag 的默认策略
|
||||
|
||||
| 类型 | 是否瞬跳 | 是否可存 | 说明 |
|
||||
| ---- | -------- | -------- | ---- |
|
||||
| `start` | 是 | 否 | tag 已禁止 |
|
||||
| `init` | 是 | 否 | tag 已禁止 |
|
||||
| **`center`** | **是** | **否** | **阶段调度,仅分发 `<<jump>>`;编写与排查时明确视为瞬跳** |
|
||||
| `function` | 是 | 否 | tag 已禁止 |
|
||||
| `event` | 多为瞬跳 | 否 | tag 已禁止;路由型 event 一律不可存 |
|
||||
| `end` | 多为瞬跳 | 否 | 建议 `end no_save` |
|
||||
| `performance` | 否(演出中) | 否 | 节点本身不可存;边界在演出前后 |
|
||||
| **`content`** | **视内容而定** | **仅非瞬跳 content 可存** | 有台词/选项/玩家停留 → 可存;纯路由 → **须 `no_save`** |
|
||||
|
||||
### 8.4 维修脚本中的常见瞬跳 content(待排查)
|
||||
|
||||
以下模式在现有脚本中已出现或容易出现,**应加 `no_save` 或改写为不可触发的保存路径**(全项目逐步排查,非一次性改完):
|
||||
|
||||
- `*检查状态`、`*状态`:条件满足后立刻 `<<jump>>` 到结束/下一阶段(如 `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` 负责启动**:最小初始化 + `<<detour>>` 调用 `init` + 唯一 `<<jump>>` 到 `Center`。
|
||||
- `**init` 负责配置**:所有变量声明集中管理;无跳转出口,执行完毕后返回 `Start`。
|
||||
- `**center` 负责调度**:打开 `center` 即可一览整个维修流程阶段;**瞬跳、不可存**。
|
||||
- `**content` 负责内容**:阶段之间的叙事、选项、小游戏交互隔离,便于单独调整。
|
||||
- `**performance` 负责原子化演出**:timeline、cutscene 等必须完整播放,保存边界清晰。
|
||||
- `**event` 负责桥接**:把 C# 事件翻译成 Yarn 内部跳转,不掺杂叙事。
|
||||
|
||||
@@ -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)。
|
||||
|
||||
+1
-1
@@ -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` 节点不保存。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user