【免费下载链接】ReSkate
ReSkate 是一款面向 skate.(Frostbite 引擎)的开源增强工具,它能离线运行游戏、自建服务器,并把你放进Mods/文件夹里的 Mod 在启动时自动合并进游戏。本文将带你彻底搞懂 ReSkate 是如何解析 Frostbite 的三大核心数据格式——EBX、TOC 与 CAS,再把多个 Mod 的修改"缝"成一个干净补丁的完整原理。
ReSkate 是什么,为什么值得研究
ReSkate 是玩家自制项目(非官方),包含三大部分:
| 组件 | 作用 |
|---|---|
ReSkateLauncher.exe | 启动器:校验游戏版本、安装游戏文件、管理 Mod |
ReSkate.dll | 运行时:注入游戏,提供菜单、控制台、Mod 合并等 |
ReSkateServer.exe | 专用服务器:无需游戏与 Steam 的无头大厅 |
其中最有技术含量的部分,就是Mod 合并系统:你放进Mods/的每个 Mod 本质上都是"对游戏原始数据层的增量修改",而游戏引擎一次只认一层补丁。ReSkate 的工作,就是把这些增量翻译成引擎能读懂的 Frostbite 数据格式,再合成为唯一的一层补丁。
要理解这个过程,先要认识 Frostbite 的三个数据格式。
一、Frostbite 的三层数据格式
Frostbite 引擎组织游戏资源的方式可以概括为:EBX 是内容,TOC 是目录,CAS 是仓库。
1. EBX:游戏资产的"对象文档"
EBX 是 Frostbite 的序列化对象格式。游戏里的滑板、角色、物品、关卡配置,本质上都是 EBX 资产里的"实例"(instance)。
ReSkate 在 Engine/Resource/ebx_document.h 中完整实现了 EBX 的读取,核心结构Document包含:
- 反射数据(reflection):
TypeDescriptor与FieldDescriptor描述每个类的字段名、字段类型(整型、字符串、GUID、指针、数组等,见FieldType枚举)——这是 EBX 能"自描述"的关键; - 实例(
InstanceRecord):真正的对象数据,每个实例有自己的 GUID,可被导出、被其它文档引用; - 导入表(
ImportReference):跨文档引用靠fileGuid + classGuid定位,这是 Mod 之间"互相指认"资产的基础; - 数组区(
ArrayRecord):根对象上的列表(比如"本关卡包含哪些对象")就存在这里,Mod 添加物品往往就是往这些数组追加条目。
也就是说,改一个 EBX,要么是改某个值(一个数字、一个字符串),要么是加一个实例(一个新物品),要么是往根数组追加引用(把新物品挂进游戏的主列表)。这三种变化,正是后面合并算法要处理的全部情形。
2. TOC:Superbundle 的目录清单
单个 EBX 文件很小,游戏内容被组织成bundle(捆绑包)再打包进superbundle(超级捆绑包)。而 TOC(Table of Contents)就是超级捆绑包的"总目录",定义见 Engine/Resource/toc.h:
TocBundle:目录中每个 bundle 的条目;TocChunk:每个 chunk 的 GUID、在 CAS 中的位置(CasIdentifier)、字节偏移与大小;bundleHashMap/chunkHashMap:两张哈希索引表,引擎靠它快速定位资源。
toc_hash使用的 FNV 种子0x811C9DC5与引擎完全一致——合并后重建的哈希表必须让引擎原样解析,这正是 write_patch_toc 能写出"引擎可解析的补丁 TOC"的原因。
3. CAS:压缩存储的"集装箱"
TOC 里的位置最终指向磁盘上的cas_NN.cas归档文件。CAS 是 Frostbite 的分块压缩容器,ReSkate 的编解码器见 Engine/Resource/cas_codec.h:
- 支持 Oodle 的
kraken、selkie、leviathan三种压缩模式; - 运行时直接链接 External/ 下的 lz4、zstd、miniz,Oodle 则复用游戏自带的
oo2core模块。
bundle 的资产清单(manifest)也存放在 CAS 里,结构见 Engine/Resource/binary_bundle.h:一份 manifest 列出三类资产——ebx、resources(如音频、Lua 脚本)、chunks(流式纹理块),每个资产带 SHA1、GUID 与所在 CAS 文件的偏移。
📦 一句话总结:TOC 回答"资源在哪",CAS 回答"字节在哪、怎么解压",EBX 回答"资源长什么样"。
二、Mod 合并原理:把 N 个 Mod 缝成 1 层补丁
引擎对每个 superbundle 只合成一个补丁层,所以"两个 Mod 都改了同一个 bundle"时,谁都不能直接覆盖谁。ReSkate 的合并入口是 merge_mods,它把所有启用的 Mod 合成为Mods/.reskate/下的统一补丁。整个流程分四步:
第 1 步:重新编号 CAS 归档。每个 Mod 出厂时都假设自己的cas_00.cas是"1 号归档",多个 Mod 放一起必然撞号。合并器给每个 Mod 的归档分一个专属编号,并重写 Mod 补丁内的所有引用(mod_merge_internal.h 中的ArchivePlacement)。由于位置用 32 位偏移寻址,单个归档不能超过 4 GB,"一个 Mod 一号段"恰好让合并后的补丁没有自己的大小上限。
第 2 步:合并物理材质网格。这是最精巧的一步。地图 Mod 可以定义自己的碰撞表面,每份地图都从游戏网格的第 116 号槽位开始追加自己的行——两个 Mod 都"声称"第 116 号是它的。material_grid.h 的Combiner把每个 Mod 的新增行依次拼接到一张网格的尾部,并返回槽位重映射表,把每个 Mod 的碰撞数据改写为"新槽位号"。这样引擎读到网格里的每个槽位都合法——因为引擎对槽位表不做越界检查,读错一格就是碰撞瞬间崩溃。
第 3 步:逐个 superbundle 合并 bundle。这是主体工作,由 mod_merge_combine.cpp 完成,核心是逐资产比较:
| 资产情形 | 合并策略 |
|---|---|
| 游戏有、Mod 没动 | 保留原版 |
| 多个 Mod 都改了同一个 EBX | 调用 EBX 三向合并(见下) |
| Mod 新增的资产 | 追加进 manifest,连同它引用的新文档一起搬走 |
| 无任何 manifest 可读的 bundle | 整体透传,优先级最高的 Mod 胜出 |
纹理chunk还有一层细节:chunk 元数据列表必须按 chunk GUID 排序、且替换的 chunk 要继承原版记录的首层 mip,否则流式加载会出错(merge_chunk_metadata)。
第 4 步:写出补丁与指纹。合并结果带一份指纹(SDK 版本 + 各 Mod 文件 + 被合并的原始文件)。下次启动若指纹没变,直接复用上次的Mods/.reskate/,秒进游戏(mod_merge_stamp.cpp)。报告结构MergeReport(mod_merge.h)还会记录每个 Mod 的失败原因,日志里能点名"是哪个 Mod 拖累了哪个关卡"。
核心算法:EBX 三向合并
两个 Mod 都基于同一份原版 EBX 各自修改后,如何合成?merge_documents 以原版为 base做三向合并,规则非常克制:
- 新增实例:各 Mod 添加的实例全部保留;
- 根数组追加:两边都追加的同一个引用只记一次;
- 原地改值:同一字段被多个 Mod 改成不同值时,按优先级顺序应用,最后一个赢;
- 其它形状的变化(指针改指别处、列表中间插值):无法安全合并,保留原版,并在
MergeSummary里记录是哪份编辑没被采纳。
MergeSummary::exact()会告诉你这次合并是否"每个编辑的每处改动都完整落地",为日志与排查提供依据。
三、进阶:游戏运行中也能热合并
更妙的是,ReSkate 支持活合并(live merge):在游戏不重启的情况下,于两次关卡加载之间重新合并。难点在于引擎不会释放已挂载的归档,所以活合并不替换任何已打开的文件——新清单追加到 1 号归档末尾,superbundle TOC 每次挂载都会重读、因此可以放心重写(mod_merge.h)。这就是为什么"大多数 Mod 变更无需重启游戏即可生效"。
四、想深入源码?从这里开始
| 想看的模块 | 路径 |
|---|---|
| EBX 解析与三向合并 | Engine/Resource/ 下的ebx_document.*、ebx_merge.* |
| TOC 读写与哈希 | Engine/Resource/toc.cpp |
| CAS 压缩编解码 | Engine/Resource/cas_codec.cpp |
| Mod 合并主流程 | Engine/Vfs/mod_merge.cpp、mod_merge_combine.cpp |
| 归档重编号 | Engine/Vfs/mod_merge_cas_store.cpp |
| 材质网格合并 | Engine/Resource/material_grid.cpp |
🧩总结:ReSkate 的 Mod 合并本质上是一套"格式级"的三向合并系统——用 EBX 反射数据理解内容,用 TOC 哈希表重建目录,用 CAS 归档重组存储,最后把 N 个 Mod 的差异收敛成引擎唯一接受的一层补丁。理解这三套格式后,你不仅能看懂 ReSkate 的日志,也具备了给 skate. 开发或调试 Mod 的底层知识。
【免费下载链接】ReSkate
相关推荐
Czkawka完整指南:如何快速清理电脑垃圾文件释放存储空间
Czkawka完整指南:如何快速清理电脑垃圾文件释放存储空间 你是否经常遇到电脑存储空间不足的困扰?😅 重复的照片、无用的临时文件、空文件夹...这些"数字垃
桌面应用CLINullAway数据流分析揭秘:深入理解null安全检测原理
NullAway数据流分析揭秘:深入理解null安全检测原理 NullAway是一款强大的Java空指针异常(NPE)检测工具,通过静态分析技术帮助开发者在编译
Google Java Format 核心架构解析:代码格式化原理揭秘
Google Java Format 核心架构解析:代码格式化原理揭秘 Google Java Format 是一款强大的 Java 代码格式化工具,它严格遵循
开发工具格式化
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考