ChinKang
ChinKang

Reputation: 4342

Unity WebGL editable configuration file

How to make an Unity WebGL project to read a kind of configuration file (any format), which is editable after the "Build" from Unity workspace.

Below is the sample of Build directory, which contains the packaged files enter image description here

The use case is to have the backend API using by this WebGL project to be configurable at the hosting server, so that when the player/user browse it, it knows where to connect to the backend API.

The closest part I could explore currently is to implement the custom Javascript browser scripting. Any advice or any existing API could be used from Unity?

Upvotes: 1

Views: 2435

Answers (1)

ChinKang
ChinKang

Reputation: 4342

An update for the chosen solution for this question. The Javascript browser scripting method was used.

Total of 3 files to be created:

  1. WebConfigurationManager.cs
    • Place it in the asset folder. This file is the main entry for the C# code, it decides where to get the web configuration, either via the default value from another C# class (while using the unity editor), or using the browser scripting method to retrieve (while browsing the distribution build via browser).
  2. WebConfigurationManager.jslib
    • Place it the same folder as WebConfigurationManager.cs. This file is the javascript code, to be loaded by browser.
  3. web-config.json
    • Your JSON configuration. The web configuration file could be hosted anywhere, example below placed under the root of the distribution build folder, you'll have to know where to load the file, for example https://<website>/web-config.json.

// WebConfigurationManager.cs
using System;
using UnityEngine;
using System.Runtime.InteropServices;
using AOT;

public class ConfigurationManager : MonoBehaviour
{

#if UNITY_WEBGL && !UNITY_EDITOR
    // Load the web-config.json from the browser, and result will be passed via EnvironmentConfigurationCallback 
    public delegate void EnvironmentConfigurationCallback(System.IntPtr ptr);

    [DllImport("__Internal")]
    private static extern void GetEnvironmentConfiguration(EnvironmentConfigurationCallback callback);

    void Start()
    {
        GetEnvironmentConfiguration(Callback);
    }

    [MonoPInvokeCallback(typeof(EnvironmentConfigurationCallback))]
    public static void Callback(System.IntPtr ptr)
    {
        string value = Marshal.PtrToStringAuto(ptr);
        try
        {
            var webConfig = JsonUtility.FromJson<MainConfig>(value);
            // webConfig contains the value loaded from web-config.json. MainConfig is the data model class of your configuration.
        }
        catch (Exception e)
        {
            Debug.LogError($"Failed to read configuration. {e.Message}");
        }
    }
#else
    void Start()
    {
        GetEnvironmentConfiguration();
    }

    private void GetEnvironmentConfiguration()
    {
        // do nothing on unity editor other than triggering the initialized event

        // mock the configuration for the use of Unity editor
        var testConfig = JsonUtility.FromJson<MainConfig>("{\n" +
              "  \"apiEndpoint\": \"ws://1.1.1.1:30080/events\",\n" +
              "  \"updateInterval\": 5\n" +
              "}");
        Debug.Log(testConfig.apiEndpoint);
        Debug.Log(testConfig.updateInterval);
    }

#endif
}
// WebConfigurationManager.jslib
mergeInto(LibraryManager.library, {

  GetEnvironmentConfiguration: function (obj) {
    function getPtrFromString(str) {
      var buffer = _malloc(lengthBytesUTF8(str) + 1);
      writeStringToMemory(str, buffer);
      return buffer;
    }

    var request = new XMLHttpRequest();
    // load the web-config.json via web request
    request.open("GET", "./web-config.json", true);
    request.onreadystatechange = function () {
      if (request.readyState === 4 && request.status === 200) {
        var buffer = getPtrFromString(request.responseText);
        Runtime.dynCall('vi', obj, [buffer]);
      }
    };
    request.send();
  }

});

Upvotes: 1

Related Questions