保存资产时如何处理版本更改?

我一直在做一个RPG的一段时间,我使用两种不同的序列化技术。

  • 敌人,武器,物品和XML一样保存。
  • 地图和事件被保存为“受控二进制”(每个类获得一个保存/加载方法,他们决定他们想要保存/加载)。

但是我开始质疑我对地图和事件的select。 我的担忧:

  • 我创建了一个地图编辑器,但是我仍然错过了能够通过打开文件来改变小的东西。
  • 变化如此之大。 假设我想给一个类添加一个variables,如果我不加载/保存每个地图,它会在稍后中断。

第一个担心是不改变我的技术难以避免。 我想转换到JSON,但这是很多工作。 我也认为它随处可见[DataContract]和[DataMember]属性,显得很丑陋。

这让我担心我的第二个问题,我想知道我该如何处理它? 你是否创建了一个循环遍历所有地图的小程序,并用新variables重新保存它们? 因为我现在开始获取几张地图,而且我仍然手动完成。 每当我想要做一些改变时,它会让我思考三次,因为它创造了许多额外的工作。

有很多方法来处理版本问题。 您可以通过每个版本具有一个加载函数来实现,您可以尝试通过描述(通常通过属性)资产结构随时间的变化来自动执行过程,您可以在加载/保存函数内部进行特定于版本的检查,等等。

我喜欢“描述变化”的方法,但是发现通过属性来做到这一点变得很快 。 我会使用function,而不是; 实现一个function,将版本N中的数据转换为版本N + 1数据,用于所有适当的版本。 在加载时,请检查最新版本,如果不是,请通过所有适当的版本控制function运行数据。 总是保存最新版本。

如果在数据仍处于运行时键值forms的情况下进行转换,则此效果最佳。 这意味着您可能需要为数据实现一个表示forms,这是“运行时属性包”方法,因为如果您拥有自己的二进制格式,则不能使用JSON或XML的基础键值forms。 如果你不这样做,你可能需要保留旧的类定义,这很丑陋。 能够让你的资产在这个属性不好的格式也是非常有用的游戏编辑器的发展。

在开发过程中,当你迭代你的数据时,它自然会冒泡到最新的版本,你最终可以删除旧版本的function。 这与我们在“激战2”中用于版本艺术资产(比如地图)的高级方法差不多。


现在,所有这一切说,我认为支持资产的文本和二进制序列化是有用的。 在开发过程中,将所有数据保存为基于XML或JSON的可读格式。 这可以增加你的迭代能力很多,因为你不需要在编辑数据的时候编译这样复杂的工具。 你可以回到能够简单快速的手动调整。

其次,假设你仍然想要一个二进制格式的游戏(这可以提高文件大小或文件IO时间,所以这是一个有效的愿望),devise你的序列化和反序列化API来处理版本。 版本控制在运输环境中仍然有用,因为有些时候您可能想要发布更新或错误修复。 有一些文档描述了.NET序列化和Boost序列化的版本控制能力,您可能会感兴趣。 如果你要支持文本和二进制格式,确保你偶尔testing它们(或者建立自动化的testing,甚至更好)。

使用带有XML或JSON等属性值对的标记语言。

parsing器可以忽略任何它不理解的属性,或者使用缺省值来找不到任何的属性,这使得向前和向后的兼容性变得相当容易。 此外,格式是人类可读的,所以你可以很容易地编辑它与文本编辑器。

当您使用XML或JSON等已建立的语言时,您也会注意到许多脚本语言都支持它,所以当您仍然需要编写脚本来编辑大量文件时,您会发现这样做更容易。

大多数这些语言的缺点是它们非常冗长。 这意味着生成的文件比使用优化的二进制格式所需的文件大得多。 如今,在大多数情况下文件大小并不重要。 但在那些重要的地方,文件大小通常可以通过使用诸如zip之类的库存压缩文件来显着减less。

标记语言通常不允许随机访问,除非从硬盘读取整个文档并parsing。 但在实践中,这并不重要,因为硬盘驱动器在连续读取时是最快的。 对同一个文件的不同部分进行多次的随机查找通常比仅仅一次读取文件要慢很多,即使这意味着你读取的数据比你需要的还要多。

你可以使用protobuf。 https://code.google.com/p/protobuf/它为您提供了json / xml的优势,您可以在向后兼容的同时轻松扩展它,并具有二进制的优势。 工作stream程是,您使用protobuf语言创建数据格式描述,然后生成序列化和反序列化的源代码。 源可以为几种语言生成。 另外,这是一个很大的优势,你有一个清晰的序列化数据的说明,相比之下,规范是在读/写隐式完成的json。