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;

转载于:https://www.cnblogs.com/nafio/p/9137569.html

Unity3D asset bundle 格式简析相关推荐

  1. Unity3d资源反编译. AssetBundle格式简析+简单应用+爬坑

    ===================  Unity3d资源反编译工具 DisUnity ================ 源码:https://github.com/ata4/disunity 需要 ...

  2. 音频格式简析解惑之二——无损压缩格式

    APE格式 新一代的无损音频格式. APE的本质,其实它是一种无损压缩音频格式.庞大的WAV音频文件可以通过Monkey''s Audio这个软件进行"瘦身"压缩为APE.很时候它 ...

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

    昨天在实战表单模拟提交的时候,有发现在提交某个表单的时候,页面(discuz!论坛)报错,无法检测到数据来源云云,但是我确实提交了http_referer了啊,怎么会出现这个情况呢?问了下haohap ...

  4. 数据集标注文件JSON格式简析

    Hey,最近在处理数据集的标注问题,今天来简要介绍一下数据集标注文件的json格式. 主要简介一下主流数据集COCO:COCO的全称是Common Objects in Context,是微软团队提供 ...

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

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

  6. Android Jetpack组件App Startup简析

    1.前言 最近简单看了下google推出的框架Jetpack,感觉此框架的内容可以对平时的开发有很大的帮助,也可以解决很多开发中的问题,对代码的逻辑和UI界面实现深层解耦,打造数据驱动型UI界面. A ...

  7. Webpack模块化原理简析

    webpack模块化原理简析 1.webpack的核心原理 一切皆模块:在webpack中,css,html.js,静态资源文件等都可以视作模块:便于管理,利于重复利用: 按需加载:进行代码分割,实现 ...

  8. 静态库调用_静态链接和动态链接对比简析

    0. 简介 在Linux环境下进行开发工作,代码要经过编译链接生成二进制可执行文件,才能被CPU识别并执行:程序的编译过程可以参考另外一篇文章<linux程序编译过程简析>:链接过程分为两 ...

  9. jxl简析[ http://www.emlog.net/fei ]

    <摘自>飞:jxl简析:http://www.emlog.net/fei 最近,完成了一个网上报表系统,刚巧用到了一个 JAVA 操作 excel 表格的 API .闲来无事,就将其大概的 ...

  10. 匿名函数自我调用_Python中的匿名函数及递归思想简析

    匿名函数 前言 上次咱们基本说了一下函数的定义及简单使用,Python中的基本函数及其常用用法简析,现在咱们整点进阶一些的.同样都是小白,咱也不知道实际需要不,但是对于函数的执行顺序以及装饰器的理解还 ...

最新文章

  1. 基于TPS28225功率MOS半桥电路测试
  2. 线程池用过吗?ThreadPoolExecutor谈谈你的理解? —— 为什么用线程池?优势?|| 线程池如何使用?
  3. 虚拟机ubuntu19.04下设置idea快捷键
  4. SQL with(unlock)与with(readpast) (转)
  5. python调用winrar解压_批量文件解压缩脚本(Python3.5 + WinRAR)
  6. 静态路由与动态路由概念及实例
  7. 首批共享单车死于2019
  8. android 手环获取步数_荣耀手环5 篮球版深度体验:专业数据精细到“毛孔”
  9. 注册、登陆、审核练习
  10. 线程间通信 1全局变量2当前主对话框指针3发消息方式4 AfxBeginThread的返回值(为CWinThread类型的指针)5AfxGetApp...
  11. 创建Win2003域和Win2008域之间的信任关系,Active Directory系列之十八
  12. ML/DL-复习笔记【八】- 信息熵与相对熵(KL散度)
  13. Android/iOS 终端快速截屏技巧
  14. 台达PLC与台达DTE8路温控程序,威纶通触摸屏与温控器modbus485通讯
  15. Subclipse in Eclipse的安装和使用
  16. BME/BMP280环境传感器、MLX90614红外测温传感器、HX711称重模块 | Mixly纯干货课程
  17. android 5.0 n,EMUI 5.0遭泄漏 基于Android N制作!华为P9用户有福啦
  18. java地铁最短距离_北京地铁最短路径(Java+Dijkstra算法)
  19. 基于单片机水温自动控制系统设计-毕设课设资料
  20. Excel利用公式向导快速设置成绩的评级系统!

热门文章

  1. FAT32文件系统格式详解
  2. GitChat · 前端 | 从软件工程角度看大前端技术栈
  3. C# 简单管理系统模板 控制台应用程序
  4. 10大亮点解读--极通EWEBS4.0
  5. Flash Builder4.7破解方法
  6. 比较简单的win7升级win10的方法
  7. 软件工程-系统设计工程
  8. 深度学习-23:矩阵理论(L0/L1/L2范数)
  9. 电子科大+矩阵理论+真题总结
  10. python编程和excel_Excel Vs. Python?为Excel正名