NarraLeaf

游戏

驱动运行中游戏的节点——开始与退出、推进对话、读写玩家偏好,以及管理存档与历史

Game 分类是蓝图与运行中剧情之间的接缝。这里的一切都在和活着的 NarraLeaf 运行时说话:游玩本身、屏幕上的对话、玩家的偏好、项目的本地存档,以及对话历史。标题画面、设置画面、存读档网格和对话记录界面,都由本页的节点搭起来

本页每一个节点都需要运行中的游戏。编辑器画布没有游戏:放在那里的 Game 节点会以该节点仅在游戏运行时可用,需在开发模式中运行失败,读取它的 Blueprint Value 预览为空。这些行为一律在开发模式中验证

约定

  • 基本上要么 pure 要么 latent。 四十四个节点是Pure,可以支撑 Blueprint Value。五十一个是Latent,Blueprint Value 一个都不提供。其余两个 Clear Visited 与 Post Notification 是例外:有副作用但同步,所以 Blueprint Value 和对待 latent 节点一样不提供它们,它们自己却不是 latent
  • Story Action 蓝图不提供。 由故事行调用的蓝图没有游戏宿主,因此它的创建浮窗里没有本页的节点,Get Build Variant 除外
  • 有 Host API 不等于有一局游戏。 List Saves、Get Save Metadata、Get Save Time、Get Save Line、Get Save Story、Get Save Playtime、Get Save Preview、Delete Save、List Auto Saves和Get Latest Auto Save读取项目的存档库,在两局游戏之间、没有游戏运行时也能工作。结局、走过的路线、DLC 与构建变体那几组读取节点同样如此——结局画廊本来就是从标题界面打开的,那时还没有任何游戏。凡是序列化、反序列化或指挥活动游戏的节点都需要一局游戏,没有就失败
  • 状态取值节点会降级,偏好取值节点不会。 每一个纯状态读取——Is In Game、Is Game Overlay、Get Nametag、Get Speaker Avatar、Get Speaker Color、Get Dialog Text、Is Narrator、Is Dialog Waiting、Get Choice Count、Get Notifications、Is NVL Mode、Is Text Read、Has Read Text、Can Undo History、Can Redo History、Get Track Volume、两个游玩时长读取,以及结局、走过的路线、DLC、构建变体与角色的那些读取——在什么都没有播放时都给出中性值:false、null、0、空数组,颜色给不透明白,音轨音量给 1。正因如此,同一个共享 Page 才能按它们分支,画廊的一行也才能把「锁住」的样子直接绑到引脚上。十八个偏好取值节点是例外:它们读的是活动GamePreference,没有游戏就失败。Is Dialog Shown 也是其中之一——它读的是 showDialog 偏好,只是名字按问题起而不是按键名起
  • 偏好初始化挂在On Game Ready上,不要挂App Boot。 App Boot可能早于LiveGame存在就运行,而没有活动游戏的偏好写入会失败。参见事件
  • 存档 id 会被校验。 id 会被 trim,不能为空,不能含路径分隔符或控制字符。磁盘上的文件名由 id 的哈希派生;你选的 id 保存在记录的 metadata 里
  • 部分节点在创建浮窗中按组列出。 浏览创建浮窗时,偏好一节的 Get … 节点合为一行获取偏好设置,Set … 节点合为一行修改偏好设置,Get Track Volume 和 Set Track Volume 各自单独一行;存档一节从 Get Save Metadata 到 Get Save Preview 的六个读取节点合为一行获取存档信息。搜索时每个节点按自己的名称列出;已放置的卡片可用标题旁的 ▾ 切换为同组的其他节点。见同类节点

游玩

Start Game和Quit Game是尾节点:它们把控制权交给运行时,没有执行出口,所以后续该发生的事属于剧情,或者属于它们打开的那个 Page

Start Game

blueprint.game.startStory · Latent

Start Game(开始游戏)启动节点卡片上选中的 Story 与 Scene,并切换到游戏舞台。游戏首帧就绪后,当前 Page 栈会被藏到游戏下面,因此之后调用Go Page是把目标叠加在舞台之上,而不是替换舞台

引脚方向类型说明
inin · exec—
storyIdin · datastring可选。连线优先于卡片
sceneIdin · datastring可选。连线优先于卡片——Import Progress 的 Scene 就接到这里
startBlockIdin · datastring可选,卡片上标作 From Row,只能连线。从该行进入场景,而不是从场景开头
inheritFromin · dataSaveSlot可选。新游戏要继承其进度的存档,见下文

卡片字段

字段含义
Story要运行的剧本。除非 storyId 已连线,否则必填
Scene要进入的场景。选项按选中的 Story 过滤。除非 sceneId 已连线,否则必填

十次里有九次作者要的是选择器:它列出项目自己的剧本,也拼不错。这几个引脚是为第十次准备的——写图的时候还不知道目标是哪一个,比如一个「继续」按钮要从玩家上次的位置接着走

接上 inheritFrom 时,游戏仍然从选中的场景开始新的一局,然后取入该存档的存档变量和其中走过的场景(即 Is Scene Visited 读取的那份记录)。舞台、对话记录和剧情位置不会被带过来;恢复这些是 Load Save 的事。Save Slot 带来存档库里的一份存档,用于从通关存档开始的二周目。Current Game 带来正在进行的这一局,用于在另一个故事里继续的路线。存档槽指向的存档不存在时,节点在剧情开始之前就失败

Quit Game

blueprint.game.quit · Latent

Quit Game(退出游戏)结束当前游玩,并打开卡片上选中的 Page。一次调用做完全部事情:丢弃活动游戏与会话、取消仍在等待的启动请求、打开 Page,然后清空对话名牌并恢复普通 Page 显示。不需要再接一个Go Page。Page 打开之前,屏幕上保留游戏的最后一帧,而 Is In Game 此时已经返回 false

引脚方向类型说明
inin · exec—
surfaceIdin · datastring可选,卡片上标为 页面 Id。连线优先于卡片

卡片字段

字段含义
Page游戏结束后打开的 Surface。除非 surfaceId 已连线,否则必填

Is In Game

blueprint.game.isInGame · Pure

Is In Game(是否在游戏中):只要游戏舞台可见且存在会话就为 true——即使上面开着 Page 叠层也一样。普通 Page 预览、首次Start Game之前、Quit Game之后为 false

引脚方向类型说明
isInGameout · databoolean

Is Game Overlay

blueprint.game.isGameOverlay · Pure

Is Game Overlay(是否为游戏覆盖层):当前 Surface 实例是否以游戏之上的 UI 叠层身份运行。Start Game或Load Save之后用Go Page打开的 Page 返回 true,游戏进行中用Show Layer显示的页面同样返回 true,内建的游戏 UI Surface(例如对话槽位)也返回 true;通过nl.frame嵌入的子 Page 继承父级的答案。普通应用 Page、游戏之外显示的叠加页面、Page 预览,以及Quit Game打开的那个 Page 返回 false

引脚方向类型说明
isGameOverlayout · databoolean

答案在 Page 或叠加页面实例创建时就锁定,所以正在播放退出动画的暂停菜单仍返回 true,哪怕Quit Game已经开始拆掉会话。要问运行时是否还在,用Is In Game;要问一个共享 Page 该显示成什么样,用这个

应用逻辑不属于任何 Surface,在应用逻辑中该节点回答的是游戏的状态,而不是某个页面的答案。游戏进行中,舞台上方画着页面或显示着模态叠加页面时返回 true;舞台上什么都没有,或只有非模态叠加页面(HUD、提示)时返回 false。答案在节点被求值的那一刻读取,应用逻辑发起的Call Fn得到同样的答案。不在游戏中时,应用逻辑读到的是当前页面自己的答案

推进剧情

Next

blueprint.game.next · Latent

Next(下一步)触发运行时的虚拟点击。有对话包装层暴露的点击目标时点它,把「打字中就先补完这句、已完成就进入下一步」的判断交还给引擎;没有对话目标时才退回去点播放器的主内容。它不会强制跳过

引脚方向类型说明
inin · exec—
nextout · exec—推进请求完成后触发

没有活动游戏运行时会失败

Skip

blueprint.game.skip · Latent

Skip(跳过)跳过当前对话。它是作者显式提供的 Skip 动作;默认对话模板不会替你绑定

引脚方向类型说明
inin · exec—
nextout · exec—

没有活动游戏运行时会失败

Select Choice

blueprint.game.choose · Latent

Select Choice(选择选项)按原始序号选择活动选择菜单中的选项。隐藏选项不会呈现给玩家,但仍然占据序号,所以菜单给出的序号不一定连续——请把选项自带的index接回来,而不是它在列表里的位置。宿主会重新校验目标的 hidden / disabled 状态,非法选择被静默拒绝

引脚方向类型说明
inin · exec—
nextout · exec—
indexin · datainteger必须是非负整数。支持卡片字面量

没有打开的选择菜单时会失败

Get Choice Count

blueprint.game.getChoiceCount · Pure

Get Choice Count(获取选项数量):活动选择菜单展示了多少个选项。隐藏选项不计入。菜单关闭后回到 0

引脚方向类型说明
countout · datainteger

对话

对话文本、说话人或完成状态变化时,绑定到对话的元素都会被 flush,因此在On Flush里读取下列取值节点的控件会随剧情推进保持最新,而不需要重新挂载

Get Nametag

blueprint.game.getNametag · Pure

Get Nametag(获取名牌):当前说话人的名字。旁白、没有说话人、说话人名为空或全是空白时为 null

引脚方向类型说明
nametagout · datastring没有说话人时为 null

默认对话模板把普通nl.text名牌的 text 绑定到一个 Blueprint Value:Init与On Flush接到Return Value,值由Get Nametag提供。这里没有任何特殊的名牌控件

Get Speaker Avatar

blueprint.game.getSpeakerAvatar · Pure

Get Speaker Avatar(获取说话人头像):说话角色的对话头像。引擎是从该角色的活的立绘上解析出来的,所以它天然反映角色当前穿着的差分,并且在撤销、读档、跳过之后依然正确。项目无法映射回资源的头像 URL 会解析为 null,而不是猜一个

引脚方向类型说明
avatarout · dataImageAsset|null可接给图片节点或图片 Blueprint Value

Get Dialog Text

blueprint.game.getDialogText · Pure

当前屏幕上那句话的文本。没有人在说话时为空字符串

引脚方向类型说明
textout · datastring

Get Speaker Color

blueprint.game.getSpeakerColor · Pure

说话角色的主题色,用来给名牌或姓名条上色

引脚方向类型说明
colorout · dataRGBAColor没有人说话时为不透明白。这个引脚是非空颜色,没有「缺省」可以承载

Is Narrator

blueprint.game.isNarrator · Pure

屏幕上这一句是旁白还是有角色在说。要为旁白整体换一套对话框外观,用它比对 Get Nametag 判空干净

引脚方向类型说明
isNarratorout · databoolean

Is Dialog Waiting

blueprint.game.isDialogWaiting · Pure

这一句是否已经打完字、正等玩家推进。「点击继续」的指示器绑的就是这个引脚

引脚方向类型说明
isWaitingout · databoolean没有宿主、屏幕上也没有句子时为 false——指示器必须在任何游戏存在之前就能排好版

Get Character

blueprint.game.getCharacter · Pure

项目里某一个角色的记录,在卡片上选。和上面三个「说话人」读取不同,它问的不是谁在说话——它是人物档案、好感度界面或者角色画廊用来画一个不在台上的人的那条路

引脚方向类型说明
nameout · datastring没选或角色已不存在时为空
characterColorout · dataRGBAColor没有记录时为默认色
characterAvatarout · dataImageAsset|null
foundout · databoolean

卡片字段

字段含义
Character项目里的某个角色

Is NVL Mode

blueprint.game.isNvlMode · Pure

Is NVL Mode(是否为 NVL 模式):游戏当前是否处于 NVL 模式

引脚方向类型说明
isNvlModeout · databoolean

Get Notifications

blueprint.game.getNotifications · Pure

Get Notifications(获取通知):运行时当前正在显示的通知,镜像自引擎的通知组件。没有通知时为空数组

引脚方向类型说明
notificationsout · dataarray<struct:nl.notificationItem>通知列表;字段见下

条目字段

字段含义
id通知 id
message通知文本

默认通知模板不使用该节点:它的列表项模板直接从项属性里读message

Post Notification

blueprint.game.postNotification

Post Notification(发送通知)在进行中的游戏里把 message 显示为通知,位置与游戏自身的提示相同:项目有通知插槽的游戏 UI 时,由它显示。通知关闭前,Get Notifications 会列出这条通知。通知显示后,链立即从 next 继续

没有进行中的游戏时节点报错,message 为空时也报错

引脚方向类型说明
inin · exec—
messagein · datastring显示的文字。支持卡片字面量
durationin · datafloat可选。通知停留的秒数,须大于 0;没有值时为 3。支持卡片字面量
nextout · exec—

Show Dialog

blueprint.game.showDialog · Latent

Show Dialog(显示对话框)把showDialog偏好设为 true,让对话 UI 重新显示。它只改运行时偏好——不改 UI 文档,也不推进剧情

引脚方向类型说明
inin · exec—
nextout · exec—

没有活动游戏运行时会失败

Hide Dialog

blueprint.game.hideDialog · Latent

Hide Dialog(隐藏对话框)把showDialog设为 false。隐藏期间对话包装层仍保留自己的交互语义,所以Next、Skip和之后的Show Dialog照常工作

showDialog只属于当前这次游玩。新游戏和每一次读档都按 项目 → 游戏 中 显示对话框 的设置开始,玩家隐藏的对话框不会带到下一次启动

引脚方向类型说明
inin · exec—
nextout · exec—

没有活动游戏运行时会失败

Toggle Dialog Display

blueprint.game.toggleDialogDisplay · Latent

Toggle Dialog Display(切换对话框显示)读取showDialog并写入相反值——一个 UI 控件配一个节点。它不碰别的:不碰对话文本、不碰名牌、不碰文字速度

引脚方向类型说明
inin · exec—
nextout · exec—

没有活动游戏运行时会失败

Is Dialog Shown

blueprint.game.isDialogShown · Pure

上面三个的读取那一半。它是顶着状态读取名字的偏好读取——它读的值就是 showDialog——所以没有活动游戏时它失败,而不是降级

引脚方向类型说明
isShownout · databoolean

偏好

下面每一对都对应活动游戏上引擎GamePreference的一个字段。取值节点是 pure 的,可安全放进 Blueprint Value;设值节点是 latent 的,写入前先校验——值不合法时节点失败,而不是被夹到范围内。showDialog在这里没有配对节点,由Show Dialog、Hide Dialog、Toggle Dialog Display和Is Dialog Shown覆盖

本节的设值节点在没有活动游戏运行时都会失败,取值节点也一样,只有 Get Track Volume 例外——它读的是引擎的混音器而不是GamePreference。要为新一局游戏播种偏好,把设值节点接在On Game Ready上——它在LiveGame已存在之后、第一句剧情之前运行

Get Sentence Speed

blueprint.game.getCps · Pure

Get Sentence Speed(获取文字速度)读取cps,即一句话逐字显示的每秒字符数

引脚方向类型说明
cpsout · datafloat

Set Sentence Speed

blueprint.game.setSentenceSpeed · Latent

Set Sentence Speed(设置文字速度)写入cps。必须是大于 0 的有限数字

引脚方向类型说明
inin · exec—
nextout · exec—
cpsin · datafloat支持卡片字面量

Get Text Fade In

blueprint.game.getTextRevealDuration · Pure

Get Text Fade In(获取文字渐入)读取textRevealDuration,单位毫秒:每个新打出的字淡入所需的时间。0 表示每个字一出现就完整显示。文字速度很快时,淡入会被缩短以跟上打字

引脚方向类型说明
textRevealDurationout · datafloat卡片上标为 文字渐入

Set Text Fade In

blueprint.game.setTextRevealDuration · Latent

Set Text Fade In(设置文字渐入)写入textRevealDuration。必须是大于等于 0 的有限数字,单位毫秒

引脚方向类型说明
inin · exec—
nextout · exec—
textRevealDurationin · datafloat卡片上标为 文字渐入。支持卡片字面量

Get Auto Forward

blueprint.game.getAutoForward · Pure

Get Auto Forward(获取自动前进)读取autoForward,即一句话播完后游戏是否自行推进

引脚方向类型说明
autoForwardout · databoolean

Set Auto Forward

blueprint.game.setAutoForward · Latent

Set Auto Forward(设置自动前进)写入autoForward。必须是布尔值

引脚方向类型说明
inin · exec—
nextout · exec—
autoForwardin · databoolean

Get Auto Forward Delay

blueprint.game.getAutoForwardDelay · Pure

读取autoForwardDelay,即自动前进在一句话打完之后要等多久才推进

引脚方向类型说明
autoForwardDelayout · datafloat

Set Auto Forward Delay

blueprint.game.setAutoForwardDelay · Latent

引脚方向类型说明
inin · exec—
nextout · exec—
autoForwardDelayin · datafloat支持卡片字面量

Get Skip

blueprint.game.getSkip · Pure

Get Skip(获取跳过)读取skip,即是否允许跳过

引脚方向类型说明
skipout · databoolean

Set Skip

blueprint.game.setSkip · Latent

Set Skip(设置跳过)写入skip。必须是布尔值

引脚方向类型说明
inin · exec—
nextout · exec—
skipin · databoolean

Get Skipping

blueprint.game.getSkipping · Pure

读取skipping,即此刻是不是正在跳过。上面的skip是「允许跳过」这个设置,这一个是状态

引脚方向类型说明
skippingout · databoolean

Set Skipping

blueprint.game.setSkipping · Latent

从图里开关跳过——一个会自锁的跳过按钮,而不是按住才跳的 Skip 动作

引脚方向类型说明
inin · exec—
nextout · exec—
skippingin · databoolean

Get Skip Read Text

blueprint.game.getSkipReadText · Pure

读取skipReadText,即跳过是否会在玩家没见过的那一句停下来。这里说的「读过」就是本页「已读文本」一节背后的那份记录

引脚方向类型说明
skipReadTextout · databoolean

Set Skip Read Text

blueprint.game.setSkipReadText · Latent

引脚方向类型说明
inin · exec—
nextout · exec—
skipReadTextin · databoolean

Get Skip Delay

blueprint.game.getSkipDelay · Pure

Get Skip Delay(获取跳过延迟)读取skipDelay,单位毫秒——玩家按住多久之后开始跳过

引脚方向类型说明
skipDelayout · datafloat

Set Skip Delay

blueprint.game.setSkipDelay · Latent

Set Skip Delay(设置跳过延迟)写入skipDelay。必须是大于等于 0 的有限数字,单位毫秒

引脚方向类型说明
inin · exec—
nextout · exec—
skipDelayin · datafloat支持卡片字面量

Get Skip Interval

blueprint.game.getSkipInterval · Pure

Get Skip Interval(获取跳过间隔)读取skipInterval,单位毫秒——跳过时两句之间的间隔

引脚方向类型说明
skipIntervalout · datafloat

Set Skip Interval

blueprint.game.setSkipInterval · Latent

Set Skip Interval(设置跳过间隔)写入skipInterval。必须是大于 0 的有限数字,单位毫秒

引脚方向类型说明
inin · exec—
nextout · exec—
skipIntervalin · datafloat支持卡片字面量

Get Game Speed

blueprint.game.getGameSpeed · Pure

Get Game Speed(获取游戏速度)读取gameSpeed,即全局速度倍率

引脚方向类型说明
gameSpeedout · datafloat

Set Game Speed

blueprint.game.setGameSpeed · Latent

Set Game Speed(设置游戏速度)写入gameSpeed。必须是大于 0 的有限数字

引脚方向类型说明
inin · exec—
nextout · exec—
gameSpeedin · datafloat支持卡片字面量

Get Global Volume

blueprint.game.getGlobalVolume · Pure

Get Global Volume(获取总音量)读取globalVolume,即其它所有声道都要乘上的总音量

引脚方向类型说明
globalVolumeout · datafloat

Set Global Volume

blueprint.game.setGlobalVolume · Latent

Set Global Volume(设置总音量)写入globalVolume。必须是大于等于 0 的有限数字

引脚方向类型说明
inin · exec—
nextout · exec—
globalVolumein · datafloat支持卡片字面量

Get BGM Volume

blueprint.game.getBgmVolume · Pure

Get BGM Volume(获取音乐音量)读取bgmVolume,即音乐声道

引脚方向类型说明
bgmVolumeout · datafloat

Set BGM Volume

blueprint.game.setBgmVolume · Latent

Set BGM Volume(设置音乐音量)写入bgmVolume。必须是大于等于 0 的有限数字

引脚方向类型说明
inin · exec—
nextout · exec—
bgmVolumein · datafloat支持卡片字面量

Get SFX Volume

blueprint.game.getSoundVolume · Pure

Get SFX Volume(获取音效音量)读取soundVolume,即音效声道

引脚方向类型说明
soundVolumeout · datafloat

Set SFX Volume

blueprint.game.setSoundVolume · Latent

Set SFX Volume(设置音效音量)写入soundVolume。必须是大于等于 0 的有限数字

引脚方向类型说明
inin · exec—
nextout · exec—
soundVolumein · datafloat支持卡片字面量

Get Voice Volume

blueprint.game.getVoiceVolume · Pure

Get Voice Volume(获取语音音量)读取voiceVolume,即语音声道

引脚方向类型说明
voiceVolumeout · datafloat

Set Voice Volume

blueprint.game.setVoiceVolume · Latent

Set Voice Volume(设置语音音量)写入voiceVolume。必须是大于等于 0 的有限数字

引脚方向类型说明
inin · exec—
nextout · exec—
voiceVolumein · datafloat支持卡片字面量

Get Voice Fade Duration

blueprint.game.getVoiceFadeDuration · Pure

Get Voice Fade Duration(获取语音淡出时长)读取voiceFadeDuration,单位毫秒——一句话结束时语音淡出所需的时间

引脚方向类型说明
voiceFadeDurationout · datafloat卡片上标为 Voice Fade

Set Voice Fade Duration

blueprint.game.setVoiceFadeDuration · Latent

Set Voice Fade Duration(设置语音淡出时长)写入voiceFadeDuration。必须是大于等于 0 的有限数字,单位毫秒

引脚方向类型说明
inin · exec—
nextout · exec—
voiceFadeDurationin · datafloat卡片上标为 Voice Fade。支持卡片字面量

Get Voice End Mode

blueprint.game.getVoiceEndMode · Pure

Get Voice End Mode(获取语音结束模式)读取voiceEndMode:一句话结束时仍在播放的语音该如何处理

引脚方向类型说明
voiceEndModeout · datastring"fade"、"stop"、"none" 之一

Set Voice End Mode

blueprint.game.setVoiceEndMode · Latent

Set Voice End Mode(设置语音结束模式)写入voiceEndMode。必须恰好是 "fade"、"stop" 或 "none"

引脚方向类型说明
inin · exec—
nextout · exec—
voiceEndModein · datastring支持卡片字面量

Get Mute When Unfocused

blueprint.game.getMuteOnWindowBlur · Pure

Get Mute When Unfocused(获取失去焦点时静音)读取muteOnWindowBlur:游戏窗口不是玩家正在使用的窗口时,游戏是否静音。玩家回来时声音按原来的音量恢复,期间任何音量偏好都不会改变

引脚方向类型说明
muteOnWindowBlurout · databoolean卡片上标为 失去焦点时静音

Set Mute When Unfocused

blueprint.game.setMuteOnWindowBlur · Latent

Set Mute When Unfocused(设置失去焦点时静音)写入muteOnWindowBlur。必须是布尔值

引脚方向类型说明
inin · exec—
nextout · exec—
muteOnWindowBlurin · databoolean卡片上标为 失去焦点时静音

Get Track Volume

blueprint.game.getTrackVolume · Pure

玩家给项目某一条音轨设的音量。混音器是项目自己声明的一棵音轨树——需要的话可以给每个角色一条音轨——而这一对正是「一条音轨一行」的设置界面的搭法

它是本节里的异类:值来自引擎的混音器而不是GamePreference,所以没有活动游戏它也不失败。没选音轨、或者没有东西可问时读作 1——绑在它上面的滑块会停在顶端,而不是在页面还没连完的时候塌到零

引脚方向类型说明
audioTrackIdin · datastring可选。连线优先于卡片
volumeout · datafloat没有指名音轨时为 1

卡片字段

字段含义
Track项目的某一条音轨

Set Track Volume

blueprint.game.setTrackVolume · Latent

引脚方向类型说明
inin · exec—
nextout · exec—
audioTrackIdin · datastring可选。连线优先于卡片
volumein · datafloat支持卡片字面量

卡片字段

字段含义
Track项目的某一条音轨

存档

存档是项目本地的,以你自己选的 id 为键。同一个 id 写第二次就是覆盖

下面每个针对单份存档的节点都有两种指定方式:id 引脚上的 id,或可选的 slot 引脚上的 SaveSlot。slot 连线时优先于 id。Save Slot 用 id 做出一个存档槽,一个 id 就能接给多个节点。Current Game 为正在进行的这一局做出存档槽,只有 Start Game 接受它;其他存档节点收到它都会失败

List Saves只返回玩家存档。自动存档住在保留 id 命名空间里——@autosave.<n>——由List Auto Saves列出;两个集合永不重叠。这是刻意的:基于List Saves做的存读档网格从不需要过滤掉 Studio 自己的簿记条目,自动存档界面也从不需要藏起玩家的存档位。在别的地方,自动存档 id 就是一个普通存档 id,可以原样喂给Load Save、Get Save Preview、Get Save Metadata和Delete Save

Save fields

一份存档携带两类数据。一类由引擎在每次存档时写入:存档将从哪一句继续、那句话由谁说出、以及时间戳。另一类由你决定,存档字段就是声明它的地方

从 Save Game 或 Get Save Metadata 卡片底部的按钮打开。每个字段有名称、类型和默认值

声明过的字段会成为具名引脚:在 Save Game 上是输入,在 Get Save Metadata 上是输出。这份列表属于项目,不属于打开它的那个节点,因此项目内所有存档节点显示的字段完全一致,一个字段只需声明一次

重命名字段只更换引脚标签,已有的连线全部保留。改变类型会重置它的默认值

行为结果
从声明该字段之前写下的存档中读取它该字段的默认值
删除字段已写入的值仍留在持有它们的存档文件中
会执行到的 Save Game 上,声明过的字段留空项目检查以 error 报告 blueprint/save-field-empty

两个节点上的 metadata 引脚都保留。在 Save Game 上,声明字段会覆盖写在它之上,因此同名的键以声明字段为准;在 Get Save Metadata 上,它仍然返回完整的存储对象

Save Game

blueprint.game.save.write · Latent

Save Game(保存游戏)把活动游戏序列化进项目的本地存档库。Capture为 true 时还会截一张舞台画面,缩小到缩略图尺寸后存为该存档的预览图;截图失败会被上报,但不会连累存档本身。页面盖住舞台时(例如从快捷菜单打开的存档页面),截下的是该页面打开那一刻的画面,包括对话框和快捷菜单

引脚方向类型说明
inin · exec—
nextout · exec—
idin · datastring支持卡片字面量
slotin · dataSaveSlot可选。连线时优先于 id
metadatain · datajson可选。任意 JSON——对象、数组、字符串、数字、布尔或 null。未接线时写入 null
screenshotin · databoolean可选。卡片上标为 Capture。支持卡片字面量
每个声明字段一个in · data该字段的类型以字段名标注。类型支持时可用卡片字面量

没有活动游戏会话时会失败

Load Save

blueprint.game.save.load · Latent

Load Save(读取存档)读入一份存档并为它放弃当前进度:清空 router 及其历史,创建新的游戏实例并反序列化;等 router 退出后,Page 栈重新被藏到舞台之下,所以这之后的Go Page打开的是游戏之上的叠层。在项目另一个故事里写下的存档,会在那个故事里打开

引脚方向类型说明
inin · exec—
idin · datastring支持卡片字面量
slotin · dataSaveSlot可选。连线时优先于 id
failedout · exec—存档缺失或损坏、当前构建的剧情里已没有存档所指的位置,或项目的旧存档设置拒绝它时走这一支。没有游戏运行时,节点直接失败

没有 next:读档成功就把正在跑的游戏整个换掉了,这张图也就没什么好接着跑的。failed 是它唯一的出口,也是游戏把这件事告诉玩家的那一支

Delete Save

blueprint.game.save.delete · Latent

Delete Save(删除存档)删掉一份存档。删一个本来就不存在的 id 也算成功,所以删除按钮不必先检查。它只需要项目的存档命名空间——不需要运行中的游戏

引脚方向类型说明
inin · exec—
nextout · exec—
idin · datastring支持卡片字面量
slotin · dataSaveSlot可选。连线时优先于 id

List Saves

blueprint.game.save.listIds · Latent

List Saves(列出存档)列出项目里玩家存档的 id。顺序不保证。损坏的、或 metadata 不是玩家存档的文件会被跳过,而不是报错。项目的旧存档设置不会恢复的存档也不列出,因此列出的每个 id 都能被 Load Save 接受。插件留给自己用的 id(例如 Quick Save 的存档位)同样不列出

引脚方向类型说明
inin · exec—
nextout · exec—
idsout · dataarray<string>

Get Save Metadata

blueprint.game.save.getMetadata · Latent

Get Save Metadata(获取存档元数据)读取一份存档的作者数据。每个声明字段各占一个引脚;metadata 引脚返回完整的存储对象,包含没有任何字段声明过的键。系统字段不属于两者:id、记录类型、createdAt、updatedAt 与预览图分别由Get Save Time和Get Save Preview读取

引脚方向类型说明
inin · exec—
nextout · exec—
idin · datastring支持卡片字面量
slotin · dataSaveSlot可选。连线时优先于 id
metadataout · datajson存档不存在或没有用户 metadata 时为 null
每个声明字段一个out · data该字段的类型以字段名标注。存档中没有该字段时给出它的默认值

Get Save Time

blueprint.game.save.getTime · Latent

Get Save Time(获取存档时间)读取一个槽位的写入时间。存档库会给每条写入的记录盖时间戳,该节点把它们读回来。存档界面无需再把时间写进自己的 metadata 并与之保持同步

引脚方向类型说明
inin · exec—
nextout · exec—
idin · datastring支持卡片字面量
slotin · dataSaveSlot可选。连线时优先于 id
savedAtout · datafloat槽位最后一次写入的时间。存档不存在时为 0
createdAtout · datafloat槽位首次写入的时间。存档不存在时为 0
existsout · databoolean

两个时间都是 1970 年 1 月 1 日 UTC 以来的毫秒数,与 List Auto Saves 报告的单位相同,Time 分类的每个节点都接受它

空槽位读 exists 判断。存档不存在时 savedAt 为 0,而 0 同时也是 1970 年的一个有效时刻

Get Save Line

blueprint.game.save.getLine · Latent

Get Save Line(获取存档语句)读取一份存档将从哪一句继续,以及那句话由谁说出。引擎每次序列化都会记下这两项,该节点把它们读回来。存档界面不必在存档时去读 backlog,再把最后一条写进自己的字段

引脚方向类型说明
inin · exec—
nextout · exec—
idin · datastring支持卡片字面量
slotin · dataSaveSlot可选。连线时优先于 id
lineout · datastring存档不存在,或存档写于任何对话播放之前时为空串
speakerout · datastring旁白,以及尚无对话的存档为空串
existsout · databoolean

它不是 backlog 的最后一条。backlog 记的是最后显示过的那一句,这两个字段记的是存档将从哪一句继续。从叠层界面存档,或在最后一句之后还执行了非对话动作时,两者并不相同

Get Save Story

blueprint.game.save.getStory · Latent

Get Save Story(获取存档故事)读取一份存档是在项目的哪个故事里写下的。读档界面用它按路线给存档位分组、排除某个故事的存档位,或标出来自另一个故事的存档位

引脚方向类型说明
inin · exec—
nextout · exec—
idin · datastring支持卡片字面量
slotin · dataSaveSlot可选。连线时优先于 id
storyNameout · datastring该故事在当前构建里的名称,因此存档之后改过名的故事读出的是现在的名称。当前构建不包含该故事时为空
storyIdout · datastring该故事的生成 id。改名后保持不变,因此分组与比较都用它,也可以接给 Start Game 的 storyId
existsout · databoolean

显示在屏幕上的应当是 storyName,不要显示 storyId。存档不存在,或存档写于存档开始记录故事之前,两者都为空;用 exists 区分这两种情况

Get Save Playtime

blueprint.game.save.getPlaytime · Latent

某个存档槽写下时,那一局已经玩了多久——存读档网格在缩略图下面写的那个「12 小时 34 分」

引脚方向类型说明
inin · exec—
nextout · exec—
idin · datastring支持卡片字面量
slotin · dataSaveSlot可选。连线时优先于 id
playtimeSecondsout · datafloat
playtimeMillisecondsout · datafloat
recordedout · databoolean在开始记录游玩时长之前写下的存档为 false——槽在,数字不在
existsout · databoolean

排版用 Time 里的 Format Duration

Get Save Preview

blueprint.game.save.getPreview · Latent

Get Save Preview(获取存档预览)把存档里的截图变成当前会话内可用的ImageAsset。这张图不会导入项目资源库;直接接给Set Image Asset或图片 Blueprint Value 即可

引脚方向类型说明
inin · exec—
nextout · exec—
idin · datastring支持卡片字面量
slotin · dataSaveSlot可选。连线时优先于 id
previewout · dataImageAsset|null存档不存在或没有截图时为 null

Save Slot

blueprint.game.save.slot · Pure

Save Slot(存档槽)按 id 指定存档库里的一个存档槽。把它接到各存档节点的 slot 引脚上:存档界面的一行要从同一个存档槽读取时间、语句和预览图时,id 只需写一次

引脚方向类型说明
idin · datastring支持卡片字面量。id 为空时节点失败
slotout · dataSaveSlot

Current Game

blueprint.game.save.currentRun · Latent

Current Game(当前游戏)把正在进行的这一局捕获为一个存档槽,不往存档库写任何东西。它是给 Start Game 的 inheritFrom 引脚用的:捕获这一局,再用它开始下一个故事,玩家的存档变量与走过的场景就会被带过去

捕获只在捕获它的那次事件执行期间有效。同一条执行链后面的 Start Game 可以使用它,之后由别的事件运行的图则不能。除 Start Game 外,其他存档节点收到它都会失败

引脚方向类型说明
inin · exec—
nextout · exec—
slotout · dataSaveSlot

没有正在进行的游戏时失败;同一次图执行里已经捕获过八次时也会失败

自动存档

自动存档按项目配置,位置在项目 → 游戏:开关、间隔,以及环保留多少个槽位。它随项目一起发布。图里不排任何日程——调度器自己在跑,并且只在剧情自上次写入以来推进过时才写,所以间隔再短,闲置的游戏也不产生开销。写入沿环轮转,最旧的先被覆盖,因此一直自动存档也只占用有界的磁盘

Auto Save

blueprint.game.autoSave.write · Latent

Auto Save(自动保存)立刻写一次自动存档,落在调度器所用的同一个环的下一个槽位,并附带截图。它同时忽略开关设置和「剧情已推进」这道门——这一次是作者显式要求的——写完之后与定时产生的自动存档没有任何区别。执行继续:自动存档不会打断正在进行的游玩

引脚方向类型说明
inin · exec—
nextout · exec—

没有正在运行的游戏时会失败,与其它存档写入节点一致

List Auto Saves

blueprint.game.autoSave.list · Latent

List Auto Saves(列出自动存档)列出保留命名空间里的全部自动存档,从新到旧。调小环容量后遗留的槽位仍会被列出——改配置不该让玩家的存档凭空消失——只是不会再被轮转覆盖

引脚方向类型说明
inin · exec—
nextout · exec—
entriesout · dataarray<struct:nl.saveEntry>存档条目列表;字段见下
countout · datainteger

条目字段

字段含义
id存档 id。可直接喂给Load Save、Get Save Preview、Get Save Metadata和Delete Save
slot在环内的槽位序号
timestamp最后写入时间,Unix 毫秒
createdAt首次写入时间,Unix 毫秒
preview该存档位的图片,与 Get Save Preview 返回的相同。没有时为 null
line该存档位停在的那一句,与 Get Save Line 读到的相同。存档写于任何对话播放之前时为空串
speaker那句话由谁说出。旁白,以及尚无对话的存档为空串
metadata写入方附带的内容,没有时为 null

条目带的是 id,而不是序列化后的存档:SavedGameData 那样的数据块在图里毫无用处,而 id 能直接接进既有的存档节点

Get Latest Auto Save

blueprint.game.autoSave.latest · Latent

Get Latest Auto Save(获取最新自动存档)取最新的一条自动存档。这是「继续游戏」按钮的专用节点——等价于List Auto Saves的第一条,省掉取下标和取字段那几个节点

引脚方向类型说明
inin · exec—
nextout · exec—
idout · datastring没有自动存档时为空字符串
hasAutoSaveout · databoolean接上它来禁用「继续」
timestampout · datafloat最后写入时间,Unix 毫秒。没有自动存档时为 0

历史

对话历史——也就是对话记录——是引擎自己保存的、已经过去的台词与选择菜单,并且可以回放到其中任意一点

它是一条带播放头的时间线,这七个节点就是它的两侧。Get History 是播放头之前的一切:已经读过的台词,按顺序。往回退会移动播放头,被它退过去的那些台词就成了未来,Get Future History 返回它们,Redo Next History Entry 再走回去。Can Undo History 与 Can Redo History 则是对话记录界面上那两个按钮据以禁用自己的东西

Get History

blueprint.game.history.get · Latent

Get History(获取历史)把对话记录作为一个扁平数组给出,从旧到新,可以直接绑到列表控件上

引脚方向类型说明
inin · exec—
nextout · exec—
entriesout · dataarray<struct:nl.historyEntry>历史记录条目列表;字段见下
countout · datainteger

条目字段

字段含义
id历史 token。喂给Restore From History
type台词为 "say",已确定的选择为 "menu"
text句子文本,或菜单的提示语。源里没有时为空字符串
charactersay 条目的说话人名牌;菜单与旁白为 null
avatar说话人的对话头像,取自角色本身的图片,而不是那一句时所穿的差分。菜单、旁白,以及项目里没有对应角色的说话人为 null
voicesay 条目的语音文件 URL;没有时为 null。图里没有节点接受它;要重播一句,用 voiceId
voiceId这一句的 voice id,可接给 Play Voice。这一句的语音不是来自项目的录音时为 null
selectedmenu 条目里被选中的选项文本;say 条目与未确定的菜单为 null
isPending当前还在屏幕上、尚未提交的那一条为 true

没有游戏运行时为空数组

Restore From History

blueprint.game.history.restore · Latent

Restore From History(从历史恢复)把游戏跳回某一条对话记录,丢弃它之后的一切。引擎允许时按该条目的快照恢复,否则退回到 undo——正因如此,它在刚刚读档、undo 栈是空的游戏上依然有效

引脚方向类型说明
inin · exec—
nextout · exec—
idin · datastring卡片上标为 Entry Id。必填;空 id 会让节点失败。支持卡片字面量

没有活动游戏运行时会失败

Undo Last History Entry

blueprint.game.history.undoLast · Latent

Undo Last History Entry(撤销上一条历史)回退一条——即不带目标的Restore From History。它就是对话记录界面上的「返回」按钮

引脚方向类型说明
inin · exec—
nextout · exec—

没有活动游戏运行时会失败

Redo Next History Entry

blueprint.game.history.redoNext · Latent

走进那些撤销造出来的未来——「返回」旁边的那个「前进」。用别的方式推进剧情会把那个未来丢掉,这正是它是 redo 而不是第二个 Next 的原因

引脚方向类型说明
inin · exec—
nextout · exec—

没有活动游戏运行时会失败

Get Future History

blueprint.game.history.getFuture · Latent

播放头之前方的那些条目,形状与 Get History 给出的相同。想让玩家看见自己退回来之前走到哪的对话记录界面,把它绑到第二个列表上

引脚方向类型说明
inin · exec—
nextout · exec—
entriesout · dataarray<struct:nl.historyEntry>条目字段与 Get History 相同
countout · datainteger

没有游戏在跑时、以及什么都没退过时,都是空数组

Can Undo History

blueprint.game.history.canUndo · Pure

引脚方向类型说明
canUndoout · databoolean没有游戏在跑时为 false

它是 pure 的,所以能直接支撑 Blueprint Value:把返回按钮的 enabled 绑上去,它就会在记录开头自己变灰,而不必每帧跑一张图

Can Redo History

blueprint.game.history.canRedo · Pure

引脚方向类型说明
canRedoout · databoolean没有游戏在跑时为 false

已读文本

一句话在文字显示完毕的那一刻被标为已读——ADV 下是打字结束,NVL 下是等待推进。记录以这一行的单元 ID 为键,因此能挺过剧本改动,并且跨越项目里的每一个 Story;它按项目级持久化,与任何存档文件无关。「只跳过已读文本」这类选项就建立在它之上

Is Text Read

blueprint.game.isTextRead · Pure

Is Text Read(文本是否已读):当且仅当屏幕上有一句对话并且它的消息被标为已读时为 true——要么早先的游玩里见过,要么刚刚显示完毕。没有台词在显示时为 false

引脚方向类型说明
isReadout · databoolean

Clear Text Read

blueprint.game.clearTextRead · Latent

Clear Text Read(清除已读记录)清空已读记录,内存与磁盘一起清,覆盖项目里的每一个 Story。仍在屏幕上、且已经显示完毕的那一句会立刻重新标为已读——玩家正看着它

引脚方向类型说明
inin · exec—
nextout · exec—

Has Read Text

blueprint.game.isTextReadById · Pure

指定的某一句是否被读过,按它的单元 ID 来问,而不是问屏幕上那一句。上面的 Is Text Read 回答的是当前这句;这一个回答的是玩家此刻并没有在看的某一句,那正是额外内容界面或语音画廊需要的

引脚方向类型说明
textIdin · datastring这一行的单元 ID,即该行属性中的单元 ID。支持卡片字面量
isReadout · databooleanid 为空时为 false,于是连了一半的画廊行只是保持锁住,而不是把整页带垮

游玩时长

Get Playtime

blueprint.game.getPlaytime · Pure

当前这一局已经玩了多久。两个引脚是同一个数字的两种单位,于是要排版小时的界面和要按毫秒算数的界面各取所需

引脚方向类型说明
playtimeSecondsout · datafloat
playtimeMillisecondsout · datafloat

没有东西在计时时为 0——在任何一局开始之前,标题界面问「这一局玩了多久」是一个有真实答案的正当问题,而故事预览根本就没有秒表

Get Total Playtime

blueprint.game.getTotalPlaytime · Pure

在这个项目上一共花过多少秒,跨越每一次游玩。通关界面写的是这个数,暂停菜单写的是 Get Playtime

引脚方向类型说明
totalPlaytimeSecondsout · datafloat
totalPlaytimeMillisecondsout · datafloat

路线进度

Is Scene Visited 与 Is Option Picked 读的是剧情编译器随玩家推进写下的那份记录。它存在存档里,因此会随读档一起回退——它回答的是「在这一局里我走过这条路线没有」,一次性选项和剧情中途的解锁要的就是这个。下面的结局记录恰好相反,存在项目持久化里

两个读取节点都是 pure 的,所以画廊的一行可以把「锁住」的样子直接绑到引脚上,而不必每行跑一张图;id 为空时回答「没有」,而不是抛错

它不是 Has Read Text。已读记录是在一句话被显示时写下的,所以玩家只是打开过的菜单里的每个选项都算读过。Is Option Picked 是在选中的那一刻写下的

Is Scene Visited

blueprint.game.isSceneVisited · Pure

引脚方向类型说明
storyIdin · datastring可选。连线优先于卡片
sceneIdin · datastring可选。连线优先于卡片
isVisitedout · databoolean

卡片字段

字段含义
Story要问的剧本
Scene场景,按该剧本过滤

十次里有九次用选择器就够了。这两个引脚是为第十次准备的:一张画廊卡放一次、从自己的参数里读出自己是哪个场景,而不是一个场景复制一张卡

Is Option Picked

blueprint.game.isOptionPicked · Pure

引脚方向类型说明
storyIdin · datastring可选。连线优先于卡片
optionIdin · datastring可选。连线优先于卡片
isPickedout · databoolean

卡片字段

字段含义
Story要问的剧本
Option一个选项,按该剧本过滤

Clear Visited

blueprint.game.clearVisited

把两份记录都清空。它有副作用但不是 latent——它在这一 tick 内清掉活动 Storable 里的两个键,不像 Clear Text Read 要写宿主持久化、必须被等待

引脚方向类型说明
inin · exec—
nextout · exec—

结局

剧本里的一行 /ending 就是完整的声明,它的 block id 就是这里一切据以索引的身份。这四个节点是结局界面的搭法:玩家找到了哪些,以及全集是什么、好把它们摆开来对照

结局记录存在项目持久化里而不是存档里,没有任何东西会让它回退。结局界面问的是这个玩家曾经见过什么,所以建在存档记录上的画廊会在有人读了旧档之后当着他的面重新锁上条目,「8 个里的 5 个」会变少。这也意味着这四个节点都不需要正在运行的剧情——结局画廊本来就是从标题界面打开的

Is Ending Reached

blueprint.game.isEndingReached · Pure

引脚方向类型说明
isReachedout · databoolean没选结局时为 false,于是连了一半的行保持锁住

卡片字段

字段含义
Story要问的剧本
Ending该剧本里声明的一个结局

Get Endings

blueprint.game.getEndings · Pure

该剧本声明的全部结局,不论是否已达成——画廊摆开、并据以计数的那个全集

引脚方向类型说明
endingsout · dataarray<struct:nl.ending>结局列表;字段见下。没选剧本时为空

卡片字段

字段含义
Story要列出结局的剧本

结局字段

字段含义
endingId结局的 id
name结局的名称,即 /ending 行上写的名称
sceneId、sceneName结局行所在的场景
isReached玩家是否已到达该结局

用 Get Field 读取字段,或从 endings 拖出连线,按字段筛选、排序或查找,见结构

Clear Ending State

blueprint.game.clearEndingState · Latent

把一个结局重新锁上

引脚方向类型说明
inin · exec—
nextout · exec—

卡片字段

字段含义
Story要问的剧本
Ending要忘掉的那个结局

Clear Endings

blueprint.game.clearEndings · Latent

把它们全部重新锁上。两个清除节点都要写宿主持久化,所以都是 latent

引脚方向类型说明
inin · exec—
nextout · exec—

版本与额外内容

Get Build Variant

blueprint.game.getAppTag · Pure

这个包是项目的哪一个变体。

它是整份目录里唯一一个在游戏存在之前就已经定下值的节点。一次构建产出一个变体,它的名字在这里被代入,消费它的那次比较被折叠,这一版不走的那条分支被删除——于是变体判断背后的内容是从包里不存在,而不只是在包里到不了。如果一张图里的 Get Build Variant 最终没有决定任何分支,它会在构建闸门上被拒绝,每一种构建包括正式版都是如此:这里没有可以退回去的运行期值,所以这样的图不是一个可以容忍的泄漏,而是根本编译不出来

这也是它不收任何输入、也没有卡片字段的原因。能给它的任何东西,都是给一个已经只有一个答案的问题再加一个输入

引脚方向类型说明
appTagout · datastring变体的名字。完整正式版是 main

Is DLC Installed

blueprint.game.isDlcInstalled · Pure

某一份额外内容此刻是不是就在运行中的游戏旁边。

这个问题问的刻意是在不在,而不是有没有买。DLC 是作为一个文件出现在游戏旁边的,是玩家从哪里买的、哪里就把它放过来;它在不在,是这个包看得见的事实。玩家是否拥有它,是商店的事实、是商店插件的节点去回答的——而拿它来挡内容,会在玩家离线时把他买过的章节夺走,问「在不在」永远不会

引脚方向类型说明
isInstalledout · databoolean没选 DLC 时为 false,于是连了一半的菜单行保持隐藏

卡片字段

字段含义
DLC项目声明的某一个 DLC

在版本之间携带进度

试玩版和完整版是两个独立的包、两个独立的 app id,因此各有各的用户数据目录,资产保护密钥也刻意不同:正式版读不了试玩版的存档文件,也不该去读。这两个节点就是那条确实跨过去的通道,而且它刻意不是一个存档文件——它是每个作品一份的普通 JSON 文档,装着项目级变量、玩家走到哪里,以及他见过哪些场景

那份文档放在哪里由执行这件事的宿主决定,绝不由图决定:桌面宿主把这件事交给自己的主进程,Web 导出则拒绝,因为一个网页没有共享文件可写。所以两个节点都带一条失败分支和一个原因,图必须听得懂「不行」

Export Progress

blueprint.game.progress.export · Latent

把这一局持有的一切写进该作品的进度文档。它不收任何输入:跨过去的是项目声明的那一整套,而不是某一张图替另一个版本必须能读的文档挑出来的一个子集

引脚方向类型说明
inin · exec—
nextout · exec—
failedout · exec—写不了的宿主、没有进度键的构建,或者磁盘拒绝了
errorout · datastring是其中哪一种

Import Progress

blueprint.game.progress.import · Latent

读那份文档,并把它持有的内容应用到运行中的游戏上。

它不会跳转。 Scene 只是作为数据交出来,节点就停在这里。启动剧情的是 Start Game,而标题界面通常还有别的事要先做——一次淡出、一次确认、一个章节选择。一个自己就跳过去的节点,会成为绕开这一切的第二种开始剧情的方式

引脚方向类型说明
inin · exec—
foundout · exec—
missingout · exec—没有人导出过
failedout · exec—读不出来的文档
sceneIdout · datastring玩家走到了哪里。文档没有锚点时为空。接给 Start Game
errorout · datastring

三条出路,因为作者对三者的回答不一样。Missing 是所有从没导出过的人的常态——全新安装、直接买完整版的玩家——它通向「开始新游戏」,而不是一句道歉;把它并进 Failed 会让每一个第一次玩的人先看到一个错误。Failed 是读不出来的文档:更新的构建写的、属于别的作品的,或者已经损坏

存储

Check Storage Durability

blueprint.game.storageDurability · Latent

这个构建写下去的东西留不留得住——关于玩家存档,唯一一件宿主知道而游戏自己推不出来的事。

打包的桌面游戏把文件放在没人会去回收的用户数据目录里。Web 导出则是浏览器的客人:一个没有拿到持久化存储授权的站点,可能在存储压力下被整体清除,存档、持久变量和已读记录一起没。页面在加载时申请那份授权,而这里给出的就是它得到的答复

引脚方向类型说明
inin · exec—
durableout · exec—
evictableout · exec—
unknownout · exec—

三条分支,因为它们通向三种不同的措辞。Evictable 是「这个浏览器可能会删掉存档」;Unknown 是浏览器不肯说,而在真相是后者时告诉玩家前者,是一个没人许下过的承诺。这里不替你做任何决定——存储可能被回收的页面,仍然是一个能把游戏打通的页面,而玩家要不要听说这件事,属于作品本身

本页目录

约定游玩Start GameQuit GameIs In GameIs Game Overlay推进剧情NextSkipSelect ChoiceGet Choice Count对话Get NametagGet Speaker AvatarGet Dialog TextGet Speaker ColorIs NarratorIs Dialog WaitingGet CharacterIs NVL ModeGet NotificationsPost NotificationShow DialogHide DialogToggle Dialog DisplayIs Dialog Shown偏好Get Sentence SpeedSet Sentence SpeedGet Text Fade InSet Text Fade InGet Auto ForwardSet Auto ForwardGet Auto Forward DelaySet Auto Forward DelayGet SkipSet SkipGet SkippingSet SkippingGet Skip Read TextSet Skip Read TextGet Skip DelaySet Skip DelayGet Skip IntervalSet Skip IntervalGet Game SpeedSet Game SpeedGet Global VolumeSet Global VolumeGet BGM VolumeSet BGM VolumeGet SFX VolumeSet SFX VolumeGet Voice VolumeSet Voice VolumeGet Voice Fade DurationSet Voice Fade DurationGet Voice End ModeSet Voice End ModeGet Mute When UnfocusedSet Mute When UnfocusedGet Track VolumeSet Track Volume存档Save fieldsSave GameLoad SaveDelete SaveList SavesGet Save MetadataGet Save TimeGet Save LineGet Save StoryGet Save PlaytimeGet Save PreviewSave SlotCurrent Game自动存档Auto SaveList Auto SavesGet Latest Auto Save历史Get HistoryRestore From HistoryUndo Last History EntryRedo Next History EntryGet Future HistoryCan Undo HistoryCan Redo History已读文本Is Text ReadClear Text ReadHas Read Text游玩时长Get PlaytimeGet Total Playtime路线进度Is Scene VisitedIs Option PickedClear Visited结局Is Ending ReachedGet EndingsClear Ending StateClear Endings版本与额外内容Get Build VariantIs DLC Installed在版本之间携带进度Export ProgressImport Progress存储Check Storage Durability