Unity 学习笔记之一AssetBundle

发表于2017-06-30
评论0 4.2k浏览

记录一下近期学习AssetBundle相关的一些知识点,作为备忘。

主要分为两部分,第一部分是关于Unity官方AssetBundleManager的实现解析,第二部分是关于打包后的AssetBundle文件格式。

1. AssetBundleManager结构和代码解析

AssetBundleManagerUnity官方提供的封装AssetBundle打包和加载接口的一个插件,集成在Unity的菜单中,便于AssetBundle正式上传部署到服务器之前进行本地的测试。

Unity 学习笔记之一AssetBundle

1  AssetBundleManager代码组织

如图1,它主要分为两部分,一部分是Editor菜单的实现部分,另一部分是AssetBundleManager主要逻辑实现。

1.1 Editor实现

Editor菜单有三个选项,分别用于本地AssetBundle测试的Simulation Mode,用于打包AssetBundleBuild功能以及用于本地创建的服务器进行测试的AssetBundle Server

Unity 学习笔记之一AssetBundle

2  AssetBundles菜单项

用于定义Editor以及功能实现的所有脚本都定义在AssetBundles命名空间。整个Editor部分功能的实现都是比较简单直接的。

AssetbundlesMenuItems.cs功能比较简单,主要定义Simulation Mode以及Build AssetBundles两个菜单项的响应函数。Simulation ModeAssetBundleManager.cs中的属性SimulateAssetBundleInEditor相关;当点击Build AssetBundles菜单时,会执行BuildScript中的BuildAssetBundles函数执行打包动作。

LaunchAssetBundleServer.cs&ExecuteInternalMono.cs是用于实现运行本地AssetBundle服务器功能的。在LaunchAssetBundleServer.cs中主要是执行AssetBundleServer.exe,通过保存进程PID来检测以及终止服务器进程,这里可以了解一些关于Unity中与进程相关的操作。

BuildScript.cs实现了基本的AssetBundle打包功能,主要是调用BuildPipeline.BuildAssetBundles函数,该函数的详细描述可以参考

https://docs.unity3d.com/ScriptReference/BuildPipeline.BuildAssetBundles.html

1.2 AssetBundleManager主逻辑实现

主要包括Utility.csAssetBundleManager.csAssetBundleLoadOperation.cs三个脚本实现。

Utility.cs主要是根据当前是否处于Editor模式分别获取BuildTarget以及RuntimePlatform,由于WebPlayerUnity 5.4版本后就不再支持,所以这里避免Warning,暂时屏蔽。

Unity 学习笔记之一AssetBundle

获取当前所处平台

AssetBundleManager.cs功能较为繁杂,主要分为初始化、加载Asset、卸载Asset,以及Update处理函数。

从调用Initialize初始化函数开始,就会执行加载AssetBundle的操作。对于开启Simulation Mode的情况,比较简单,就不做过多描述。重点看AssetBundle从服务器下载的流程。

 

Unity 学习笔记之一AssetBundle

4 初始化函数调用示意图

首先会获取加载AssetBundle所处的平台,比如Windows。紧接着会判断当前是否正在加载AssetBundle,如果没有,则判断需要加载的Bundle名是否已经在已加载的Bundle对象集合中,如果已经在m_LoadedAssetBundles中,则直接返回,否则从服务器进行下载。如果是加载manifest,则直接调用new WWW(url)进行下载;其他的bundle,则调用

LoadFromCacheOrDownload函数,并提供相应的版本号进行判断是否已经有缓存,如果有缓存,则不需要再从服务器重新下载减少带宽占用,并将当前的下载任务添加到

m_DownloadingWWWs集合中,该变量会在Update函数中用到。

如果已经加载过manifest文件,并且在assetbundle还没有处理完成时,会加载相应的依赖。加载依赖的过程分为三步,第一步是通过manifest文件获取所有的依赖,第二步是判断这些依赖是否有variants,第三步就通过调用前面提到过的LoadAssetBundleInternal加载依赖。

AssetBundleManager继承了MonoBehaviour,其实现了Update函数,其逻辑也比较清晰。在每一帧主要做三件事,第一是判断m_DownloadingWWWs中是否有下载完成的,如果有下载完成的,则把AssetBundle添加到m_LoadedAssetBundles;第二是从m_DownloadingWWWs中删除并释放已经下载完成的WWW对象;第三是遍历所有的加载操作对象,执行相应的Update函数。

每个Update函数的定义都各不相同,这一部分位于AssetBundleLoadOperation.csCodeMap如下,展示了定义的六个类的关系,其中绿色箭头表示继承,粉色箭头表示调用。Unity 学习笔记之一AssetBundle

5  AssetBundleLoadOperation CodeMap示意图

可以看出AssetBundleLoadOperation为基类,它本身继承自IEnumerator,并实现了MoveNext函数,这里的目的是用于Coroutine调用。最重要的两个核心调用分别是在类AssetBundleLoadLevelOperationUpdate函数中实现了加载场景的功能,在类AssetBundleLoadAssetOperationFullUpdate函数中实现了异步加载Asset的操作。

Unity 学习笔记之一AssetBundle

加载场景以及Asset调用

1.3加载AssetBundle实例

AssetBundle中还附带了四个使用的例子,以其中的LoadAsset.cs为例,其余三个大同小异。

LoadAsset.cs中,实现了Start函数,创建了两个协程,分别为Initialize

InstantiateGameObjectAsync,定义如下:

Unity 学习笔记之一AssetBundle

7  Start函数定义

Initialize函数主要是调用AssetBundleManager的同名函数执行加载AssetBundle的初始化操作,由于返回的仍然是IEnumerator类型,所以可以调用StartCoroutine作为协程进行调用。这里对于Unity中的协程,后面准备再深入写一篇文章来分析。

Unity 学习笔记之一AssetBundle

8  Initialize函数定义

InstantiateGameObjectAsync函数执行真正的加载Asset的操作,加载完成后,调用Instantiate函数创建prefab对象的一个实例,显示在场景中。

Unity 学习笔记之一AssetBundle

9  InstantiateGameObjectAsync函数定义

2. AssetBundle存储格式

AssetBundleBuild以后,文件类似于如下的形式,

Unity 学习笔记之一AssetBundle

10  AssetBundle文件目录组织

使用WinHex查看其二进制格式如下

Unity 学习笔记之一AssetBundle

11  压缩的AssetBundle文件二进制格式

其文件头为UnityFS,后面的字段大概可以猜测到为类型、支持的版本、Hash128,以及压缩后的真正数据。其压缩算法有LZ4LZMA。本来打算在没有Unity源码的情况下,逆向一下Unity解析bundle文件的过程,后来发现有一些现成的工具已经可以实现对Unity AssetBundle文件的解析,比如Unity Studio,除了解析,还可以预览某些类型的资源。

Unity 学习笔记之一AssetBundle

12  Unity Studio解析AssetBundle

但是对于游戏自定义加密处理过的AssetBundle就无法解析了,好在Unity Studio是开源的,可以根据特定游戏的需要做相应的修改。

Unity 学习笔记之一AssetBundle

13  Unity Studio解析代码

3. 参考文章

https://unity3d.com/cn/learn/tutorials/topics/scripting/assetbundles-and-assetbundle-manager?playlist=17117

http://www.xuanyusong.com/archives/2405

https://github.com/Perfare/UnityStudio

https://github.com/Unity-Technologies/AssetBundles-Browser

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引

0个评论