http://blog.codingnow.com/2014/08/unity3d_asset_bundle.html

Unity3D 的 asset bundle 的格式并没有公开。但为了做更好的差异更新,我们还是希望了解其打包格式。这样可以制作专门的差异比较合并工具,会比直接做二进制差异比较效果好的多。因为可以把 asset bundle 内的数据拆分为独立单元,只对变更的单元做差异比较即可。

网上能查到的资料并不是官方给出的,最为流行的是一个叫做 disunity 的开源工具。它是用 java 编写的,只有源代码,而没有给出格式说明(而后者比代码重要的多)。通过阅读 disunity 的代码,我整理出如下记录:


asset bundle 分为压缩模式和非压缩模式。压缩模式仅仅是用开源的 lzma 库 对整个非压缩包做了一次整体压缩。压缩数据的头有 13 个字节,前 5 个字节是 lzma 解压缩的 API 需要穿入的 props ,接下来的 4 字节是解压缩后的数据库长度。最后 4 字节不用理会它。

把压缩数据解开后,就和非压缩模式没有差别,下面只讨论非压缩格式:

assert bundle 的文件头是从这样一个数据结构序列化出来的。

struct AssetBundleFileHead {
struct LevelInfo {
unsigned int PackSize;
unsigned int UncompressedSize;
}; string FileID;
unsigned int Version;
string MainVersion;
string BuildVersion;
size_t MinimumStreamedBytes;
size_t HeaderSize;
size_t NumberOfLevelsToDownloadBeforeStreaming;
size_t LevelCount;
LevelInfo LevelList[];
size_t CompleteFileSize;
size_t FileInfoHeaderSize;
bool Compressed;
};

string 是直接以 \0 结尾的字符串,顺序序列化;size_t 是大端的 4 字节数字;bool 是单个字节;vector 就是顺着排列的结构。

根据 Unity 版本的不同,assert bundle 的格式也不完全相同。Version 指明了 bundle 的格式版本,从 Unity 3.5 开始到 4.x 版都使用 Version = 3 ,下面只讨论这个版本。HeaderSize 应该恰好等于以上这个文件头的数据长度。

一个 assert bundle 是由多个 asset 文件打包而成,接下来顺序打包了这些 asset 。序列化成这样的结构:

struct AssetFileHeader {
struct AssetFileInfo {
string name;
size_t offset;
size_t length;
};
size_t FileCount;
AssetFileInfo File[];
};

这样我们就可以分解出被打包在一起的多个 Asset 了(大多数情况下只有一个)。offset 表示的是除去 HeaderSize 后的偏移量。我们可以用 HeaderSize 加上那个部分的 offset 得到这个部分相对于整个 bundle 的文件偏移。

对于每个 asset ,又有它自己的数据头。数据头除了基本的数据头结构 AssetHeader 外,还有额外的三个部分。disunity 把它们称为 TypeTree ObjectPath 和 AssetRef 。注意:这里 Format 随不同 Unity3D 的版本有所不同,我们只关心目前的版本的格式,这里 Format 为 9 (其它版本的格式,在大小端等问题上有所不同)。

struct AssetHeader {
size_t TypeTreeSize;
size_t FileSize;
unsigned int Format;
size_t dataOffset;
size_t Unknown;

Unity 对 Asset 数据做了简单粗暴的序列化操作。整个序列化过程是针对每种对象的数据结构进行的。TypeTree 是对数据结构本身的描述,通过这个描述,就可以反序列化出每个对象。

AssetHeader 后面紧跟着的就是 TypeTree 。但是,这个 TypeTree 对于 asset bundle 来说是可选的,因为数据结构的信息可以事先放置在引擎中(引擎多半只支持固有的数据类型)。在发布到移动设备上时,TypeTree 是不打包到 asset bundle 中的。

每个 asset 对象,都有一个 class id ,可以在 TypeTree 中查到如何反序列化。class id 的和具体类型的对应关系,在 Unity3d 的官方文档 可以查到。但若我们只是想将差异比较在对象一级进行(而不是具体比较对象中具体的属性),那么就不需要解开具体对象的细节信息,这部分也不用关心。所以这里也不展开(有兴趣可以读一下 disunity 的代码,格式并不复杂)。

在 AssetHeader 中的 TypeTreeSize 指的就是 TypeTree 部分的大小。接下来是每个 AssetObject 的描述数据。

struct ObjectHeader {
struct ObjectInfo {
int pathID;
int offset;
int length;
byte classID[8];
};
int ObjectCount;
ObjectInfo Object[];
};

这里,所有的 int 都是以小端编码的 4 字节整数(不同于外部文件格式采用的大端编码)。在 Unity3D 中,每个对象都有唯一的字符串 path ,但是在 asset bundle 里并没有直接保存字符串,而是一个 hash 过的整数,也可以看成是对这个对象的索引号。真正的对象放在数据头的后面,偏移量为 offset 的地方。

这里的 offset 是相对当前 asset 块的。如果想取得正确的相对整个文件的位置,应该是文件的 HeaderSize + asset 的 offset + asset 的 dataOffset + 这里的 object offset 。


接在 ObjectHeader 后的是 AssetRef 表,记录了 Asset 的引用关系。用于指明这个 bundle 内 asset 对外部 asset 的引用情况。AssetRefTable 结构如下:

struct AssetTable {
struct AssetRef {
byte GUID[8];
int type;
string filePath;
string assetPath;
};
int Count;
byte Unknown;
vector Refs;

Unity3D asset bundle 格式简析的更多相关文章

  1. JPEG/PNG/GIF图片格式简析

    JPEG/PNG/GIF是Web浏览器广泛支持的3种图片格式. 1.JPEG格式最适合保存照片和其他复杂图像. 2.GIF和PNG格式最适合保存logo和其他包含单色.线条.文本的简单图形. 3.JP ...

  2. 【HTTP】另类的POST头数据 RFC1867协议格式简析

    http://blog.csdn.net/ai2000ai/article/details/52161979 昨天在实战表单模拟提交的时候,有发现在提交某个表单的时候,页面(discuz!论坛)报错, ...

  3. Unity 4.x Asset Bundle 重名

    在 Unity 4.5.1f3中测试发现如下问题 两个不同文件下相同名字的资源打包成AssetBundle以后加载失败,提示错误  xxxxx can't be loaded because anot ...

  4. RecycleView + CardView 控件简析

    今天使用了V7包加入的RecycleView 和 CardView,写篇简析. 先上效果图: 原理图: 这是RecycleView的工作原理: 1.LayoutManager用来处理RecycleVi ...

  5. Android RecycleView + CardView 控件简析

    今天使用了V7包加入的RecycleView 和 CardView,写篇简析. 先上效果图: 原理图: 这是RecycleView的工作原理: 1.LayoutManager用来处理RecycleVi ...

  6. Java Annotation 及几个常用开源项目注解原理简析

    PDF 版: Java Annotation.pdf, PPT 版:Java Annotation.pptx, Keynote 版:Java Annotation.key 一.Annotation 示 ...

  7. zxing二维码扫描的流程简析(Android版)

    目前市面上二维码的扫描似乎用开源google的zxing比较多,接下去以2.2版本做一个简析吧,勿喷... 下载下来后定位两个文件夹,core和android,core是一些核心的库,android是 ...

  8. 简析TCP的三次握手与四次分手【转】

    转自 简析TCP的三次握手与四次分手 | 果冻想http://www.jellythink.com/archives/705 TCP是什么? 具体的关于TCP是什么,我不打算详细的说了:当你看到这篇文 ...

  9. Linux 目录结构学习与简析 Part1

    linux目录结构学习与简析 by:授客 QQ:1033553122 说明: /             linux系统目录树的起点 =============== /bin      User Bi ...

随机推荐

  1. macos下查看用户组,以及修改文件权限

    查看当前用户所属组 groups 查看指定用户所属组 groups username 更改权限 将单个文件更改为777权限 chmod 777 aaa.txt 更改文件夹所属组 sudo chown ...

  2. MARA 附加结构(增强字段)

  3. window cmd 自动补全

    1. 用命令里输入regedit注册表 WIN+R 快捷输入 regedit regedit2. 键值改为9(十进制) HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Co ...

  4. [Vim 使用]vim 自动括号补全配置

    打开Vim的配置文件,windows 上面的配置文件在vim 的安装目录下,_vimrc,使用记事本或vim打开 在下方加入如下代码 inoremap ( ()<ESC>i inorema ...

  5. html5--5-7 绘制圆/弧

    html5--5-7 绘制圆/弧 学习要点 掌握arc() 方法创建圆弧/曲线(用于创建圆或部分圆) 矩形的绘制方法 rect(x,y,w,h)创建一个矩形 strokeRect(x,y,w,hx,y ...

  6. http://www.cnblogs.com/yaozhenfa/archive/2015/06/14/4574898.html

    笔者这里采用的是mongoDB官网推荐使用.net驱动: http://mongodb.github.io/mongo-csharp-driver/2.0/getting_started/quick_ ...

  7. Windows下Tesseract4.0识别与中文手写字体训练

    一 . tesseract 4.0 安装及使用 1. tesseract 4.0 安装 安装包下载地址: http://digi.bib.uni-mannheim.de/tesseract/tesse ...

  8. zookeeper入门到精通

  9. [SHOI 2017] 寿司餐厅

    [题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=4873 [算法] 注意到题目中的限制条件可表述为 : 若选择区间[L , R] , 则 ...

  10. Android开发者的四大工具

    1. Basic4Android Basic4Android是Android平台上一个简单而又强大的可视化快速应用开发工具,它可被用来开发和测试数据库通信,甚至可以被用来开发2D的即时游戏! 主要特性 ...