Extend Addressables with custom provider

Hey guys,
we want to add avatars/character icons to our multiplayer game.
There should be built-in icons (just sprites or prefabs) but it should also support icons from other sources.
Lets take facebook as an example.

The player sends an icon key (addressable key OR facebook thumbnail url) to the other players. This id is passed to the Addressables which resolves the id and returns either the asset bundle resource OR the downloaded sprite from facebook.

Is it possible to achieve this with the Addressable system and if so, how?
Maybe with a custom resource provider and/or operation?

Thanks for your help!

I found a solution:

Possible improvements:

  • Use an operation and use the ResourceManager to display events in the profiler
  • Support more types

Code

Resource Locator:

    /// <summary>
    /// Resource locator for urls.
    /// Resolves ids that start with "url:" to a ResourceLocation
    /// </summary>
    public class UrlResourceLocator : IResourceLocator
    {
        private const string PROTOCOL = "url:";
      
        public bool Locate(object key, Type type, out IList<IResourceLocation> locations)
        {
            if (key is string stringKey && stringKey.StartsWith(PROTOCOL))
            {
                string url = stringKey.Substring(PROTOCOL.Length);
              
                // Build the resource location with the url provider
                locations = new List<IResourceLocation>(1)
                {
                    new ResourceLocationBase(
                        "URL-" + url,
                        url,
                        typeof(UrlResourceProvider).FullName,
                        typeof(Sprite))
                };

                return true;
            }
          
            locations = null;
            return false;
        }

        public string LocatorId => GetType().FullName;
      
        public IEnumerable<object> Keys => new object[0];
    }

ResourceProvider:

    /// <summary>
    /// Provider for downloading sprites from an url
    /// </summary>
    public class UrlResourceProvider : ResourceProviderBase
    {
        public override void Provide(ProvideHandle provideHandle)
        {
            // Get the url from the IResourceLocation built by the ResourceLocator
            string url = provideHandle.Location.InternalId;

            UnityWebRequest webRequest = UnityWebRequestTexture.GetTexture(url);
          
            webRequest.SendWebRequest().completed += result =>
            {
                if(webRequest.result == UnityWebRequest.Result.Success)
                {
                    // Create the texture and sprite
                    Texture2D texture = ((DownloadHandlerTexture)webRequest.downloadHandler).texture;
                  
                    Sprite sprite = Sprite.Create(
                        texture,
                        new Rect(0f, 0f, texture.width, texture.height),
                        new Vector2(0.5f, 0.5f));
                  
                    // Resolve
                    provideHandle.Complete<Sprite>(sprite, sprite != null, null);
                }
                else
                {
                    // WebRequest failed, pass the exception
                    provideHandle.Complete<Sprite>(null, false, new Exception(webRequest.error));
                }
            };
        }
    }

Register locator and provider:

Addressables.AddResourceLocator(new UrlResourceLocator());
Addressables.ResourceManager.ResourceProviders.Add(new UrlResourceProvider());