Live2Dの除霊記録
概要
除霊した。成仏してくれ。
やばかったところ
OnPostprocessAllAssets ってあるじゃない。
ドキュメント
https://docs.unity3d.com/ScriptReference/AssetPostprocessor.OnPostprocessAllAssets.html
大事なこととしては、
「このAPIは全体で1回だけ走ります」とか
一切書いてないことで。
つまりこのメソッド、Unityが「あー全部読み込み終わったわ~」ってなったら、いつでも着火する可能性があるんだな。
で、Live2DのPostprocessではこのメソッドにフックする形でResourcesの生成やモデルのインポート時処理をしており、
これは複数回呼ばれる必要が全くないのに不必要に何回も呼ばれてしまうことがある。
結果的に、
「開いていたシーンに謎のサンプルキャラクターが発生する」
「無限にインポートが発生して終わらない」
などが起こり得る。
除霊内容
・Assetがnullな時にAssetDatabaseを使わない(string.Emptyが返ってくる
・Live2Dがインストールされている箇所の取得を行う
などをやった。
Assetがnullな時にAssetDatabaseを使わない(string.Emptyが返ってくる
Live2Dの中で、Resourcesに入っているAssetの読み込み順が不自然だった時に発生する。
OnPostprocessAllAssets は、そりゃあまあ最後のインポート後に実行される、、はずなんだけど、どこを「最後」とみなすかはUnity次第で。
これが、例えば「Live2Dのインポートが終わる前に、別の仕掛けでリソース生成をして、
そのimportが終わった」みたいな悪魔のようなタイミングで発生するとどうなるか。
Live2Dでは、AssetDatabaseに対してimport済みのResourceを突っ込む処理があり、その時、このResourceがnullな可能性がある。
で、null を放り込むとどうなるか?
返ってくるのはstring.Emptyなんだこれが。
初めて知ったけどさ。
AssetDatabaseに対して検索目的でAssetを放り込む場合、
・nullチェックして
・AssetDatabaseに放り込む
とかをやったほうがいい。少なくとも返ってきたものがstring.Emptyじゃないかどうかみたいなチェックはすべきだ。
Live2Dのコードはそういうのをやってなかったので、見事にstring.Emptyが入った。
で、入った結果どうなるか?
ルート/Materials みたいなところにリソースを作ろうとする。当然これはaccess denyされる。
この辺は次のように解決できる。
・Assetのリファレンスを使わない(パスベースで解決する。
・ディレクトリはある? あるなら生成が成功してるはず。
みたいな。 Resource系で、nullになり得るものを信用してはいけない(教訓)。
Live2Dがインストールされている箇所の取得を行う
Live2D、デフォルトパス以外にAssetが移動することが考慮されてない。
Live2D自体のパスの導出に失敗して、前出のインポートエラーが起きたりする。
対策は2つで、
1.絶対に動かすなよって感じにガチガチに縛る。例えばSDK実行時にAssets直下でなかったらエラー出す。
2.動かしてもいいように作る
オススメは2。利用しやすいほうが利用される。そして絶対パスは大体変なバグを生む。