流程规则与游戏动作
这些规则用于帮助你编写脚本或使用社区接入方案。JSON 包含数据,而非可执行源码。编辑器中的布局、选择状态和内部界面排列不会控制游戏。
在第一步之前
检查 format = vnle.story、containerVersion = 1,以及受支持的 execution.contractVersion 和 requiredCapabilities。示例使用 1.1,能力为 core.v1 和 substory.call-return.v1。JSON Schema 检查结构;执行时还需要检查引用、类型和命令是否受支持。遇到未知节点类型时,不能默默跳过。
各节点的作用
| kind | 行为 |
|---|---|
dialogue | 显示文本,等待 Continue,然后按 continuation 继续。 |
choice | 按 optionOrder 排列选项,以 option.condition 筛选,将选中选项的 effects 应用一次,然后按 continuation 继续。没有可用选项时遵循 whenEmpty。 |
branch | 判断 condition,然后进入 whenTrue 或 whenFalse。 |
action | 按顺序执行 effects,然后按 continuation 继续。 |
jump | 跳转到目标入口,不新增返回点。 |
call | 记住 continuation,然后进入目标入口。 |
return | 恢复最近保存的 continuation。没有对应 Call 的 Return 属于错误。 |
command | 计算参数,请求游戏动作,等待结果,然后进入匹配的结果分支。 |
end | 结束当前整段对话,即使当前位于子故事内。Return 则会回到调用方。 |
条件与带类型的值
操作数可以是 literal(带类型的固定值),也可以是 variable(通过 variableRef 引用变量)。compare 支持 eq、ne、lt、lte、gt、gte。all 要求所有子条件成立,any 要求至少一个成立,not 对子条件取反。请勿将布尔值与字符串 "true"/"false" 混淆。
变量操作包括 set、add 和 subtract。add/subtract 使用 −2147483648 至 2147483647 范围内的整数。按顺序计算操作,但若任何操作无效,不得只提交一部分更新。不要在每次对话开始时用初始 defaultValue 覆盖已保存的值。
Jump · 购买后前往仓库
跳转
已购买钥匙时,直接跳转到 Warehouse 入口。target 包含 flowRef 和 entryRef;execution.entries[entryRef].nodeRef 给出下一个节点。Jump 不会自动打开引擎场景或地图,这需要通过相应的游戏动作实现。
{
"flowRef": "1f69a7b6-1bdc-4dff-b8ee-9b2819b35168",
"id": "2e1710dc-c32f-418f-abca-e055d6fd28f3",
"kind": "jump",
"target": {
"entryRef": "a4dd48dc-b0e2-47fc-b102-def52583a8fe",
"flowRef": "2a0a259c-b76a-4de0-8cee-567713c2d320"
}
}Call Substory / Return · 米拉介绍仓库
调用子故事/返回
是的,这段流程由 JSON 描述。问候之后,故事会调用锁着的仓库的说明。游戏将 continuation 压入栈,然后进入 target。米拉说明完毕后到达 return,取出最近保存的 continuation,并执行 Already have the key?。嵌套调用遵循相同规则。
{
"continuation": {
"kind": "node",
"nodeRef": "95e9a55f-f6b1-4696-9c52-6ea3ea2ac7e5"
},
"flowRef": "1f69a7b6-1bdc-4dff-b8ee-9b2819b35168",
"id": "85b3aadf-2b95-4150-bc44-c0c796337874",
"kind": "call",
"target": {
"entryRef": "2bac8555-3cae-4a21-9b8c-b410ab207ebb",
"flowRef": "ea13b52e-092a-44ff-b087-0ce65d040c9a"
}
}{
"flowRef": "ea13b52e-092a-44ff-b087-0ce65d040c9a",
"id": "f8b8673a-cb86-40ae-a4f6-d37a5c1563c3",
"kind": "return"
}相关节点全部包含在导出的 story.json 中。Call 并不表示加载另一个 JSON 文件或脚本。maxCallDepth 限制嵌套深度。对空栈执行 Return 属于错误;End 则会结束整段对话并清空栈。
Command · 打开商店或给予钥匙
命令
“打开商店”是一个合适的例子:游戏打开自己的商店界面并暂停对话,只有商店界面关闭后才报告约定的结果,例如 purchased 或 cancelled。请在该 VNLE 项目中将这些名称和参数定义为游戏动作;open_shop 不是 VNLE 内置命令。
实际的港口导出数据使用 give_item:命令引用一个定义,提供物品 ID,并包含两个结果。游戏将钥匙加入背包,或拒绝接收。作者已经为这两种结果分别定义了后续路径。
{
"arguments": {
"3cac6185-4404-4a2a-be5f-14afa0f97137": {
"kind": "literal",
"value": {
"entityType": "item",
"type": "reference",
"value": "2d71e57e-9b58-4fdb-a33f-42b89bd8bf04"
}
}
},
"commandRef": "0723beb0-daba-4602-a665-4efc27511bc3",
"flowRef": "1f69a7b6-1bdc-4dff-b8ee-9b2819b35168",
"id": "500c28a1-ed85-4c36-9a38-bedacce1c6b7",
"kind": "command",
"outcomes": {
"12bc86a9-b2eb-4eb4-836c-a9efd936bf1b": {
"continuation": {
"kind": "node",
"nodeRef": "382640aa-5b50-4715-9148-b470bc2f7cd6"
},
"resultBindings": {}
},
"1c527580-69a6-4e99-8503-1b0de3fc8e78": {
"continuation": {
"kind": "node",
"nodeRef": "221d6b0c-99e1-45a8-bc73-768c4ee679eb"
},
"resultBindings": {}
}
}
}{
"id": "0723beb0-daba-4602-a665-4efc27511bc3",
"key": "give_item",
"name": "Give item",
"category": "custom",
"inputs": [
{
"id": "3cac6185-4404-4a2a-be5f-14afa0f97137",
"name": "Item",
"valueType": {
"entityType": "item",
"kind": "reference"
}
}
],
"outcomes": [
{
"id": "12bc86a9-b2eb-4eb4-836c-a9efd936bf1b",
"name": "Received",
"results": []
},
{
"id": "1c527580-69a6-4e99-8503-1b0de3fc8e78",
"name": "Declined",
"results": []
}
]
}- 在 execution.commands 中通过 commandRef 查找命令签名,在 content.commandDefinitions 中查找可读的键。
- 通过输入 ID 计算参数。缺少可选参数时,使用其声明的 defaultValue。
- 仅请求一次明确受支持的游戏动作。等待期间,禁止 Continue 或重复执行。
- 验证结果 ID 和带类型的结果值。outcome.resultBindings 将结果值赋给故事变量,然后按 outcome.continuation 继续。
- 技术故障不等同于作者定义的取消结果。请显示错误,并在游戏中提供受控的重试或取消路径。
在此项目中,如果背包拒绝接收钥匙,后续流程会退还五枚金币。这由导出的 continuation 实现,并非每个 Command 都会自动退款。背包、任务日志和引擎地图属于你的游戏系统,仅有 JSON 内容记录不会自动创建这些系统。
占位符 · “你还剩 5 枚金币”
文本和占位符
{
"continuation": {
"kind": "node",
"nodeRef": "2e1710dc-c32f-418f-abca-e055d6fd28f3"
},
"flowRef": "1f69a7b6-1bdc-4dff-b8ee-9b2819b35168",
"id": "0d7f959e-8fba-4882-ae98-b66d8416d4d2",
"kind": "dialogue",
"speakerRef": "807b2957-7bab-4a28-83a4-1f3d1589bbc2",
"text": {
"bindings": {
"1084cf8e-515e-4b33-92f8-b5c260e88a9e": {
"kind": "variable",
"variableRef": "a547610e-661f-4b8d-a25b-21d042f1a2d5"
}
},
"textRef": "fcc775ff-558e-4a41-823d-183aaff03e4b"
}
}直接拼接 kind: text 片段。对于 kind: placeholder,通过 placeholderRef 查找文本记录中的定义和 node.text.bindings 中的绑定。绑定提供固定值或变量值。在显示该句时获取值,并按类型格式化。类型和格式选项见字段参考。
进度、限制与错误
将当前位置、故事变量、返回栈和待完成的游戏动作与游戏状态一起保存。语言是独立的游戏设置。storyBuildId 用于将存档与对应的执行版本关联;对于不兼容的故事版本,不要猜测后续路径。
maxAutomaticTransitions、maxConditionDepth、maxConditionTerms 和 maxCallDepth 限制自动执行或深度嵌套的流程。缺失引用、whenEmpty: fault 且没有可用选项、未知命令和无效类型都需要明确报错。重新绘制界面绝不能重复购买或重复修改变量。
交给开发者或 AI 接入
提供实际导出文件、引擎版本、目标平台、这些流程规则和对应引擎文档。说明界面元素及现有背包或商店功能。要求对方使用实际的 JSON 字段和有文档依据的引擎 API,并测试以下情况。
- 十枚金币:获得钥匙,剩五枚金币;两枚金币:不获得钥匙,也不扣钱。
- 背包拒绝接收:按故事流程退款,不得假报成功。
- Call/Return 回到预定节点;Call 内的 End 结束整段对话。
- 切换语言后保留进度;缺失译文和有意留空的文本均能正确处理。
- 随游戏发布的 JSON、图片和字体在开发目录之外也能使用;图片缺失时不会继续显示上一张立绘。