【问题标题】:Returning a byte array from JavaScript to Emscripten/Unity Web Assembly将字节数组从 JavaScript 返回到 Emscripten/Unity Web Assembly
【发布时间】:2019-07-07 19:11:51
【问题描述】:

我有一些我正在序列化的 JavaScript 数据,以便 Unity 可以将其作为 byte[] 数组使用,如 generally described here。我想通过这样的 jslib 接口将这些数据公开给 Unity:

[DllImport("__Internal")]
private static extern byte[] GetByteArray();

我尝试使用 emscripten 中的内置方法将我的价值观与 JavaScript 联系起来:

  GetByteArray: function () {
    var myTypedArray = new Uint8Array([10, 20, 30, 40, 50]);
    var buf = _malloc(myTypedArray.length * myTypedArray.BYTES_PER_ELEMENT);
    writeArrayToMemory(myTypedArray, buf);
    return buf;
  },

不幸的是,这不起作用——WebAssembly C# 只是将一个长度为 0 的数组视为返回类型。我还尝试了HEAPU8.set(myTypedArray, buf) 之类的东西。

问题:

  1. 执行此操作的正确方法是什么?
  2. 如果做不到这一点,我是否至少从 JavaScript 到 C 的角度正确地做到了这一点? C# 表示字节数组的方式是否更有可能出现问题?

【问题讨论】:

    标签: c# unity3d emscripten webassembly


    【解决方案1】:

    希望您找到解决问题的方法。这是我的(非常老套的解决方案),但它有效:

    jslib

    GetByteArray: function(){
        var array = new Uint8Array([10, 20, 30, 40, 50]);
        var str = array.toString();
        str = '[' + str + ']';
        unityInstance.sendMessage('gameObject', 'ByteArrayAvailable', str);
    }
    

    c#

    #if UNITY_WEBGL && !UNITY_EDITOR
    
    [DllImport("__Internal")]
    private static extern void GetByteArray();
    
    #endif
    
    ...
        
    void CallWebGL()
    {
        GetByteArray();
    }
    
    void ByteArrayAvailable(string byteArrayStr)
    {
        var byteArray = JsonConvert.DeserializeObject<byte[]>(byteArrayStr);
    }
    

    您需要将 Newtonsoft.Json.dll 添加到您的插件文件夹以使其工作,但这是我发现使其工作的唯一简单方法:)

    【讨论】:

      【解决方案2】:

      秘诀是要有一个方法来实例化字节数组并从 js 上下文中调用它。实例化数组的方法然后调用实际填充字节数组的 js 方法。这是一个两步的过程。

      C#端

      [DllImport("__Internal", EntryPoint = "getByteArrayTmp")]
      private static extern void getByteArrayTmp(Action<int> instantiateByteArrayCallback);
      [DllImport("__Internal", EntryPoint = "getByteArray")]
      private static extern void getByteArray(Action callback, byte[] byteArray);
       
      private static event Action callbackEvent;
       
      public static byte[] byteArray;
       
      [MonoPInvokeCallback(typeof(Action))]
      private static void callback() {
          callbackEvent?.Invoke();
          callbackEvent = null;
      }
       
      [MonoPInvokeCallback(typeof(Action<int>))]
      private static void instantiateByteArrayCallback(int size) {
          byteArray = new byte[size];
          getByteArray(callback, byteArray);
      }
      

      用户实际调用的方法是

      public static void getByteArray(Action callback) {
          #if UNITY_WEBGL && !UNITY_EDITOR
              callbackEvent = null;
              callbackEvent += callback;
              getByteArrayTmp(instantiateByteArrayCallback);
          #endif
      }
      

      在 js 方面

      getByteArrayTmp: function(instantiateByteArrayCallback) {
          const byteArray = new Uint8Array([21, 31]);//example
          Module["yourplugin"].byteArray = byteArray;
          Module.dynCall_vi(instantiateByteArrayCallback, byteArray.length);
           
      },
      getByteArray: function(callback, byteArray) {
          Module.HEAPU8.set(Module["yourplugin"].byteArray, byteArray);
          Module.dynCall_v(callback);
      },
      

      这比使用字符串作为中间体快几倍。你可以像这样在不到一秒的时间内从 js 传输超过 20MB 到 Unity,而使用 string 方法则需要几秒钟。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-06-12
        • 1970-01-01
        • 2013-01-16
        • 1970-01-01
        • 2020-07-20
        • 1970-01-01
        相关资源
        最近更新 更多