Files
aibis-dream/Docs/Yarn维修节点类型规范.md
T

508 lines
22 KiB
Markdown
Raw 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.
# Yarn 维修节点类型规范
本规范适用于 `Assets/Yarn/FP/` 下的维修流程脚本,包括:
- `FP_Huoshan1`
- `FP_Peipei1` / `FP_Peipei2` / `FP_Peipei3`
- `FP_Shitou1` / `FP_Shitou2`
- `FP_Prologue`
> **注意**`FP_Day*_sleep` 属于梦境脚本,沿用《Yarn 节点类型规范.md》;`FP_Day*_begin/mid/night` 属于外出/日常脚本,不在本规范范围内。
---
## 1. 节点类型与跳转权限
| 类型 | 标签 | 职责 | 跳转权限 | 内容限制 |
| ------------- | ------------- | ------------ | ----------------- | ------------------------------------------------------ |
| `start` | `start` | 引擎入口 | 单出口 `<<jump>>` | 无叙事文本;负责最小环境初始化,并 `<<detour>>` 调用 `init` 后跳转到 `Center` |
| `init` | `init` | 变量声明与初始状态 | 无出口 | 仅 `<<declare>>` / `<<set>>` / 全局参数初始化;本身不跳转 |
| `center` | `center` | 阶段调度中枢 | 可多出口 `<<jump>>` | 仅按 `$gameStage` 分发,无文本、无选项 |
| `content` | `content` | 阶段内容节点 | 通常单出口 | 可含叙事文本、局部选项、小游戏指令 |
| `interaction` | `interaction` | 交互内容节点 | 可按分支结束或跳转 | 可含叙事、选项与玩法准备指令;正常结束 Dialogue 后进入游戏内交互 |
| `performance` | `performance` | 原子化线性演出节点 | 单出口 | timeline、cutscene 等,禁止选项 |
| `event` | `event` | C# 调用的事件响应入口 | 单/多出口 `<<jump>>` | 仅轻量路由,禁止大段叙事 |
| `function` | `function` | 纯指令封装 | **禁止 `<<jump>>`** | 仅 Command,无文本;命名加 `_Func` 后缀 |
| `end` | `end` | 维修结束/收尾 | 单出口 | 可含少量结束演出,最终必须 `<<NextYarn>>` |
附加标记(可附加到任何类型):
- `deprecated`:已废弃节点,运行时不可达。
- `wip`:待编辑/占位节点,运行时不可达。
- `no_save`:该节点**不可作为保存边界**。即使节点类型通常允许保存(如 `content`),附加此标签也表示此处不应触发保存。
- `save_on_exit`:覆盖一级类型的默认保存语义;进入节点时不保存,节点完成后直接结束本轮 Dialogue 时保存 state-only 档。
- **瞬跳节点**:见 [§8 瞬跳节点与存档边界](#8-瞬跳节点与存档边界)。所有瞬跳节点均不可作为保存边界。
`interaction` 已天然包含 `save_on_exit`,不得重复标记。`no_save``interaction` / `save_on_exit`
互相冲突;运行时遇到冲突时按不保存处理,并输出配置错误。
---
## 2. 命名规则
| 类型 | 命名示例 | 规则 |
| ------------- | ------------------------------------------------------------ | ----------------------------------------------------- |
| `start` | `Start` | 固定命名,首字母大写 |
| `init` | `VarsInit``数据初始化` | 建议统一为 `VarsInit`;如项目已有 `数据初始化`,可保留但同一 project 内保持一致 |
| `center` | `Center` | 固定命名,每个维修 Yarn project 一个 |
| `content` | `Stage1``开头对话``检查情绪``旋钮调节` | 阶段入口建议用 `StageN`;阶段内子节点用中文动宾/名词短语 |
| `interaction` | `Stage3``等待插线``End_memoryPaly` | 沿用内容节点命名;名称应能表达即将进入的游戏内交互 |
| `performance` | `地铁到站演出``手术动画``滤波器启动动画` | 中文描述性名称,明确表达演出内容 |
| `event` | `EmoPlugIn``IntoEyeView``OnSalesTurnComplete` | 用 `OnXxx` 或模块名 + 事件名,表达触发来源 |
| `function` | `Wave_Show_Func``Wave_Hide_Func``Module_HighlightOff_Func` | `领域_动作_Func``模块_动作_Func`PascalCase;必须带 `_Func` 后缀 |
| `end` | `End``Stage8_End` | 统一用 `End` 或带阶段前缀的结束名 |
---
## 3. 各类型详细规范
### 3.1 start 节点
Yarn Spinner 默认从名为 `Start` 的节点开始运行。它不属于任何功能类型,职责仅是启动流程。
```yarn
title: Start
tags: start
---
<<init_environment Day>>
<<init_actor 地铁医生 左边>>
<<show_actor 地铁医生>>
<<detour VarsInit>>
<<jump Center>>
===
```
**约束清单:**
- 整个项目的开始阶段固定命名为 `Start`,标签 `start`
- 单个yarn脚本的开始阶段不能命名为`Start`,但标签为`start`
- 不写叙事文本、不声明变量、不含选项。
- 仅做最小必要的环境初始化。
---
### 3.2 init 节点
集中声明维修流程所需变量,并设置初始全局参数。与梦境规范中的 `InitParams` 属于同一类型,只是节点名可按项目习惯选择 `VarsInit``数据初始化`
`init` 节点本身**不包含任何跳转出口**,由 `Start` 节点通过 `<<detour>>` 调用;执行完毕后控制流自动返回 `Start`,再由 `Start` 统一跳转到 `Center`
```yarn
title: VarsInit
tags: init
---
// 流程阶段
<<declare $gameStage=1>>
// 模块检查标记
<<declare $emoChecked=false>>
<<declare $memoryChecked=false>>
<<declare $logicChecked=false>>
// 小游戏相关状态
<<declare $salesTurnIndex=0>>
<<declare $knobFailCount=0>>
===
```
**约束清单:**
- 标签 `init`,固定命名为 `VarsInit`(或统一使用 `数据初始化`)。
- 仅包含 `<<declare>>``<<set>>``<<set_global_param>>` 等初始化指令。
- 禁止叙事文本、选项和任何 `<<jump>>`
- 同一 project 内,`init` 节点的命名必须一致。
---
### 3.3 center 节点
唯一拥有多出口跳转权的节点,负责按 `$gameStage` 进行阶段调度。
```yarn
title: Center
tags: center
---
// Stage1: 诊室开场
// Stage2: 后脑检查
// Stage3: 滤波器深入
// ...
<<if $gameStage == 1>>
<<jump Stage1>>
<<elseif $gameStage == 2>>
<<jump Stage2>>
<<elseif $gameStage == 3>>
<<jump Stage3>>
<<elseif $gameStage == 999>>
<<jump End>>
<<endif>>
===
```
**约束清单:**
- 标签 `center`,固定命名为 `Center`
- 仅按 `$gameStage``if` 分发,不写叙事文本、不含选项。
- 维修终止条件统一在此处理(如 `$gameStage == 999` 时跳转到 `end`)。
- 是同一 project 内**唯一**应该读取 `$gameStage` 的节点。
- **瞬跳节点**`Center` 只做阶段分发,进入后立刻 `<<jump>>``StageN` 等目标,不向玩家停留;**不得作为存档边界**(tag 上已属禁止保存类型,编写时勿把可存逻辑写在此节点)。
---
### 3.4 content 节点
维修流程的核心单元,承载阶段中的实际内容:叙事、选项、小游戏指令等。
```yarn
title: Stage1
tags: content
---
<<hide_dialog>>
<<switch_fix_system_to "Clinic">>
<<fade_out 1>>
<<jump 开头对话>>
===
```
```yarn
title: 开头对话
tags: content
---
hs: 医——生——! #line:0bade9e
<<change_actor_state 捂头表情idle 火山>>
<<fade_in_actor 火山>>
// ... 叙事与演出 ...
<<set $gameStage = 2>>
<<jump Center>>
===
```
**约束清单:**
- 标签 `content`
- 阶段入口节点建议命名为 `StageN`;阶段内子节点用中文描述性名称。
- 阶段末尾通常做两件事:设置 `$gameStage`、跳回 `Center`
- 允许内部嵌套局部选项,但选项应服务于当前阶段内容,不做跨阶段跳转。
- 不应读取 `$gameStage` 做复杂分发(这是 `center` 的职责)。
- **瞬跳 content**:若节点内无台词、无选项、进入后仅做 `<<set>>` / 条件判断并立刻 `<<jump>>`(如 `UF检查状态`),属于瞬跳节点,须附加 `no_save`,不得依赖默认的 content 可存语义。详见 [§8](#8-瞬跳节点与存档边界)。
---
### 3.4.1 interaction 节点
`interaction` 是一种有内容的玩法交互入口。它可以承载与 `content` 相同的台词、选项、演出和
状态准备,但进入节点时不保存;只有节点完成后直接结束本轮 Dialogue 的执行路径,才会生成
state-only 自动档,并把控制权交给游戏系统。
```yarn
title: Stage3
tags: interaction
---
<<switch_fix_system_to "BodyModule" "Head">>
dn: 请使用检查设备继续操作。
===
```
**约束清单:**
- `interaction` 是一级类型,不与 `content` 等其他一级类型并列书写。
- 正常交互入口路径应直接结束 Dialogue;读档时只恢复状态,不重新运行该节点。
- 退出档仍会在 `anchor.nodeName` 中保留该节点名,并通过 `startDialogueOnRestore=false` 表示只加载 YarnProject。
- `DialogEnd` 初始化完成到下一帧快照捕获之间保持玩法输入锁定;快照进入写盘队列后才交出控制权。
- 允许某些条件分支 `<<jump>>` / `<<detour>>` 到其他 Yarn 节点;这些路径会取消退出档并记录告警。
- 节点结束前必须完成所有需要写入快照的状态命令。未等待的 fire-and-forget 命令不可作为可靠边界。
- 后续玩法必须能够完全通过 Snapshot Provider 恢复,包括输入、交互监听和玩法模式,而不只是视觉状态。
- 普通节点需要同样语义时可附加 `save_on_exit``interaction` 无需重复附加。
---
### 3.5 performance 节点
原子化线性演出节点,用于 timeline、cutscene 等必须完整播放的演出。
```yarn
title: 地铁到站演出
tags: performance
---
<<hide_dialog>>
<<play_timeline 地铁到站>>
<<wait 2>>
<<jump 诊室外2>>
===
```
**约束清单:**
- 标签 `performance`
- **禁止分支选项**,必须单出口。
- **禁止叙事文本、角色台词与旁白**;
- 保存点只能出现在 `performance` 节点的**开始之前**或**结束之后**,节点内部不允许保存。
- 仅包含 timeline 播放、镜头运动、动画演出等线性指令。
---
### 3.6 event 节点
由 C# 代码调用的事件响应入口,负责把外部游戏事件映射到对应阶段节点。
```yarn
title: EmoPlugIn
tags: event
---
<<jump 检查情绪>>
===
```
```yarn
title: OnSalesTurnComplete
tags: event
---
<<if $salesTurnIndex == 1>>
<<jump 销售转动_语义合成>>
<<elseif $salesTurnIndex == 2>>
<<jump 销售转动_语言审查>>
<<elseif $salesTurnIndex == 3>>
<<jump 销售转动_异常检测>>
<<endif>>
===
```
**约束清单:**
- 标签 `event`
- 节点标题应表达触发来源,建议使用 `OnXxx` 或「模块 + 事件」形式。
- 允许根据 `$gameStage` 或少量状态变量做轻量 `if` 分发。
- **禁止大段对话、旁白、演出文本**。
- 不应成为玩家直接阅读的内容节点。
---
### 3.7 function 节点
纯指令封装,零文本、零跳转,用于复用一组命令。与梦境规范的 `function` 保持一致,命名加 `_Func` 后缀。
```yarn
title: Wave_Show_Func
tags: function
---
<<switch_emotion_wave_config "normal">>
<<show_emotion_wave 1>>
===
```
```yarn
title: Wave_Hide_Func
tags: function
---
<<hide_emotion_wave 0.3>>
===
```
**约束清单:**
- 标签 `function`
- 命名必须带 `_Func` 后缀。
- **禁止任何叙事文本、对话、选项**。
- **禁止任何 `<<jump>>`**。
- 仅包含演出或小游戏相关的 Command。
---
### 3.8 end 节点
维修流程的收尾节点,负责结束当前脚本。
```yarn
title: End
tags: end
---
<<fade_out 1>>
<<wait 1>>
me: 今天就到这里吧。 #line:xxxxxxxx
<<hide_dialog>>
<<wait 2>>
<<NextYarn>>
===
```
**约束清单:**
- 标签 `end`,建议同时附加 `no_save`:维修流程已结束,控制权即将交还 C#,通常不应作为保存边界。
- 可含少量结束演出与收尾对话。
- 可能跳回center,也可能进入<<NextYarn>>
- 不要在一个维修脚本里设置多个 `end` 节点,除非剧情明确需要分支结局。
---
## 4. 控制流图
```
Start ──<<detour>>──> VarsInit / 数据初始化
│ │
│ │(自动返回 Start)
│ ▼
│ Start
│ │
▼ │
Center ◀─────────────────────┘
├──<<jump>>──> Stage1content/performance 入口)
│ │
│ ├── content 子节点 ── ...
│ │
│ ├── interaction 子节点 ──> 结束 Dialogue ──> 游戏内交互
│ │
│ ├── performance 子节点 ──<<jump>>──> content 或 end
│ │
│ └── <<set $gameStage>> ──> <<jump Center>>
├──<<jump>>──> End ──<<NextYarn>>
└── C# 调用 ──> event 节点 ──<<jump>>──> content 子流程
```
---
## 5. `$gameStage` 使用规范
- `$gameStage``center` 节点的调度主键。
- 类型可以为 `int``string`,但**同一 Yarn project 内必须保持一致**。
- 只有 `center` 节点读取 `$gameStage`
- `content` 节点在末尾写入 `$gameStage`,然后跳回 `center`
- 终止值(如 `999``"流程结束"`)统一在 `center` 中处理。
---
## 6. 快速检查表
| 检查项 | start | init | center | content | interaction | performance | event | function | end |
| ------------------ | ----- | ---- | ------ | ------- | ----------- | ------------------------ | ------------------- | -------- | ----------------- |
| 是否包含叙事文本? | 禁止 | 禁止 | 禁止 | 允许 | 允许 | 禁止 | 禁止 | 禁止 | 允许(少量) |
| 是否包含选项? | 禁止 | 禁止 | 禁止 | 允许 | 允许 | 禁止 | 禁止 | 禁止 | 禁止 |
| 是否有 `<<jump>>`? | 仅一个出口 | 禁止 | 可多出口 | 通常一个出口 | 可按分支跳转 | 单出口 | 可有 | 禁止 | 最终 `<<NextYarn>>` |
| 是否修改 `$gameStage`? | 禁止 | 可初始化 | 禁止 | 允许 | 允许 | 禁止 | 尽量避免 | 禁止 | 禁止 |
| 是否被 C# 调用? | 否 | 否 | 否 | 否 | 否 | 否 | 是 | 否 | 否 |
| 是否可作为保存边界? | 否 | 否 | 否(瞬跳) | 是(**瞬跳 content 除外**,须 `no_save` | 正常结束时保存 state-only | 仅开头/结尾(节点本身建议 `no_save` | 否(可附加 `no_save` 强调) | 否 | 否(建议 `no_save` |
---
## 7. 附加标记
- `deprecated`:已废弃节点,运行时不可达。
- `wip`:待编辑/占位节点,运行时不可达。
- `no_save`:该节点不可作为保存边界,运行时经过此处不应触发保存。
- `save_on_exit`:节点进入时不保存;节点完成并直接结束本轮 Dialogue 后保存 state-only 档。
### 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` 的节点处触发 **OnNodeStart 自动保存**
### 7.2 Yarn 显式存档 `<<save>>`(兼容旧内容)
`<<save>>` 已标记为 deprecated,仅用于兼容尚未迁移的旧内容。新内容进入无对话 / 纯 C# 交互阶段时,
应优先使用一级类型 `interaction`;其他一级类型需要相同行为时使用 `save_on_exit`
```yarn
<<play_timeline 地铁>>
<<hide_dialog>>
<<change_actor_state "turn" "地铁医生">>
<<save>>
<<detour 切换到诊所外>>
```
约定:
- **插入位置**:所有需要进快照的状态命令之后;`<<jump>>` / `<<detour>>` / `load_scene` **之前**(顺序即快照内容)。
- **anchor**:保留来源节点,并写入 `startDialogueOnRestore=false`;依赖 sections 还原画面与玩法状态。
- **判定**:绕过 tag / `no_save`;读档中、暂停、SuppressAutoSave 仍拒绝。
- **async 命令**`change_actor_state_async` 等未等待的命令之后立刻 `<<save>>` 可能 capture 未完成态,save 前应 `<<wait>>` 或使用同步命令。
`no_save``no_save` 禁止的是 **OnNodeStart 自动存**;节点末尾仍可写 `<<save>>` 表达作者意图。
---
## 8. 瞬跳节点与存档边界
### 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 内部跳转,不掺杂叙事。
- `**function` 负责复用指令**:零文本零跳转,`_Func` 后缀与梦境规范保持一致。
- `**end` 负责收尾**:统一出口,统一 `<<NextYarn>>`
---