您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關Unity3D中assetbundle格式的示例分析,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
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 ,又有它自己的數據頭。數據頭除了基本的數據頭結構 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游戲開發精華教程干貨(u3dnotes)。
關于“Unity3D中assetbundle格式的示例分析”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。