Contents — 8 sections

VRChat向けのEditor Toolを作っていた。

最初のInstallは通る。

AnimatorもExpression Parametersも生成される。

「これならいける」と思って、同じアバターへもう一度Installした。

壊れた。

Expression ParametersからDLV_系のパラメータが7個消えた。

表示用AnimationClipを開くとCurveが0本になっていた。

一度目は正常。

二度目だけ壊れる。

生成ロジックそのものより、Assetの保存や再importの境界が怪しかった。

作っていたのは再実行される前提の導入ツール

対象はDancelaveというVRChat向けギミック。

Contact、Animator、Expression Menu / Parameters、表示用AnimationClipなどを自動生成し、選択したアバターの複製へ導入する。

元アバターは直接壊さない。

既存FXやExpressionsはコピーして追記する。

そして重要なのが、同じアバターへ何度Installしても壊れないこと。

ユーザーが一度しか押さない前提のToolではない。

だから再導入は、最初から品質要件の一部だった。

再導入すると7 ParameterとCurveが消えた

再現条件は単純だった。

  1. SDK同梱Robot AvatarへInstall
  2. 生成物を確認
  3. 同じAvatarへ再Install
  4. 同じパスへ生成物を作り直す
  5. Asset Databaseから再import
  6. 構造を再検査

症状は、

  • Expression ParametersからDLV_系7個が消える
  • Sender / Marker / Dance Effect用AnimationClipのCurveが0本になる

というもの。

厄介なのは、生成直後のメモリ上のObjectだけを見ると正常に見えることだった。

一度ディスクから読み直すと壊れる。

普通の「作った直後にassert」だけでは見逃せる。

原因はCreateAssetの順序だった

旧フローはだいたいこうだった。

  1. 空のAssetを作る
  2. CreateAsset で先にディスクへ置く
  3. その後で中身を書き換える
  4. 別のAsset操作やimportが走る

この順番だと、ディスク上には一度「空のAsset」が存在する。

再導入では、直前に同じ生成フォルダを削除し、同じパスへ作り直す。

その条件で後続importが走ると、ディスク上の空状態が読み直され、メモリ上で書き込んだ内容が失われた。

つまり問題は、

Unity Objectを変更したことと、その状態がAssetとして永続化されたことを同じだと思っていたこと

だった。

新規Assetは中身を完成させてからCreateAsset

修正は大掛かりではなかった。

新規Assetは、

旧:

CreateAsset
  ↓
中身を書き込む

ではなく、

新:

中身を完成させる
  ↓
CreateAsset

へ変更。

既存Assetは変更後、必要なタイミングで即保存するようにした。

さらにテスト側も変えた。

生成直後のObjectをそのまま検査するのではなく、

ディスクから再importしてから検査する。

ここが一番重要だった。

修正前は3件FAIL、修正後は56/56

スモーク試験は、SDK同梱Robot Avatarに対して、

  1. Build Shared Assetsを2回
  2. 重複がないことを確認
  3. 導入前Validation
  4. Install
  5. 導入後Validation
  6. 同じAvatarへ再Install
  7. 生成物をディスクから再import
  8. 構造を検査

まで通す。

検査対象は、

  • Contact値
  • localOnly
  • allowSelf / allowOthers
  • Animator Layer
  • Tracking / Weight
  • Driver
  • Expressions
  • Blueprint ID
  • AnimationClip内Path / Curve
  • 再導入後の重複
  • Write Defaultsの整合

など。

修正前のコードへ同じ試験を当てると3件FAIL。

修正後は56 / 56 PASS。

「直った気がする」ではなく、壊れる旧コードでテストが落ちることまで確認した。

Editorで通っても、購入者環境で通るとは限らない

その後、もう一段階進めた。

開発Projectには、

  • テストコード
  • 開発用Package
  • 過去の生成物
  • 依存Asset
  • 手元だけの設定

がある。

そこで、VRChat SDKだけの新しいProjectを作り、配布物と同じ中身だけを入れた。

結果は、

  • Compile Error 0
  • Smoke 68 / 68 PASS

さらに、Exporterで実際に書き出した Dancelave_v0.1.0.unitypackage を通常のimport経路で入れ直した。

配布物は33 files、54,876 bytes。

この状態でも68 / 68 PASS。

ここまで分けて初めて、

  • 開発Projectで動く
  • 再導入しても壊れない
  • 配布物だけでも動く
  • 実際のPackageをimportしても動く

を別々に確認できた。

一度作れたかより、二度作っても同じか

この件で一番大きかったのは、Idempotencyだった。

Editor Toolは「生成できるか」だけでは足りない。

  • 再生成
  • 再導入
  • 再import
  • 新規Project
  • 配布Package

まで通して初めて、実運用に耐える。

特にAsset生成では、

メモリ上のObjectとディスク上のAssetを分けて考える。

これはVRChat固有というより、Unity Editor Tool全般で効く話だった。

いまの結論

派手なギミックの不具合ではない。

ダンスが暴走したわけでもない。

原因は、かなり地味なAsset保存順序だった。

でも、こういう地味な不具合ほど販売後に踏むと重い。

一度目だけ通るToolより、二度目でも、別Projectでも、Package経由でも同じ結果になるToolの方が価値がある。

PicoTowaでは、完成画面だけでなく、こういう「二度目で壊れた」話も残していく。