Unity で AssetBudle が更新されたかどうかを知るための Hash をいい感じにしたい

December 7, 2019
Unity Unity 2018 AssetBundle

この記事は Akatsuki Advent Calendar 2019 7日目の記事です。

はじめに

ゲームのシステムを作っていると、「更新があったアセットだけを検知してダウンロードする」という機能が当たり前のように必要になります。
Unityではアセットバンドルという、複数のアセットをひとまとめにする機能があり、その機能を使ってアセットの配信を行うのがスタンダードです。また、アセットバンドルをビルドする際にmanifestファイルとういものが自動で生成され、その中にHash値が保存されているので、更新されたかどうかの判定にその値を使おう、と思っていたのですがいろいろありました、というお話。

ちなみに、Unity全然わからないマンなので間違ってたら指摘入れてください。

環境

Unity 2018.3.8f1
macOS Mojave(10.14.2)

何が起きたか

AssetBundleに更新が必要かどうかを判断するために、manifestのAssetFileHashを使っていました。
しかし、事件は起きました。

»> マシンを変えるとハッシュ値が変わる «<

えぇマジで?Hashだよ?と思いながらも調べてみると、同じことに悩んでいる方がいました。

http://sassembla.github.io/Public/2018:09:02%2010-17-07/2018:09:02%2010-17-07.html

AssetFileHashはLibraryフォルダが共有されないと一貫性を失ってしまう

つまり
・それまで変化がなければ一定の値を保っていた
・変化があった時「のみ」変わっていた
という特性だと思っていたのが、Libraryフォルダを生成するようなことがあるとこの一貫性が破綻する。

一応、Libフォルダが生成されることがトリガーで値が変わる、というのがわかっている状態だが、
これは例えば、
「先祖代々ABを作成していたマシンが死んだ」
「新たにABを生成するマシンにプロジェクトをpullして~」
みたいなタイミングで牙を剥く。

なるほど〜〜〜(複雑な感情が流れる)。

他にもトラップ有るかもしれないし、ちょっと動作確認してみるか、
ということで簡単なサンプル作って試してみることにしました。

  1. 適当な画像1枚を AssetBundle ビルドする
  2. その画像を編集して AssetBundle ビルドする
  3. その画像を元と全く同じ状態に戻して AssetBundle ビルドする

すると、1.AssetBundle3.AssetBundle のバイト数が違う
なぜ???と思いながら色々調べてみましたが、同じ方の別の記事でこのような記述を発見。

http://sassembla.github.io/Public/2015:02:04%2012-47-46/2015:02:04%2012-47-46.html

ところでAssetBundleは作り直すたびに違うサイズになる

上記でも触れたけどそういう感じ。
内容は一緒でも、作り直すたびにサイズが変化(誤差レベルだけど確実な変化)、もちろんcrcも変化する。
ただしcache後のサイズは変わらない。構成要素が一緒なんだからまあそう。

なるほど???(複雑な感情が流れる)

つまりなんだ、同じマシンの中でも変わる可能性があると。
何を信じればよいのだ。。。

どうしたか

結局、調べてもこれらの要件を満たすような値を取得する方法は見つかりませんでした。

無ければ、作るしか無い(管理するもの増えるの嫌だけど)。
ということで作りました。

https://github.com/3nan3/asset_bundle_hash

manifestファイルを引数に渡すと、1つのHash値を計算して返してくれます。
こんなイメージ

$ asset_bundle_hash AssetBundles/sample.manifest
678e851755589c2ed8905b10e0e8302a694af7e40ee86abacfa4bddfba859bb1

具体的な処理は以下の通りです。

  1. AssetBundle の manifestファイルを引数に指定して実行
  2. Assetsのファイルに対して、SHA256SumsファイルパスmetaファイルのSHA256Sumsを計算して、文字列結合
  3. 上記で求めた文字列を結合してSHA256Sumsを計算し、標準出力

使い方としては、SingleManifestファイルからAssetBundle一覧を取得して、順番にHash値を計算してリストとして渡すようにしてあげれば良いと思います。

さいごに

アセット以外の要因でHash値が変わってしまうと冗長構成が取れなくて非常に困ります。みなさんはどのように解決しているのでしょうか。。。同じように苦労している方がいらっしゃいましたら、とても情報交換がしたいところです。

参考

http://sassembla.github.io/Public/2018:09:02%2010-17-07/2018:09:02%2010-17-07.html http://sassembla.github.io/Public/2015:02:04%2012-47-46/2015:02:04%2012-47-46.html https://qiita.com/k7a/items/23d909ffeea3bab7dfcb

comments powered by Disqus