19 KiB
Yarn 维修节点类型规范
本规范适用于 Assets/Yarn/FP/ 下的维修流程脚本,包括:
FP_Huoshan1FP_Peipei1/FP_Peipei2/FP_Peipei3FP_Shitou1/FP_Shitou2FP_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 |
阶段内容节点 | 通常单出口 | 可含叙事文本、局部选项、小游戏指令 |
performance |
performance |
原子化线性演出节点 | 单出口 | timeline、cutscene 等,禁止选项 |
event |
event |
C# 调用的事件响应入口 | 单/多出口 <<jump>> |
仅轻量路由,禁止大段叙事 |
function |
function |
纯指令封装 | 禁止 <<jump>> |
仅 Command,无文本;命名加 _Func 后缀 |
end |
end |
维修结束/收尾 | 单出口 | 可含少量结束演出,最终必须 <<NextYarn>> |
附加标记(可附加到任何类型):
deprecated:已废弃节点,运行时不可达。wip:待编辑/占位节点,运行时不可达。no_save:该节点不可作为保存边界。即使节点类型通常允许保存(如content),附加此标签也表示此处不应触发保存。- 瞬跳节点:见 §8 瞬跳节点与存档边界。所有瞬跳节点均不可作为保存边界。
2. 命名规则
| 类型 | 命名示例 | 规则 |
|---|---|---|
start |
Start |
固定命名,首字母大写 |
init |
VarsInit、数据初始化 |
建议统一为 VarsInit;如项目已有 数据初始化,可保留但同一 project 内保持一致 |
center |
Center |
固定命名,每个维修 Yarn project 一个 |
content |
Stage1、开头对话、检查情绪、旋钮调节 |
阶段入口建议用 StageN;阶段内子节点用中文动宾/名词短语 |
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 的节点开始运行。它不属于任何功能类型,职责仅是启动流程。
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。
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 进行阶段调度。
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 节点
维修流程的核心单元,承载阶段中的实际内容:叙事、选项、小游戏指令等。
title: Stage1
tags: content
---
<<hide_dialog>>
<<switch_fix_system_to "Clinic">>
<<fade_out 1>>
<<jump 开头对话>>
===
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。
3.5 performance 节点
原子化线性演出节点,用于 timeline、cutscene 等必须完整播放的演出。
title: 地铁到站演出
tags: performance
---
<<hide_dialog>>
<<play_timeline 地铁到站>>
<<wait 2>>
<<jump 诊室外2>>
===
约束清单:
- 标签
performance。 - 禁止分支选项,必须单出口。
- 禁止叙事文本、角色台词与旁白;
- 保存点只能出现在
performance节点的开始之前或结束之后,节点内部不允许保存。 - 仅包含 timeline 播放、镜头运动、动画演出等线性指令。
3.6 event 节点
由 C# 代码调用的事件响应入口,负责把外部游戏事件映射到对应阶段节点。
title: EmoPlugIn
tags: event
---
<<jump 检查情绪>>
===
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 后缀。
title: Wave_Show_Func
tags: function
---
<<switch_emotion_wave_config "normal">>
<<show_emotion_wave 1>>
===
title: Wave_Hide_Func
tags: function
---
<<hide_emotion_wave 0.3>>
===
约束清单:
- 标签
function。 - 命名必须带
_Func后缀。 - 禁止任何叙事文本、对话、选项。
- 禁止任何
<<jump>>。 - 仅包含演出或小游戏相关的 Command。
3.8 end 节点
维修流程的收尾节点,负责结束当前脚本。
title: End
tags: end
---
<<fade_out 1>>
<<wait 1>>
me: 今天就到这里吧。 #line:xxxxxxxx
<<hide_dialog>>
<<wait 2>>
<<NextYarn>>
===
约束清单:
- 标签
end,建议同时附加no_save:维修流程已结束,控制权即将交还 C#,通常不应作为保存边界。 - 可含少量结束演出与收尾对话。
- 可能跳回center,也可能进入<>
- 不要在一个维修脚本里设置多个
end节点,除非剧情明确需要分支结局。
4. 控制流图
Start ──<<detour>>──> VarsInit / 数据初始化
│ │
│ │(自动返回 Start)
│ ▼
│ Start
│ │
▼ │
Center ◀─────────────────────┘
│
├──<<jump>>──> Stage1(content/performance 入口)
│ │
│ ├── content 子节点 ── ...
│ │
│ ├── 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 | performance | event | function | end |
|---|---|---|---|---|---|---|---|---|
| 是否包含叙事文本? | 禁止 | 禁止 | 禁止 | 允许 | 禁止 | 禁止 | 禁止 | 允许(少量) |
| 是否包含选项? | 禁止 | 禁止 | 禁止 | 允许 | 禁止 | 禁止 | 禁止 | 禁止 |
是否有 <<jump>>? |
仅一个出口 | 禁止 | 可多出口 | 通常一个出口 | 单出口 | 可有 | 禁止 | 最终 <<NextYarn>> |
是否修改 $gameStage? |
禁止 | 可初始化 | 禁止 | 允许 | 禁止 | 尽量避免 | 禁止 | 禁止 |
| 是否被 C# 调用? | 否 | 否 | 否 | 否 | 否 | 是 | 否 | 否 |
| 是否可作为保存边界? | 否 | 否 | 否(瞬跳) | 是(瞬跳 content 除外,须 no_save) |
仅开头/结尾(节点本身建议 no_save) |
否(可附加 no_save 强调) |
否 | 否(建议 no_save) |
7. 附加标记
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。 - 特殊
content节点:极少数剧情上明确不希望保存的content节点,可附加no_save覆盖默认可保存语义。
任何活跃节点不得 <<jump>> 到 deprecated / wip 节点,也不得在标记为 no_save 的节点处触发 OnNodeStart 自动保存。
7.2 Yarn 显式存档 <<save>>
用于节点末尾、状态已就位、即将进入无对话 / 纯 C# 交互阶段时的显式存盘点(OnNodeStart 无法覆盖的场景)。
<<play_timeline 地铁>>
<<hide_dialog>>
<<change_actor_state "turn" "地铁医生">>
<<save>>
<<detour 切换到诊所外>>
约定:
- 插入位置:所有需要进快照的状态命令之后;
<<jump>>/<<detour>>/load_scene之前(顺序即快照内容)。 - anchor:默认 omit(读档不重进 Yarn);依赖 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 与存档的关系
所有瞬跳节点均不得作为存档边界。 原因:
- 语义:存档点应对应玩家能感知的进度位置;瞬跳节点只是控制流中转,不是叙事/玩法上的「停点」。
- 实现:瞬跳节点常在同一帧内连跳(如
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或调整跳转结构。优先级可参考存档验证工具中误报节点(如 PeipeiUF检查状态)。
9. 设计原则
**start负责启动**:最小初始化 +<<detour>>调用init+ 唯一<<jump>>到Center。**init负责配置**:所有变量声明集中管理;无跳转出口,执行完毕后返回Start。**center负责调度**:打开center即可一览整个维修流程阶段;瞬跳、不可存。**content负责内容**:阶段之间的叙事、选项、小游戏交互隔离,便于单独调整。**performance负责原子化演出**:timeline、cutscene 等必须完整播放,保存边界清晰。**event负责桥接**:把 C# 事件翻译成 Yarn 内部跳转,不掺杂叙事。**function负责复用指令**:零文本零跳转,_Func后缀与梦境规范保持一致。**end负责收尾**:统一出口,统一<<NextYarn>>。