【Unity】Addressableのカタログは分割可能と聞いたので試してみた

Addressableについて調べていたらもうこんな時間です。

アセットバンドルのビルドに数時間かかる事例を目にしたので、何かいい方法がないか調べていると、Addressableのカタログは分割が可能であるという情報をいくつか見つけました。

Addressables.LoadContentCatalogAsyncにカタログが置いてあるURLを渡すことで、カタログをロードすることができるそうです。
カタログのロード後は通常通りAddressables.LoadAssetAsyncなどでアセットのロードが可能になります。

https://docs.unity3d.com/ja/Packages/com.unity.addressables@1.20/manual/LoadContentCatalogAsync.html

https://synamon.hatenablog.com/entry/unity_addressables_catalog#Catalog%E3%81%AE%E5%88%86%E5%89%B2

「unity addressable カタログ 分割」で検索すると他にもいくつか出てきます。

しかし、この関数を使えばよいといった情報ばかりで、実例を見つけられなかったため、自分の想像している通りのことが可能か実際に試してみました。
(本当は、同じカタログの一部のアセットだけをビルドできれば良いのですが)

# 環境
Unity: 6000.0.38f1
Addressables: 2.2.2
アセットバンドル格納先: aws s3(CloudFront)

# 各種設定
### awsについて
本筋ではないので簡潔に。
参考にしたリンクと自分用の手順メモを貼っておきます。
(お金がかかる可能性があります。)

https://im0039kp.jp/%E3%80%90unity%E3%80%91addressables%E3%81%A8aws%E3%81%AEs3%EF%BC%8Bcloudfront%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%A6%E3%82%B5%E3%83%BC%E3%83%90%E3%81%8B%E3%82%89%E3%82%A2%E3%82%BB%E3%83%83/

<details><summary>手順メモ</summary>

- s3設定
推奨設定でバケットを作成
ブロックパブリックアクセス設定だけオフに変更
- CloudFront設定 
Origin domain...作成したs3のバケットを設定
オリジンアクセス...Legacy access identitiesを指定し、オリジンアクセスアイデンティティで新しいOAIを作成
バケットポリシーを自動で更新する
キャッシュビヘイビア...ビューワープロトコルポリシーをRedirect HTTP to HTTPSに変更
キャッシュキーとオリジンリクエスト...キャッシュポリシーをCachingDisableに変更(ここはCloudFrontのキャッシュ削除ができるようになったら、そのままにしてよさそう)
ウェブアプリケーションファイアウォール (WAF) ...お金がかかるので、いったんオフ
料金クラス...北米、欧州、アジア、中東、アフリカを使用

</details>

### Addressablesについて
Unityプロジェクトを新規作成してPackageManagerからAddressablesをインストールしたら、Settingsなどの設定を行います。

- Addressables Profiles
プロファイルを3つ作成し、RemoteのBuildPathとLoadPathを変更します。
BuildPathには、ServerData/data1/[BuildTarget]
LoadPathには、https://{Remote.RemoteURL}.cloudfront.net/AssetBundle/[BuildTarget]
を設定します。
各プロファイルでdata1、data2、data3とAssetBundle、AssetBundle2、AssetBundle3と設定します

- Addressable Asset Settings
<details><summary>こちらの画像を参考にしてください</summary>

![スクリーンショット 2025-02-25 234629.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3480806/a989f137-905c-453d-ba74-c1e1a49ef3e1.png)
![スクリーンショット 2025-02-25 234656.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3480806/be26fa08-8e3f-4c20-bdbe-5ab5fd38acde.png)

</details>

- Addressables Groups
FirstGroup、SecondGroup、ThirdGroupを作成し、それぞれ画像アセットを1つずつ追加します。
![スクリーンショット 2025-02-24 221051.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3480806/7e0783e7-7353-4f96-9d52-1032c3444b61.png)
Addressable Asset Groupなどの設定は、下の画像を参考にしてください。3種類とも同じ設定です。
<details><summary>Addressable Asset Group</summary>

![スクリーンショット 2025-02-24 220924.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3480806/3829627b-fce7-4b93-b0f1-ebf3948f03d7.png)

</details>
<details><summary>Bundled Asset Group Schema</summary>

![スクリーンショット 2025-02-25 235201.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3480806/82c5a9f4-08d0-48a5-b697-c1810b8dc8b8.png)

</details>

# 実験準備
### アセットのビルド
グループごとにアセットのビルドを行います。

必要な作業はAddressables Profilesウィンドウからプロファイルを切り替えることと、
Addressable Asset GroupのInclude In Buildを切り替えることです。

プロファイルごとに、Include In Buildのチェックが入っているアセットグループが一つだけになるように切り替えます。
切り替えたら、Addressables GroupsウィンドウのBuild->New Buildからビルドします。これを各プロファイルで行います。

ビルドが完了すると、Assetsなどのフォルダの並びにServerDataフォルダが作成されます。
ServerDataフォルダの中には、BuildPath通りにAssetBundleが配置されているので、それぞれ対応するLoadPath通りにs3へアップロードします。

<details><summary>s3の画像</summary>

今回の設定では下記のようにフォルダを用意して、対応する[BuildTarget]フォルダをそれぞれのs3フォルダにドロップする
![スクリーンショット 2025-02-24 220135.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3480806/ed95a1b5-8555-4d53-911b-31c9c269bd7e.png)


</details>

### プロジェクトのビルド
![スクリーンショット 2025-02-24 232042.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3480806/0ab990a5-1a9d-441d-9119-bbf39c5946d9.png)
画像のようなシーンを用意しました。catalogボタンでカタログを、imageボタンで対応するカタログの画像をロードし、表示します。
<details><summary>catalogボタンに設定した関数</summary>

```c#
public class AddressableTest : MonoBehaviour
{
    [SerializeField] TextMeshProUGUI text;

    string cloudFrontPath = "https://" + Remote.RemoteURL + ".cloudfront.net/";
    string[] bundlePaths = { "AssetBundle", "AssetBundle2", "AssetBundle3" };
    string catalogPath = "/StandaloneWindows64/catalog_0.1.0.json";

    public void LoadCatalog(int number)
    {
        string path = bundlePaths[number] + catalogPath;
        Addressables.LoadContentCatalogAsync(cloudFrontPath + path, true);
        text.text = "Load " + path;
    }
}
```

</details>
PreferenceのAddressablesの欄にある「Build Addressables on build Player」を
「Do Not~」に切り替えてからビルドする。

# 実験
![スクリーンショット 2025-02-24 235325.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3480806/889febe9-8f92-43b0-a679-8d9c58fc3fb3.png)
catalog1を押下し、それからimage1を押下する
=> FirstGroupに設定した画像が表示される

---
![スクリーンショット 2025-02-24 235339.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3480806/9c4abbee-c6a8-47de-9a5d-2735fd1a694d.png)
catalog2を押下せずにimage2を押下する
=> キーが存在しないというエラーが表示され、画像が読み込まれなかった時用の画像が表示される

---
![スクリーンショット 2025-02-24 235355.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3480806/84a57e4b-67dd-498f-a2d4-ad3876acd307.png)
catalog2を押下してから、image2を押下する
=> SecondGroupに設定した画像が表示される

---
アプリを一度再起動
![スクリーンショット 2025-02-24 235416.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3480806/b2d54ed5-a195-4700-b20c-5db86a1e9082.png)
catalog3を押下せずにimage3を押下する
=> なぜかThirdGroupに設定した画像が表示される
=> settings.jsonを確認すると、AssetBundle3のカタログがデフォルトになっていた
![スクリーンショット 2025-02-24 234738.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3480806/37d0438b-073b-4f83-863a-6e7ad62411cb.png)


# まとめ
LoadContentCatalogAsyncを使うことで、catalog(アセットバンドル)を分割しても、問題なくアセットをロードすることができました。
一点注意があり、アセットバンドルを分割した場合、分割をまたいで参照を持つことができなくなるそうです。この点は意識してアセットを分割するしかないです。(あるいは解決方法を探すか)

また、プロファイルとアセットグループの切り替えを手動で行うのはかなり面倒です。
そのため、エディター拡張などを行い、手軽に運用できる環境を整えていく必要がありそうです。