Wednesday, December 14, 2022

Unity Addressable Assets in WebGL with Dynamic Remote Load Path

 We recently worked on a Unity WebGL project that used Addressable Assets, and it included a library that required us to load the Addressables from a Remote Load Path.  However, we knew we would be hosting the final Addressable Assets at the same location as the WebGL application itself, so they would always have the same base URL.  This location could change, though depending whether we were testing on a staging server or a live server, and we didn't want to remake the Unity build for each location we would be deploying to.

Originally, it seemed that we had to have a fixed Remote Load Path URL for the Unity build, and we created a Python script that would replace the path from Unity with a custom path depending on where we knew we were deploying to.  This proved cumbersome, though, and we found a better solution.

This Unity forum thread provides some helpful information about how to specify Addressable Assets paths with more dynamic information.  The Addressable Assets system allows you to specify variables in the build and load paths that will be evaluated at either build time or runtime.  Based on that and the fact we can look up the current location a web page is running from using window.location.href, we can dynamically generate a Remote Load Path for our Addressables.

First, we create a MonoBehaviour to handle the dynamic path.  This is necessary in order to access it through Javascript at runtime.

using UnityEngine;

public class CustomAddressablePaths : MonoBehaviour
{
     public static string RemoteURL
     {
          if ( _instance != null )
          {
               if ( _instance.remoteURL.EndsWith( "/" ) )
               {
                    return _instance.remoteURL + "ServerData";
               }

               return _instance.remoteURL + "/ServerData";
          }

          return "";
     }

     private static CustomAddressablePaths _instance = null;

     private string remoteURL = "";

     private void Awake()
     {
          if ( _instance == null )
          {
               _instance = this;
          }
          else if ( _instance != this )
          {
               Destroy( gameObject );

               return;
          }

          DontDestroyOnLoad( gameObject );
     }

     public void SetRemoteURL( string remoteURL )
     {
          this.remoteURL = remoteURL;
     }
}

Now, in the Remote Load Path in the Addressables Profile, we can use the {} syntax to specify a runtime value of {CustomAddressablePaths.RemoteURL}.


In the startup scene of the project, create a new GameObject named CustomAddressablePaths and add the CustomAddressablePaths component.  In theory this should be set to exist before the Addressables system is initialized.

If you're not already using a custom WebGL template for the project, we can create a new one.  Copy the contents of <Unity Editor install path>\Editor\Data\PlaybackEngines\WebGLSupport\BuildTools\WebGLTemplates\Default to your project under Assets\WebGLTemplates.  Give it a new subfolder name (e.g. Assets\WebGLTemplates\MyNewTemplate).  Select the new template from the WebGL PlayerSettings "Resolution and Presentation" section.

In index.html in the custom WebGL template, find where createUnityInstance() is run, and where a variable called unityInstance is returned.  You can then run the following Javascript code:

unityInstance.SendMessage( "CustomAddressablePaths", "SetRemoteURL", window.location.href );


Finally, when deploying your WebGL game, assuming your index.html file is at <server root>\index.html, the built Addressable Assets should be at <server root>\ServerData.  Now when the Addressables system attempts to download an asset, it should use the correct URL.

No comments:

Post a Comment