Addressables × CRIの調査メモ

# Asset Support Add-on

参考: [CRIWARE Unity Plugin Manual - Asset Support Add-on](https://game.criware.jp/manual/unity_plugin/latest/contents/addon4u_assetsupport.html)

CRIWARE関連ファイルをUnityアセット形式で取り扱うことを可能にする公式アドオンプラグイン。

- CRI Assets
    - データのUnityアセット化とそれに伴う各種開発補助
- CRI Addressables
    - Addressable Asset Systemでのデータロードへの対応

CRIWARE関連ファイルはUnityではDefaultAsset扱いで、ファイルパスを指定する形で取り扱っていた。
これをUnityアセットとして認識させ、Addressablesでも扱えるようにするアドオン。

## CRI Assets

調査時点では v0.3.10
現在の最新版は v0.4.01

[Scripted Importer](https://docs.unity3d.com/ja/2021.3/Manual/ScriptedImporters.html)を活用して、CRIWARE関連ファイルをUnityアセットとして認識させる。

| 項目 | CRIWARE標準 | CRI Assets |
| --- | ---| ---|
|データの扱い | Non-Asset CRIデータ (ツール出力ファイル) | Unityアセット|
|参照方法 | ファイルパス|GUID参照|
|Editor拡張による開発サポート | コンポーネント/Editor Window | アセット単位で拡張 |
|データの配置場所 | StreamingAssetsまたはキャッシュフォルダ | プロジェクト内の任意のフォルダ |
|ストリーミング再生(単体ファイルから)|可能|可能|
|ストリーミング再生(AssetBundleから)|非対応|可能(CRI Addressables併用時のみ)|

※ 表は[CRIWARE Unity Plugin Manual - CRI Assets](https://game.criware.jp/manual/unity_plugin/latest/contents/addon4u_assetsupport_assets_overview.html)から引用

実装的にはScripted ImporterによってCRIWARE関連ファイルはScriptableObjectとして認識される。
クラス的には下図のような構成。

![cri_assets.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216890/6461e648-0981-2c03-dd1e-6a1c4ac21edf.png)

### CriAssetBase

各種アセットの基底抽象クラス。ScriptableObjectの派生クラス。
SerializeReference属性でICriAssetImplインタフェースを実装した型への参照を保持している。
このCriAssetBaseを継承してACB/ASB/ACFに対応した各クラスが実装されている。

ICriAssetImplを基底をしたインタフェースは以下の3つ

- ICriMemoryAssetImpl
    - オンメモリに展開されたデータへの参照
- ICriFileAssetImpl
    - ファイルとして保存されたデータへの参照
- ICriFsAssetImpl
    - CPKファイル内のコンテンツへの参照

#### ACFファイルのインスペクタ

![acf.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216890/8b561be6-43bc-6c55-2e83-c6d243d238bc.png)

#### ACBファイルのインスペクタ

紐付いたAWBファイルやキュー情報が確認できるのが便利。

![acb.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216890/ca08200e-3b69-6619-bcdd-8f3da5bfa8ef.png) 

### Deploy Type

各ファイルのインスペクタで設定するパラメータ。アセットの実データをどこに配置するかを表す。
詳細は[公式マニュアル](https://game.criware.jp/manual/unity_plugin/latest/contents/addon4u_assetsupport_assets_import.html)参照。

- StreamingAssets
- OnMemory
- Addressables (Local)
- Addressables (Remote)

※ CRI Addressablesのv0.4.09からAddressablesのLocalとRemoteは統合された。

## CRI Addressables

調査時点では v3.3.07
現在の最新版は v0.5.04

`CRI Assets`によりインポートした各種CRIアセットをAddressablesに対応させる。

### アンカーアセット

CRIアセット(ScriptableObject)からNon-Asset CRIデータへの依存関係を表現する便宜上のアセット。
`Deploy Type`をAddressablesにすると自動で生成される。CRIアセットとアンカーアセットは1:1で対応する。

![ 2023-02-15 16.50.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216890/808d4cbb-0c8d-5c9a-288c-8be4449e3dcb.png)

### CriDataグループ

アンカーアセットが生成されると、Addressablesに自動で追加されるグループ。
アンカーアセットが登録されており、CRI独自のResourceProviderによってリソース取得を行う。

![crigroup.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216890/545399e2-33d0-7617-9689-d74bd7aa173e.png)

### CriResourceProvider

`UnityWebRequest`と`DonwloadHandlerFile`を用いてNon-Asset CRIデータをキャッシュへダウンロードする。
キャッシュ済みの場合、またはダウンロード完了時に対象のNon-Asset CRIデータのパスをファイル名をキーとして`CriAddressables`に登録する。

### CriAddressableAssetImpl

CRI Assetsの`ICriFileAssetImpl`を実装したクラス。
ファイルパスとしてCriAddressablesからパスを取得して返す。

## AddressablesでCRIの各種アセットを扱う仕組み

###  ビルド時
    
1. CriDataグループに登録されたアンカーアセットがビルドされてアセットバンドルになる
1. ビルド完了をフックして、アンカーアセットのアセットバンドルをNon-Asset CRIデータと置換する

![ 2023-02-15 17.12.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216890/c440f26e-0644-2205-6765-b0305451fa1e.png)


下記がビルド完了のコールバックとして、置換を行うDeployメソッドを登録している箇所の実装

```C#:CriAddressableAssetsDeployer
[InitializeOnLoadMethod]
static void RegisterHook()
{
	BuildScript.buildCompleted += (AddressableAssetBuildResult result) => {
		if (EditorApplication.isPlayingOrWillChangePlaymode) return;
		Deploy();
	};
}
```

### ランタイム

1. CRIアセットを参照したコンポーネントを含んだプレハブのロード要求をする
1. CRIアセットはアンカーアセットを参照しているので、依存解決によってアンカーアセットのアセットバンドルを先にダウンロードしようとする
1. ビルド時にアンカーアセットのアセットバンドルはNon-Asset CRIデータにすり替えられているので、それを`CriResourceProvider`がダウンロードして保存したパスを登録する
1. CRIアセットが内部的に保持しているファイル名をキーとして`CriAddressables`に問い合わせて再生などの処理を行う

## その他気になったこと

- 登録するパスのキーがファイル名なので、フォルダが違うだけでファイル名が同一の場合に困る
    - v0.3.13でBundleNameを併用するようになったので解決
- Addressablesのカタログにはアンカーアセットのアセットバンドルのサイズが記載されてしまう
    - ランタイムに再計算する`CriWare.Assets.CriAddressables.ModifyLocators`メソッドが提供されている
- Addressablesの通信並列数の制御から外れている。外付け拡張なので仕方がない
- ビルド完了時の置換の都合上、Addressablesの`BundleNameingMode`を`Filename`から変えられない
- prefabなどのアセットから参照されていないアンカーアセットは置換が行われない
- ビルドするのはアンカーアセットなので、Non-Asset CRIデータを更新しても、Addressables的には更新扱いにならない
    - アンカーアセットを再生成すれば解決する
    - v0.5.04で一括再生成する機能が追加された