> For the complete documentation index, see [llms.txt](https://obvious-game.gitbook.io/soap/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://obvious-game.gitbook.io/soap/useful-tips/addressables/solutions.md).

# Solutions

First, if you use Addressables that reference ScriptableObjects (SO), those SOs need to be Addressables as well. Then, you just need to ensure that everyone is using the same `AssetReference` and that the Addressable has been loaded before it is used.

There are a few solutions to achieve this:

1. Expose the `AssetReference` instead of the SO in your scripts, and then use a static class to load it. This class will also cache the loaded instances in a dictionary.

```csharp
using UnityEngine;
using UnityEngine.AddressableAssets;
using System.Collections.Generic;
using System.Threading.Tasks;

public static class AddressableSOHelper
{
    private static Dictionary<AssetReference, ScriptableObject> _loadedInstances = new Dictionary<AssetReference, ScriptableObject>();

    public static async Task<T> LoadSOAsync<T>(AssetReference assetReference) where T : ScriptableObject
    {
        if (_loadedInstances.TryGetValue(assetReference, out var loadedInstance))
        {
            return loadedInstance as T;
        }

        var loadOperation = assetReference.LoadAssetAsync<T>();
        T instance = await loadOperation.Task;
        _loadedInstances[assetReference] = instance;
        return instance;
    }

    public static void ReleaseAll()
    {
        foreach (var assetReference in _loadedInstances.Keys)
        {
            assetReference.ReleaseAsset();
        }
        _loadedInstances.Clear();
    }
}
```

To see how to use this, here’s an example:\
There is an `EnemySpawner` that loads the enemy prefab as an Addressable. Additionally, each enemy prefab has a script, `Enemy.cs`, which exposes a reference to an `AssetReference` of the SO event. The only difference when using SO events as Addressables is that we need to expose an `AssetReference` (instead of the SO), make the SO event an Addressable, and ensure we load it (using the static class) before using it.

```csharp
using Obvious.Soap;
using UnityEngine;
using UnityEngine.AddressableAssets;

public class Enemy : MonoBehaviour
{
    public AssetReference EventSOReference;
    private ScriptableEventNoParam _eventSO;
    
    async void Start()
    {
        _eventSO = await AddressableSOHelper.LoadSOAsync<ScriptableEventNoParam>(EventSOReference);
        _eventSO.OnRaised += Kill;
    }

    private void OnDestroy()
    {
        _eventSO.OnRaised -= Kill;
    }

    private void Kill()
    {
        Destroy(gameObject);
    }
}
```

```csharp
using System.Collections;
using Obvious.Soap;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using Random = UnityEngine.Random;

public class EnemySpawner : MonoBehaviour
{
    public AssetReference enemyPrefabReference;
    private AsyncOperationHandle<GameObject> enemyPrefabHandle;
    
    public AssetReference destroyEventReference;
    private ScriptableEventNoParam _eventSO;

    async void Start()
    {
        enemyPrefabHandle = Addressables.LoadAssetAsync<GameObject>(enemyPrefabReference);
        await enemyPrefabHandle.Task;
        _eventSO = await AddressableSOHelper.LoadSOAsync<ScriptableEventNoParam>(destroyEventReference);
        StartCoroutine(SpawnEnemies());
    }

    IEnumerator SpawnEnemies()
    {
        while (true)
        {
            yield return new WaitForSeconds(1f);
            Vector2 randomPosition = Random.insideUnitCircle * 10;
            var pos = new Vector3(randomPosition.x, 0, randomPosition.y);
            Addressables.InstantiateAsync(enemyPrefabReference, pos, Quaternion.identity)
                .WaitForCompletion();
        }
    }

    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
           _eventSO.Raise();
        }
    }

    private void OnDestroy()
    {
        if (enemyPrefabHandle.IsValid())
            Addressables.Release(enemyPrefabHandle);
        AddressableSOHelper.ReleaseAll();
    }
}
```

2. Load the `AssetReference` in one script, then pass it as a dependency to all other scripts that need a reference to it. This breaks the independence of SOs, but it works.
3. Create a "manager" or an SO database that will load all your `AssetReferences`. Any class that needs a specific SO will have to interact with this manager to get the loaded Addressable.
4. Create a loading scene that will load all Addressables, then load other scenes as Addressables. I found this solution [here](https://github.com/njelly/addressables-scriptableobjects-test?tab=readme-ov-file).

Of course, it would be great to be able to use the EventListeners and  the Bindings with Addressables, and I am planning to try to support that in the future. In the meantime, load and use the addressables SO by code and do not use the EventListeners or Bindings in Addressable loaded prefabs or scenes.
