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. Lua_第17 章 数学库

    第17 章 数学库 在这一章中(以下关于标准库的几章中相同)我的主要目的不是对每个函数给出完整地说明,而是告诉你标准库可以提供什么功能.为了可以清楚地说明问题,我可能 会忽略一些小的选项或者行为.基本 ...

  2. UVA 12130 - Summits(BFS+贪心)

    UVA 12130 - Summits 题目链接 题意:给定一个h * w的图,每一个位置有一个值.如今要求出这个图上的峰顶有多少个.峰顶是这样定义的.有一个d值,假设一个位置是峰顶.那么它不能走到不 ...

  3. 九度OJ 1123:采药 (01背包、DP、DFS)

    时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:2705 解决:1311 题目描述: 辰辰是个很有潜能.天资聪颖的孩子,他的梦想是称为世界上最伟大的医师. 为此,他想拜附近最有威望的医师为师 ...

  4. 九度OJ 1120:全排列 (DFS)

    时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:4471 解决:1139 题目描述: 给定一个由不同的小写字母组成的字符串,输出这个字符串的所有全排列. 我们假设对于小写字母有'a' < ...

  5. [2017-10-26]Abp系列——DTO入参验证使用方法及经验分享

    本系列目录:Abp介绍和经验分享-目录 声明式的入参验证逻辑 声明式入参验证主要使用了System.ComponentModel.DataAnnotations中提供的各种验证参数的Attribute ...

  6. git多人协作冲突解决方法

    http://www.trinea.cn/dev-tools/git-skill/ http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361 ...

  7. 关于git上传文件的一个小问题

    *** Please tell me who you are. Run git config --global user.email "you@example.com" git c ...

  8. html5 canvas 涂鸦画板

    html5 canvas 的涂鸦画板,可以加载图片进行涂鸦,也可以下载服务器使用的php上传的图片不能超过1M,只能是jpg或者png 格式的演示地址的服务器网速不怎么样,读取文件可能很慢,到达100 ...

  9. android中获取包名,类名

    LogUtil.i("getPackageName()=" + getPackageName()); //Context类 LogUtil.i("getClass().g ...

  10. UIButton设置为圆形按钮并增加边框

    设置按钮的长和宽尺寸一致(即为正方形),然后将圆角半径设为边长的一半,即形成一个圆形 UIButton *btn = [UIButton buttonWithType:UIButtonTypeSyst ...