unityでいってみよう!

unityがチョットワカル位の人のブログ

AssetBundleをダンプしてみよう!

目的

AssetBundleをダンプしてAssetBundleの構造を理解します。

検証環境

Unity2021.3l7f1で検証を行いましたが、Unity2017以降であれば特に変更は無いと思います。

Tools

AssetBundleをダンプする為にはWebExtract・binary2textの2種類のToolを使用します。

これらのToolはUnityのインストール先ディレクトリ以下のEditor\Data\Toolsにありますのでこちらにパスを通すなりしてご利用下さい。

※これらのToolは念の為、AssetBundleをビルドしたUnityと同じバージョンのものをご利用下さい。

尚、これらのToolをUnityEditor上からGUIで実行するUnityCommandLineToolsというパッケージがありますので、そちらを利用するとコマンドラインから実行する必要が無いので便利です。

 WebExtract

圧縮されたAssetBundleを解凍する為のToolです。

コマンドライン

WebExtract AssetBundleFilePath

引数としてAssetBundleのパスを渡すのみで、オプション等はありません。

binary2text

Serializeされたファイルを人間が読めるテキストファイルへ変換するToolです。

コマンドライン

binary2text シリアライズファイルへのパス 出力先ファイルへのパス [-detailed][-largebinaryhashonly][-hexfloat]

指定可能なオプションは下記の通りです。

-detailed:詳細情報を付与します。

オプション無し

ID: -8471220842657547617 (ClassID: 115) MonoScript

オプションあり

ID: -8471220842657547617 (ClassID: 115)     0: MonoScript [size: 40, children: 6 pathID: -1417479521]

-largebinaryhashonly:巨大なバイナリデータはHash値のみを出力します

オプションなし

    m_FontData  (vector)
        size 350200 (int)
        data (char) #0: 0 1 0 0 0 19 1 0 0 4 0 0 F F T M a 16 139 S 0 5 W 220 0
        data (char) #25: 0 0 28 G D E F } 254 t 1 0 5 3 4 0 0 0 136 G P O S 17 176
        data (char) #50: r 161 0 5 12 140 0 0 K N G S U B O Q . 14 0 5 3 188 0 0 8
        data (char) #75: 208 O S / 2 0 166 203 151 0 0 1 184 0 0 0 ` c m a p 18 152 [ 196
        data (char) #100: 0 0 * 132 0 0 6 . c v t   J 218 K 250 0 0 ; 172 0 0 2 136 f
        data (char) #125: p g m ~ a 182 17 0 0 0 180 0 0 7 180 g a s p 0 24 0 9 0 5
...(以下略)...
    m_Ascent 14.4844 (float)

オプションあり

m_FontData  (vector)
    size 350200 (int)
        ArrayDataHash 63eb1d53e6c1708c
m_Ascent 14.4844 (float)

-hexfloat:float1をHexで出力します

オプション無し

m_DefValue[0] 1 (float)
bytes[0] 213 (UInt8)

オプションあり

m_DefValue[0] 1(0x3f800000) (float)
bytes[0] d5 (UInt8)

解凍・テキスト化!

早速、WebExtract/binary2textをそれぞれ利用して解凍 → テキストファイル化を行って行きます。

解凍

AssetBundleのファイル名がrawimageprefabの場合、解凍するコマンドは次の通りです。

WebExtract rawimageprefab

コマンドを実行すると、AssetBundleと同じ階層にAssetBundle名のディレクトリが作成されています。 そのディレクトリの中にはCAB-から始まる拡張子が無いファイルと拡張子が.resSのファイルが出力されます。 拡張子が無いファイルがシリアライズファイルで、.resSがリソースファイルです。2

CABファイルにはAssetをシリアライズ化したデータで構成されています。 また、既に記載した通り、AssetをAssetBundle化した場合はシリアライズファイル名はCAB-となりますが、SceneをAssetBundle化した場合はCAB-ではなくBuildPlayer-YYYY(YYYYはScene名)となります。(Addressablesでビルドした場合はBuildPlayer-とならないようです。)

CAB-の後ろに続く文字列はAssetBundleのファイル名をHash化したものです。 Hash値はAssetBundleに埋め込まれている為、AssetBundleをバイナリエディタ等で確認するとHash値を確認する事が出来ます。

テキストファイル化

上記で解凍したシリアライズファイル(拡張子が無いファイル)をbinary2textに渡すことで人間が読めるテキストファイルに出力することが出来ます。

オプションは必要に応じて指定すれば良いと思いますが、バイナリデータが含まれていると可読性が落ちる為、-largebinaryhashonlyを指定することをお勧めします。

上記で解凍したシリアライズファイルをテキストファイルへ変換するコマンドは下記の通りです。

binary2text CAB-82deffcb2a40184f7f37651f72bd2b50 CAB-82deffcb2a40184f7f37651f72bd2b50.text -largebinaryhashonly

テキストファイル解説

上記で作成したテキストファイル(CAB-82deffcb2a40184f7f37651f72bd2b50.text )を確認していきましょう!

External References

まず初めにExternal Referencesという行から始まっていることを確認出来る筈です。 その次の行からpathという文字から始まる行が続いていると思います。3 このブロックにはAssetBundle内から他のAssetBundleやリソースファイルを参照している場合、そのファイルへのパスが追加されます。

External References
path(1): "archive:/CAB-5bc189da2eff62b169e56057bb58bfdf/CAB-5bc189da2eff62b169e56057bb58bfdf" GUID: 00000000000000000000000000000000 Type: 0
path(2): "Library/unity default resources" GUID: 0000000000000000e000000000000000 Type: 0

path()で括られている数値は後程説明するm_FileIDの値です。 CAB-に続く文字列はAssetBundleのファイル名をHash化したものです。AssetBundleのファイル名そのものでは無い為、可読性が悪いですが、Hash値はAssetBundleファイルに含まれている為、一致するAssetBundleを見つける為にはAssetBundleファイルをgrepして下さい。

オブジェクトの定義

External Referencesブロックに続いて、IDから始まる行が確認できる筈です。 この行は一つのAssetを定義するブロックの先頭になります。

ID: 1 (ClassID: 142) AssetBundle

IDに続く数値はAssetBundle内でのオブジェクトIDです。このAssetBundle内では重複しませんが、他のAssetBundleとは重複しています。ClassIDに続く数値はYAML形式のClassIDで、その後にClassIDと対になる実際のClass名が続きます。 次の行からは、そのオブジェクトのプロパティ情報で構成されます。 プロパティ情報は、

プロパティ名  プロパティの値  プロパティの型 

で構成されます。

m_Name "rawimageprefab" (string)

プロパティ名の後にPPtrが続く場合、そのプロパティがポインタである事を表しています。

ID: 5387879631776031585 (ClassID: 224) RectTransform
    m_GameObject  (PPtr<GameObject>)
        m_FileID 0 (int)
        m_PathID 8680877022782407731 (SInt64)
...

ポインタはm_FileIDとm_PathIDから実態の場所を検索することが可能です。

m_FileID :実態が存在するファイルID 0:このAssetBundle内に存在している 0以外:External Referencesで指定されているpath(数値)

プロパティ名の後にPPtrが続く場合、そのプロパティがポインタである事を表しています。

ID: 5387879631776031585 (ClassID: 224) RectTransform m_GameObject (PPtr) m_FileID 0 (int) m_PathID 8680877022782407731 (SInt64) ...

m_PathID:オブジェクトID

上記の例では、m_FileIDが0、m_PathIDが8680877022782407731 とあるので、このファイル内で8680877022782407731 を検索すると下記のように定義されていることが分かります。

ID: 8680877022782407731 (ClassID: 1) GameObject
    m_Component  (vector)
        size 3 (int)
        data  (ComponentPair)
            component  (PPtr<Component>)
                m_FileID 0 (int)
                m_PathID 5387879631776031585 (SInt64)
        data  (ComponentPair)
            component  (PPtr<Component>)
                m_FileID 0 (int)
                m_PathID -4813361763885006494 (SInt64)
        data  (ComponentPair)
            component  (PPtr<Component>)
                m_FileID 0 (int)
                m_PathID 7863041924028432304 (SInt64)
 
    m_Layer 0 (unsigned int)
    m_Name "RawImagePrefab" (string)
    m_Tag 0 (UInt16)
    m_IsActive 1 (bool)

基本的には以上です。

最後に

テキストファイルを読む場合、先ず初めにExternal Referencesを確認し、次にID: 1 (ClassID: 142) AssetBundleを検索するのが良いでしょう。このブロックはAssetBundleクラスであり、m_PreloadTableプロパティで定義されているオブジェクトを順番に見ていくと、このAssetBundleに含まれているオブジェクトや他のファイルに依存しているオブジェクトを確認することが出来ます。


  1. floatだけではなくbyte値もHexで出力します。(むしろbyte値のHex化が本命?)
  2. Textureのようなシリアライズがされないデータが含まれる場合、シリアライズファイルとは別にシリアライズファイルと同盟で拡張子がresSのファイルが合わせて作成されます。
  3. AssetBundleが他のファイルと依存関係が無い場合は、pathから始まる行は存在しません。