-
Notifications
You must be signed in to change notification settings - Fork 78
Restoration
woctordho edited this page Feb 5, 2022
·
36 revisions
- 保存和读取各种前端组件(图片、BGM等)的状态
- 在对话中设置变量,用变量控制剧情分支,在读档时恢复变量
- 在小游戏中设置变量,此时变量取决于玩家输入
- 在章节选择界面、文本回顾界面、流程图界面中跳转到一条已经到达过的对话
- 读档时恢复文本回顾界面的内容
- 在文本回顾界面中回跳时,恢复更早的文本
- TODO:根据变量改变文本
- TODO:用随机数设置变量
- 占用的硬盘空间足够小
- 读写文件的速度足够快
- 每个有状态的前端组件实现
IRestorable
,它的状态表示成IRestoreData
- 在
CheckpointSerializer.Write
中,每个IRestoreData
用BinaryFormatter
序列化成二进制流,再用DeflateStream
压缩,再写到文件- 存档的状态一般是很稀疏的,所以需要压缩
- 我们没有提供存档加密功能,因为代码是开源的,如果需要加密请自行解决
- TODO:
BinaryFormatter
已经被微软官方deprecate了,以后我们可能会换成JSON或者其他格式
- 需要存档的状态(checkpoint)由全局变量(
CheckpointManager.globalSave.data["global_variables"]
)、节点历史(GameState.nodeHistory
)和对话序号(GameState.currentIndex
)唯一确定- Checkpoint与分支选项无关,如果两个选项从同一个旧节点跳转到同一个新节点,它们不会造成不同的状态
- 节点历史的内容:
- 首先是每个节点的名称
- 剧本可以有循环,为了方便在节点历史中指定一段,每个节点每次出现时要记录出现次数
- 以及每个小游戏结束后变量的hash,由
NodeHistory.interrupts
记录
- 每条对话都有一个
GameStateRestoreEntry
,保存这条对话的(default stage的)代码块运行之前所有前端组件的状态,记录在CheckpointManager.globalSave.reachedDialogues
中- 读档时,先恢复目标对话的状态,再运行目标对话的代码块
- 为了支持持续动画(详见演出系统),并减少存档占用的空间,
GameStateRestoreEntry
分为两类:-
GameStateCheckpoint
完整记录所有前端组件的状态 -
GameStateSimpleEntry
不记录这些状态,只记录上一个GameStateCheckpoint
的相距步数- 读档时先读取上一个
GameStateCheckpoint
,再快进到GameStateSimpleEntry
的位置
- 读档时先读取上一个
- 我们避免使用full/raw/real checkpoint之类的说法
-
- 快进时,如果之前到达过一条对话,无论现在的变量如何,这条对话都视为已读
-
CheckpointManager
有方法IsReachedAnyVariables(string nodeName, int dialogueIndex)
-
- 可能的节点历史的数量随着分支选项和小游戏结果的数量增加而指数增长,但是我们只会记录玩家遇到过的节点历史。在最坏情况下,checkpoint占用的内存和硬盘随着游玩时间而线性增长
- 存档/读档界面中的每个存档称为书签(
Bookmark
),记录节点历史的hash和对话序号- 读档时,提供这些信息就能恢复checkpoint
- 自动存档、快速存档与手动存档的格式是一样的
- Log界面中的每个
LogParam
记录一条对话的节点名称、出现次数和对话序号- 在log界面中回跳时,提供这些信息就能恢复checkpoint
- Log界面中的每条对话的节点历史一定是当前的节点历史的前缀,因此每个
LogParam
不用记录完整的节点历史,只要记录一个节点的名称和出现次数
-
LogParam.displayData
记录这条对话的文本,包括所有语言的翻译,以便于随时切换语言- 如果文本中有需要插值的变量,
LogParam.displayData
则会记录插值后的文本
- 如果文本中有需要插值的变量,