[专栏作家]Lua表结构描述和数据版本
Posted 游戏蛮牛
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[专栏作家]Lua表结构描述和数据版本相关的知识,希望对你有一定的参考价值。
用lua开发游戏服务端时,往往会将lua表作为玩家数据存入数据库中,但随着游戏的版本的迭代,往往需要添加、删除存储表的字段。如果不能够自动的处理数据版本,需要在逻辑层去判断某个字段是否存在,会增加游戏逻辑开发人员的工作量,也容易出现因为忘记判断某个字段是否存在而导致的bug。于是我们编写一个名为“表结构描述”的模块,让它自动处理数据版本。
为什么需要版本控制
比如在一款坦克游戏中,玩家身上的数据可能如下所示。玩家的id是123,名字叫“坦克战神”,它拥有两辆坦克,其中一辆是id为101的坦克,另外一辆是id为102的坦克。
正常情况下,只需要将playerdata序列化然后存储到数据库中。然而对于经常迭代的游戏,因为经常需要新增或删除存储字段,可能会导致逻辑编写的困难。比如在某个版本中需要给坦克增加一个等级的属性,玩家的存储结构变成如下的lua表。
因为需要新增level字段,而老玩家的游戏数据里并没有这个字段,于是在游戏逻辑里可能需要下面这么写。
意味着在使用到level的逻辑里,都需要去判断level存不存在,如果不存在就赋予初值。
如果游戏存储了很多数据,而且版本更迭较快,我们将很难弄成哪些字段需要判断是否存在,哪些字段不需要判断,每一次写逻辑都要多考虑存不存在的问题,很麻烦。
希望的结果
我们希望随着游戏更迭,如果需要某个字段,在加载数据时就能够自动给该字段赋予初值,而不需要手动去判断值是否存在。在上面的例子中,如果框架层就能够自动给level赋予初值,逻辑层将能够减少一次判断,减轻逻辑开发人员的压力。
表结构描述
为了达到上述目的,需要一个表结构描述的表,描述存储的数据到底包含了哪些数据,这些数据的初始值是什么。我们规定一种如下的表结构,它能够支持string、number、array(数组)、dict字典四种类型的数据,并且支持嵌套。该表与常规的lua表没有区别,字段的值代表默认值,如果表中有key为”_array”的字段,代表该表里的元素都是”_array”字段所描述的数组;如果表中有key为”_dict”的字段,代表该表里的元素都是”_dict”字段所描述的字典。
以第一个版本的playerdata为例,它的表描述结构如下。其中的“["_dict"] = { id = -1}”代表tanks是一个字典,每个字典的元素包含id一个字段。
以第二个版本的playerdata为例,它的表描述结构如下。其中的“["_dict"] = { id = -1, level = 1}”代表tanks是一个字典,每个字典的元素包含id和level两个字段,而且level的默认值为1。
版本匹对
定义一个版本匹对的方法commit(desc, inst),它带有两个参数,第一个参数代表描述表,第二个参数代表存储表。以上述坦克数据为例,在经过匹对方法后,会自动给坦克数据增加level字段,而且默认值是1。
调用方法举例:
处理版本匹对的commit方法,它遍历描述结构表,对不同的数据类型做判断。如果描述表中存在实例表的字段,则复制实例表的字段。如果是数组或字典类型,将对实例表的每一项和描述表的对应字段做匹配,只返回匹配的结果或者默认值。
有了该版本匹对的方法后,只要先编写描述表,描述表能够清晰的指明哪些数据需要存储,很有意义。然后在读取数据和存储数据时都匹对一次,这样将使存储和读取的数据都符合最新的描述,起到了数据版本升级的功能。
更多做法
本文的方法是基于lua表描述和匹对的数据版本更新方法。除了本文提及的方法外,使用lua面向对象编程、使用protobuf做序列化也能够实现同样的功能。但本文提及的方法最为简单纯粹,不涉及任何第三方库,且直观易懂。
以上是关于[专栏作家]Lua表结构描述和数据版本的主要内容,如果未能解决你的问题,请参考以下文章