Unity WebGL 可编辑配置文件

Unity WebGL editable configuration file

如何让Unity WebGL项目读取一种配置文件(任何格式),在Unity工作区"Build"后可编辑。

下面是Build目录的示例,里面有打包后的文件

用例是让此 WebGL 项目使用的后端 API 在托管服务器上 可配置 ,这样当 player/user浏览它,它知道在哪里连接到后端 API.

我目前可以探索的最接近的部分是实现自定义 Javascript browser scripting。任何建议或任何现有的 API 都可以从 Unity 使用吗?

针对此问题选择的解决方案的更新。使用了Javascript browser scripting方法。

总共要创建 3 个文件:

  1. WebConfigurationManager.cs
    • 将其放在资产文件夹中。此文件是 C# 代码的主要入口,它决定从何处获取 Web 配置,或者通过来自另一个 C# 的默认值 class (使用统一编辑器时) ,或使用浏览器脚本方法检索 (同时通过浏览器浏览分发版本).
  2. WebConfigurationManager.jslib
    • 将其放在与 WebConfigurationManager.cs 相同的文件夹中。此文件为javascript代码,由浏览器加载。
  3. web-config.json
    • 您的 JSON 配置。 Web 配置文件可以托管在任何地方,下面的示例放置在分发构建文件夹的根目录下,您必须知道在哪里加载文件,例如 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();
  }

});