Unity 3 D asset bundleフォーマットの概要

4041 ワード

http://blog.codingnow.com/2014/08/unity3d_asset_bundle.html
 
Unity 3 Dの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は、上記のファイルヘッダのデータ長にちょうど等しいはずです.
1つのassert bundleは、複数のassetファイルでパッケージ化され、これらのassetが順次パッケージ化されます.このような構造にシーケンス化されます.
struct AssetFileHeader {
     struct AssetFileInfo {
          string name;
          size_t offset;
          size_t length;
     };
     size_t FileCount;
     AssetFileInfo     File[];
};

これにより、パッケージ化された複数のAssetを分解することができます(多くの場合、1つしかありません).offsetはHeaderSizeを除いたオフセット量を表します.HeaderSizeにその部分のoffsetを加えてbundle全体に対するこの部分のファイルオフセットを得ることができます.
各assetには、独自のデータヘッダがあります.データヘッダには、基本的なデータヘッダ構造AssetHeaderのほか、追加の3つの部分があります.disunityはそれらをType-Tree ObjectPathとAssetRefと呼ぶ.注意:ここでFormatはUnity 3 Dのバージョンによって異なり、現在のバージョンのフォーマットにのみ関心を持っています.ここでFormatは9(他のバージョンのフォーマットは、サイズなどの問題で異なります).
struct AssetHeader {
     size_t TypeTreeSize;
     size_t FileSize;
     unsigned int Format;
     size_t dataOffset;
     size_t Unknown;

UnityはAssetデータに対して簡単で乱暴なシーケンス化操作を行った.シーケンス化プロセス全体は、各オブジェクトのデータ構造に対して行われます.TypeTreeはデータ構造そのものの記述であり,この記述により各オブジェクトを逆シーケンス化することができる.
AssetHeaderの後ろに続いているのがTypeTreeです.しかし、このType-Treeはasset bundleにとってオプションであり、データ構造の情報は事前にエンジンに配置できるため(エンジンの多くは固有のデータ型のみをサポートする).TypeTreeは、モバイルデバイスにパブリッシュされるとasset bundleにパッケージされません.
各assetオブジェクトにはclass idがあり、Type Treeで逆シーケンス化の方法を調べることができます.class idの具体的なタイプとの対応関係は、Unity 3 dの公式ドキュメントで調べることができます.しかし,差異比較をオブジェクトの1レベル(具体的な比較オブジェクトの具体的な属性ではなく)で行いたいだけであれば,具体的なオブジェクトの詳細情報を解く必要はなく,この部分にも関心はない.だからここも展開しません(disunityのコードを読むことに興味がありますが、フォーマットは複雑ではありません).
AssetHeaderでのType TreeSizeとは、Type Tree部分の大きさを指します.次に、各AssetObjectの記述データを示します.
struct ObjectHeader {
     struct ObjectInfo {
          int pathID;
          int offset;
          int length;
          byte classID[8];
     };
     int ObjectCount;
     ObjectInfo Object[];
};

ここで、すべてのintは、小端符号化の4バイト整数(外部ファイルフォーマットで採用されている大端符号化とは異なる)である.Unity 3 Dでは、各オブジェクトに一意の文字列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;