单片数据文件的原因

Ali*_*own 7 data-files

这似乎是游戏使用的一种技术,它将所有声音都放在一个文件中,纹理放在另一个文件中.这些文件通常达到GB大小.

这样做的原因是如何将子目录中的所有内容保存为小文件 - 许多小型游戏使用这种格式的一个,整体系统受到大公司的青睐?

是否有一些文件系统开销有很多小文件?他们是否试图保护自己的财产 - 尽管大多数似乎只是一个带有新扩展名的压缩文件?

lea*_*der 6

我们使用像我这样工作的"归档"系统(游戏开发公司)的原因:

  • 查找速度:我们很少需要遍历目录中的文件; 我们更经常直接通过名字查找它们.通过使用基本上只是序列的自定义"文件分配表" hash( normalized_filename ) -> [ offset, size ],我们可以非常快速地查找文件.我们还可以将此索引保留在RAM中,可能会将其与其他索引表等交错.
  • (当我们需要迭代时,我们可以轻松地遍历a中的所有文件.arc,或者我们可以存储文件名列表,文件散列名列表,或者只是某处[offset,size]对的列表 - - 甚至可能作为档案中的文件.这通常比FS上的目录遍历更快.)
  • 元数据:我们很容易收集我们想要的任何文件元数据.例如,"大小"字段中的单个位指示文件是否已压缩(如果是,则它具有包含有关如何解压缩文件的更多详细信息的标头).如果我们提前知道文件的结构,我们甚至可以对文件的各个部分进行压缩(我们这样做是为了精灵档案).
  • size:我们使用的设备之一是"文件大小必须是X的倍数"要求,其中X与我们的某些文件相比较大.例如,我们的一些lua脚本在编译时最终只有几百个字节; 每个.luc文件的额外开销加起来很快.
  • 对齐:另一方面,有时我们浪费空间.为了利用来自文件系统的更快的流(例如后台DMA),我们的一些文件确实需要遵守某些对齐/大小要求.我们可以在工具中处理这个问题,我们拍摄的对齐/尺寸不一定要与底层FS对齐,这样我们就可以在我们需要的地方浪费空间.

但这些是世俗的原因.更有趣的东西:

每个都.arc在列表中注册,并尝试打开文件,知道查看弧.我们首先搜索已经在RAM中的存档,然后在设备FS上存档,然后在实际设备FS上存档.这给了我们很大的灵活性:

  • 对文件系统的动态添加:我们可以随时将新文件或存档流式传输到相关机器(通过网络等),并使其显示为"逻辑"文件系统的一部分; 当实际的FS驻留在ROM或CD上时,这很好,并且允许我们比我们更快地迭代.
  • (Doom的.wad系统就是上述的一个例子,它允许模组更容易地覆盖游戏中内置的资产和脚本.)
  • 没有底层fs的可能性:可以使用在链接时bin2obj直接在可执行文件(.rodata)中嵌入整个弧,此时您不需要查看设备FS - 我们为某些小型演示版本执行此操作等等.我们也可以通过网络发送关卡或以这种方式savegame-sneakernet.=)
  • 组织和加载/卸载:因为我们可以随时加载和卸载并覆盖我们文件系统的虚拟"部分",所以我们可以做一些性能技巧,使FS中的文件数量在任何给定时间都非常小.我们还可以指定将整个存档加载到内存,索引表和数据中; 我们的文件加载代码非常智能,知道如果文件已经在内存中,除了移动指针外,它不需要做任何事情来读取它.一些更高级别的代码实际上可以检测到文件是ram并且只是直接询问可能已经看起来像结构的指针.
  • 可移植性:我们只需要弄清楚如何在我们使用的每个新设备上获取一些文件,然后FS代码的其余部分或多或少相同.=)我们偶尔会更改工具输出(出于对齐原因),但大多数处理仍然相同.
  • 重复数据删除:通过我们的精灵档案等更智能的档案,我们可以(并且确实)对数据进行重复数据删除.如果"跳跃"动画的第五帧和"踢"的第三帧是相同的,我们可以拉开文件并仅存储该帧的一个副本.我们可以对整个文件做同样的事情.

我们最近将PC游戏移植到FS访问速度慢得多的系统.我们没有改变数据格式,结果是在原始设备FS上通过dir迭代加载了一百个小的XML文件,这绝对会扼杀我们的加载时间.我们使用的解决方案是获取每个目录,使其成为自己的目录,并将其subdir.arc粘贴在主game.arc压缩中.当需要dir(类似于opendir)时,我们将整个subdir.arc解压缩到RAM中,将其添加到文件系统中,然后超级快速地迭代它.

它能够在几个小时内将这样的东西放在一起,并减轻跨系统移植的痛苦,这使得这样的东西值得.