[Unity] AddressableAssetSystemの同期読み込み(Synchronous Addressables API)を試す

Uintyブログを見ているとAddressableAssetSystemにしれっと同期読み込みが追加されていることに気付く。
https://blogs.unity3d.com/jp/2021/04/14/find-out-whats-new-for-the-addressable-asset-system/

試してみることにした。

# 環境

- Unity2019.4.22f1
- Addressables 1.17.17

# Addressableのインストール
いつもどおりPackageManagerから
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159111/a41a2503-87d8-81ec-24d1-133fceb80ef9.png)

# 環境の準備
今回はCubeのPrefabをAddressableで同期読み込みしてみる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159111/e8039642-f0db-fe7c-70f2-e578bbe2f3e4.png)

PrefabをクリックしAddressableにチェックを入れ、アドレスをいい感じに設定する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159111/fea1ff36-1d9f-50c5-a087-29618b4f4a31.png)
Cubeという名前にした
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159111/b12bd31b-e15b-a8b5-42e4-2169ebb42aeb.png)

Groupウィンドウにも登録されているのを一応確認しておく
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159111/845baef4-5f76-4ec7-a346-602877bb748f.png)


# 読み込み処理を書いてみる

早速読み込みのコードを書いてみる

```cs:AddressableTest.cs
using UnityEngine;
using UnityEngine.AddressableAssets;

/// <summary>
/// Addressableのテストクラス
/// </summary>
public class AddressableTest : MonoBehaviour
{
    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.A))
        {
            var cube_prefab = Addressables.LoadAssetAsync<GameObject>("Cube").WaitForCompletion();
            if (cube_prefab == null) return;
            
            Instantiate(cube_prefab, Vector3.zero, Quaternion.identity);
        }
        
    }
}

```
.WaitForCompletion()
をつけてやると読み込み完了まで同期で待ってくれる。

このスクリプトをMainCameraにでもくっつけて実行してみる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159111/e17ae0be-a2fe-5eed-63a3-7556dbeebd23.png)

Aキーを押したらPrefabがInstantiateされた。動いてそうである。


# AssetReferenceにしてみる
文字列でのアドレス指定ではなくAssetReferenceでも読み込めるか一応確認してみる

```cs:AddressableTest.cs

using UnityEngine;
using UnityEngine.AddressableAssets;

/// <summary>
/// Addressableのテストクラス
/// </summary>
public class AddressableTest : MonoBehaviour
{
    [SerializeField] private AssetReference cubeAssetReference = null;
    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.A))
        {
            var cube_prefab = Addressables.LoadAssetAsync<GameObject>(cubeAssetReference).WaitForCompletion();
            if (cube_prefab == null) return;
            
            Instantiate(cube_prefab, Vector3.zero, Quaternion.identity);
        }
        
    }
}
```
InspectorからCubeを指定し読み込ませてみる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159111/5b36c2a8-e265-8917-ee78-16690561a97c.png)

同様に動作した。特に今までのAddressableの使い方を変えずに対応できそうだ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159111/20f8d4a2-3857-3f81-62ed-7b046e48f041.png)

# ローカルに無いDLが必要なアセットを同期読み込みしてみる
ユーザー体験的には絶対やっちゃ駄目なのだが、DLが発生する場合のリソース読み込みを同期でできるのか、試してみた。

Downloadというグループを作りそこにCubeを移動させる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159111/34545673-bdda-377d-45f9-a0cbd7851bab.png)

そしてBuildPathをRemoteBuildPath,LoadPathをRemoteLoadPathにする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159111/8eedd576-944a-7f24-6e66-e339c736299a.png)

AWSのS3にバケットを作成し、publicな状態でファイルをアップロードできるようにしておく（検証用なので雑設定）

AddressableのProfileのRemoteLoadPathをS3のファイルDLURLにしておく
![スクリーンショット_2021_04_28_2_15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159111/391274ee-18ba-d51b-001e-ffe8e529f626.png)
そしてAssetBundleをビルドする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159111/dac15f28-0977-fa2e-3bba-9a396e0be1b2.png)
プロジェクト直下のServerDataフォルダにプラットフォームフォルダとアセットバンドルが生成される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159111/e286c43d-110a-6dd8-2729-901910035a8a.png)

このプラットフォームフォルダごとS3にアップロードする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159111/7ab2a529-a783-32eb-b60d-49a51e02a13b.png)

最後にEditorで実行した際に実際のAssetBundleを読みに行くように設定を変更する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159111/86963fa2-e391-56c1-dffc-253f182f3644.png)

先程のコードのままこれで実行してみる
Aキーを押したところ１秒ほど立ってから表示された（画像じゃわからんね）
DLされてそうだ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159111/ab484d61-98d4-fede-1612-5f0bb65ca2d8.png)

一度実行するとキャッシュされちゃうのでキャッシュ削除処理をStartに追加して何度か試してみる

```cs:AddressableTest.cs
    private void Start()
    {
        Addressables.ClearDependencyCacheAsync("Cube");
    }
```

押す度に時間がかかるようになってるので再DLされてそうだ。

最後にS3からデータを消して落とせなくしてみる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159111/436af098-340e-1134-7bb1-bf8826df16c4.png)
バッチリ例外が出まくってる。これで今まで確実にDLしてたのが明らかになった。
![SampleScene_-_aas_test_-_PC__Mac___Linux_Standalone_-_Unity_2019_4_22f1_Personal__Personal___Metal__と_aas_test_–_AddressableTest_cs.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159111/0bd31c2d-e15b-9de8-c03a-ea46c9429f34.png)

DLする必要があってもちゃんと同期読み込みが可能であった。
UX的には不親切極まりないので非推奨だが覚えておいて損は無さそうだ。


# まとめ
Addressableは出た当初、非同期読み込みが一切できないという事が発覚しフォーラムが大変盛り上がっていたがUnity側も理解してくれてちゃんと同期APIが提供されたのは嬉しい限り。
起動時に設定ファイルを読み込む、みたいなユースケースだと非同期だと気にする範囲が多く、どうしても使いにくさを感じていたがこれにより解消された感がある。

今回のアップデートでAddressableがいよいよ実用的になったと感じる。
Resources.Loadをプロジェクトから完全に撲滅できるという人も多そうである。