一般的资源包文件格式基本上是由包文件头和包内容组成。文件头描述资源包内打包的文件
信息,例如文件名、在资源包里的偏移、大小、压缩加密相关信息等;包内容则是实际文件
打包在一起后的内容,可能直接是未打包前文件连续存放在一起的内容,也可能是相同类型
文件除掉文件头的内容(例如某个资源包里打包的全部是相同格式的图片文件,那么这些图
片文件被打包后包内只需要保存一个图片文件头,包内容全部是直接的图片数据)。
网络游戏资源包有个显著的需求就是支持补丁包更新。更新程序会把补丁包内的更新资源文
件插入到老的资源包里。最简单的解决办法,就是在包文件头里预留一定的空间,用于将来
插入新的文件描述。当然,新的文件内容可以直接插入到包尾。一个简单的文件格式如下:
pkg_header是一个对整个资源包综合描述的结构,可能包含的域为:
struct PkgHeader {
int ver; /* 版本号 */
int ctx_offset; /* 文件内容偏移 */
int file_tag_cnt; /* 文件标记数量 */
int empty_tag_cnt; /* 空标记数量 */
};
pkg_header后面则是文件标记(信息)结构体集合,每一个标记用于描述打包的一个文件的
信息,可能包含的域有:
struct FileTag {
char name[128]; /* 包含目录名的文件名,用于索引,如./model/character.dat */
int offset; /* 该文件在资源包内的偏移 */
int size; /* 在资源包中的大小 */
int orig_size; /* 原始大小,即未压缩/加密前大小 */
int crc; /* crc校验 */
};
如果要支持客户端自己下载数据更新,考虑到断点续传功能,可能还会添加一些成员用于标
记当前文件获得的数据大小。
empty_tags则是一些空的FileTag。当要往包里插入新的文件时,则会在这里申请。同样,
如果要删除文件,也可以将前面的file_tag转移过来。因为采取这种包格式,文件实际内容
的偏移基本上是不会改变的,所以,每一次都可以直接重新排列file_tags和empty_tags。
接下来包的内容就直接是文件内容。如果中间的文件大小有变化,会涉及到其他文件数据的
移动。
对于只需要读取资源包的游戏客户端而言(不包括更新程序),可以只读取pkg_header和
file_tags。程序将file_tags置于一个索引表中,效率考虑,可以标记每一个file_tag是否
已在内存中。每一次应用层请求一个资源文件时,就从该表中查找。若资源已在内存中,就
直接取出使用,否则根据file_tag的描述从资源包里取出(这里涉及到IO操作)。