艾克斯の编码者

一个伪宅级别的码畜。

关于游戏资源包的更新、删除

大纲

  最近除了忙各种各样的期末考试、去西班牙的签证,就是公司的那个韩国项目了。

  我的任务基本完成——将原本单屏的游戏改成三屏,完善整个 GUI系统 以及“劫持”了原游戏中的一些逻辑,比如滚轴的排列可以任意控制等。由于原代码中的GUI系统没有文本编辑框,我还得自己写一个。然而我对于IME的操作、GDI和DX的结合不是非常熟悉,所以还是参照了一下 ShowLong 所修改的微妙的平衡给HGE写的中文解决方案。

  完成了以上的任务之后,由于我的考试以及签证问题以及我本身的任务差不多了,就把这个摊子就扔回公司去了。在交接的时候,老大给我派了一个任务,让我来写这个游戏资源包的代码。

  原版游戏代码中有资源包代码,但是写得非常乱,于是需要我来写一个新的文件结构、新的加密算法,然后仍然是“劫持”掉原代码中的资源包加载函数。

  在此之前,我拜读了云风的《游戏资源的压缩、打包与补丁更新》,有了点灵感。

  最主要的就是其删除这一块。为了让用户在更新的时候减少大量的文件IO操作,做法就是减少文件内容的大幅度移动。

  而我便是参考了云风大大的这个思想来写我的文件包。首先因为在游戏中需要实时读取,所以文件没有压缩,只是做了两层加密处理,密钥也是通过哈希得到的,所以每个文件的密钥是不同的。

  然后在文件索引的时候,我这里是分了两种索引:文件索引以及空块索引

  所谓空块索引就是:在文件包中删除某一个文件的时候,不把后面的文件内容全部往前挪以覆盖这一块的内容、导致整个文件包在删除文件之后的信息全部往前挪而产生的大量IO操作,而是对这一块内容不作任何处理、把这一块内容的索引从文件索引中移除并附加到空块索引中以供以后新文件加入时所用,这样就只产生了一点对于索引的文件IO更新,不过索引的更新充其量也就那么点,相对于文件的操作来说只是九牛一毛,当然前提是这个索引是在整个文件包的最后。而在有新文件插入的时候,先在空块索引中找有比新文件大的空块,如果有的话就直接把这个文件插入到那个空块中,然后更新一下文件索引以及空块索引即可,这里又少掉了一些IO操作。

  正如云风所说:

如果新增加的文件较之小,就重复利用这个空间。如果利用不上,就浪费在那里。这有点像内存管理算法,时间久了,资源包内会有一些空洞,但也是可以接受的。

  接着就是资源包在游戏中的使用了。在原先的游戏代码中是有判断重复加载的代码,也就是说把已加载的资源存到node里,在之后再次需要加载这个资源(通过文件名判断)就直接从node中去,这样就少了很多内存开销,尤其是当我把单屏改为三屏之后,这样的优化效果更为明显(否则相同的资源要加载三次,等于消耗了三倍的内存)。不得赞一下这05年开发的代码,虽然是棒子。不过原游戏代码中的高耦合度让我蛋疼。

  想到以后这个资源包类要用到以后的一些项目,于是我自己也写了一个Cache机制。就是在一个包中,当加载某个资源的时候,顺便把这个资源的Buffer加到一个Cache中,当下次再需要用到这个资源的时候就直接从Cache中取就好了,实际上这就还是之前的代码实现的功能,只不过我自己在这基础上精简了一下。最后写一个ClearCache的函数能清除Cache,我这个资源包类就算完成了。

  还有在获取资源的时候,为了防止内存突增,我的Buffer是一段一段获取的,类似于Socket中的获取消息一直到消息结束为止。当然,每一段Buffer的大小是可以自己传进去的。我这种以时间换空间的做法还没自己实际测试过效果如何,只不过是自己想想可能会比较优罢了,因为最近实在是太慢,这篇日志还是考完了概率然后摸着黑地写的。

  我对文件系统本身不是非常了解,操作系统还没考呢。所以我现在仅仅做到的是云风九年前的一种设计,然后加上了原先代码有的Cache机制而已。不过写下这篇日志来记录我自己成长的足迹罢了。