Skip to content

Restoration

woctordho edited this page Jan 27, 2022 · 36 revisions

存档系统

这篇文档对应的是master branch上的旧版的存档系统。我们已经发现了它的设计有一些问题,你可以换成new_checkpoint branch上的新版。新版的文档在这里

设计目标

  • 保存和读取各种前端组件(图片、BGM等)的状态
  • 在对话中设置变量,用变量控制剧情分支,在读档时恢复变量
  • 在小游戏中设置变量,此时变量取决于玩家输入
  • 在章节选择界面和文本回顾界面中跳转到一条已经到达过的对话
  • 读档时恢复文本回顾界面的内容(这个版本的存档系统会有bug,新版已经修了)
  • 在文本回顾界面中回跳时,恢复更早的文本
  • 占用的硬盘空间足够小
  • 读写文件的速度足够快

序列化

  • 每个有状态的前端组件实现IRestorable,它的状态表示成IRestoreData
  • CheckpointManager.WriteSave中,每个IRestoreDataBinaryFormatter序列化成二进制流,再用DeflateStream压缩,再写到文件
    • 存档的状态一般是很稀疏的,所以需要压缩
    • 我们没有提供存档加密功能,因为代码是开源的,如果需要加密请自行解决
    • TODO:BinaryFormatter已经被微软官方deprecate了,以后我们可能会换成JSON或者其他格式

保存游戏状态

  • 需要存档的状态(checkpoint)由全局变量(CheckpointManager.globalSave.data["global_variables"])、(局部)变量(GameState.variables)、节点名称(GameState.currentNode.name)和对话序号(GameState.currentIndex)唯一确定
    • Checkpoint与分支选项无关,如果两个选项从同一个旧节点跳转到同一个新节点,它们不会造成不同的状态
  • 每条对话都有一个GameStateRestoreEntry,保存这条对话的(default stage的)代码块运行之前所有前端组件的状态,记录在CheckpointManager.globalSave.savedNodes
    • 读档时,先恢复目标对话的状态,再运行目标对话的代码块
  • 为了支持持续动画(详见演出系统),并减少存档占用的空间,GameStateRestoreEntry分为两类:
    • GameStateCheckpoint完整记录所有前端组件的状态
    • GameStateSimpleEntry不记录这些状态,只记录上一个GameStateCheckpoint的相距步数
      • 读档时先读取上一个GameStateCheckpoint,再快进到GameStateSimpleEntry的位置
    • 我们避免使用full/raw/real checkpoint之类的说法
  • 快进时,如果之前到达过一条对话,无论现在的变量如何,这条对话都视为已读
    • CheckpointManager有方法GetReachedForAnyVariables(string nodeName, int dialogueIndex)

书签

  • 存档/读档界面中的每个存档称为书签(Bookmark),记录一条对话的变量hash、节点名称和对话序号
    • 读档时,提供这些信息就能恢复checkpoint
  • 自动存档、快速存档与手动存档的格式是一样的

文本回顾界面

  • Log界面中的每个InitParams记录一条对话的变量hash、节点名称和对话序号
    • 回跳时,提供这些信息就能跳转到那条对话
  • 为了在读档时恢复log,每个checkpoint中保存上一个checkpoint到它之前的所有InitParams
Clone this wiki locally