Search Unity

[SOLVED] [WebGL] returning a byte[] from jslib to unity

Discussion in 'Web' started by mnml_, Jun 17, 2015.

  1. mnml_

    mnml_

    Joined:
    Jun 17, 2015
    Posts:
    44
  2. mnml_

    mnml_

    Joined:
    Jun 17, 2015
    Posts:
    44
  3. jonas-echterhoff

    jonas-echterhoff

    Unity Technologies

    Joined:
    Aug 18, 2005
    Posts:
    1,666
    What you can do:

    Make a function where you pass in a buffer and buffer size, and which returns a length.

    If the passed buffer is large enough, it will write to the buffer and return the length it wrote.

    If the passed buffer is to small, it will only return the required length.

    So, you can call it once passing 0 as buffer length, get the required length in the return value, allocate an array of that size and pass that when you call the function again.
     
    forcepusher likes this.
  4. mnml_

    mnml_

    Joined:
    Jun 17, 2015
    Posts:
    44
    I did it... if someone's curious, here's my hacky way to do it :)

    the part in the html template
    Code (javascript):
    1. <script type='text/javascript'>
    2. function sendfile(e){
    3.     var files = e.target.files;
    4.     for (var i = 0, f; f = files[i]; i++) {
    5.         var reader = new FileReader();
    6.         reader.onload = (function(file) {
    7.             return function(e) {
    8.                 (window.filedata = window.filedata ? window.filedata : {})[file.name] = e.target.result;
    9.                 SendMessage("DaefObject", "FileUpload", file.name);
    10.             }
    11.         })(f);
    12.         reader.readAsArrayBuffer(f);
    13.     }
    14. }
    15. </script>
    16. <input style="color:#ccc;" type="file" multiple="false" id="fileuploader" onchange="sendfile(event);return false;">
    the unity part
    Code (csharp):
    1.     public void FileUpload(string filename) {
    2.         var length = GetFileDataLength(filename);
    3.         Alert(length.ToString());
    4.  
    5.         var ptr = GetFileData(filename);
    6.         var data = new byte[length];
    7.         Marshal.Copy(ptr, data, 0, data.Length);
    8.         FreeFileData(filename);
    9.  
    10.         Alert(Encoding.ASCII.GetString(data));
    11.     }
    the jslib part
    Code (javascript):
    1. var LibraryFileOpen = {
    2.    Alert: function(msgptr) {
    3.      window.alert(Pointer_stringify(msgptr));
    4.    },
    5.    GetFileData: function(filenameptr) {
    6.      var filename = Pointer_stringify(filenameptr);
    7.      var filedata = window.filedata[filename];
    8.      var ptr = (window.fileptr = window.fileptr ? window.fileptr : {})[filename] = _malloc(filedata.byteLength);
    9.      var dataHeap = new Uint8Array(HEAPU8.buffer, ptr, filedata.byteLength);
    10.      dataHeap.set(new Uint8Array(filedata));
    11.      return ptr;
    12.    },
    13.    GetFileDataLength: function(filenameptr) {
    14.      var filename = Pointer_stringify(filenameptr);
    15.      console.log("GetFileDataLength");
    16.      console.log(filename);
    17.      console.log(window);
    18.      console.log(window.filedata);
    19.      return window.filedata[filename].byteLength;
    20.    },
    21.    FreeFileData: function(filenameptr) {
    22.      var filename = Pointer_stringify(filenameptr);
    23.      _free(window.fileptr[filename]);
    24.      delete window.fileptr[filename];
    25.      delete window.filedata[filename];
    26.    }
    27. };
    28.  
    29. mergeInto(LibraryManager.library, LibraryFileOpen);
     
  5. Baktillus

    Baktillus

    Joined:
    Apr 9, 2014
    Posts:
    2
    Sorry for necroposting.. This is pretty much the only resource i could find about this topic, so here goes.

    For some reason, SendMessage doesn't work for me. It did earlier, when I tried to do it in a different way, but now I copied your code to test it out and i get an alert ("ReferenceError: SendMessage is not defined").

    As I said, I was able to SendMessage before, but in the context of your HTML it just won't work.

    Any ideas?
     
  6. JJJohan

    JJJohan

    Joined:
    Mar 18, 2016
    Posts:
    214
    The Unity WebGL application is now loaded into an object in the default template. All you'd need to do is access SendMessage from the object.

    So instead of:

    SendMessage("object", "func", data);

    You'd call (if your object is called gameInstance):

    gameInstance.SendMessage("object", "func", data);

    From the documentation:

    var gameInstance = UnityLoader.instantiate("gameContainer", "Build/build.json", {onProgress: UnityProgress});
     
  7. Baktillus

    Baktillus

    Joined:
    Apr 9, 2014
    Posts:
    2
  8. ChrisWalsh3

    ChrisWalsh3

    Joined:
    Mar 30, 2016
    Posts:
    6
    @mnml_ Thanks a lot for this code, saved me a ton of time! One thing though - does the heap allocated in GetFileData ever get freed? [EDIT: after re-reading the code, yes it does!]
     
    Last edited: Apr 29, 2020
  9. Rufus31415

    Rufus31415

    Joined:
    Mar 16, 2020
    Posts:
    10
    @mnml_
    Very... very smart, thx !
     
  10. GS_Unity3D

    GS_Unity3D

    Joined:
    Jul 2, 2020
    Posts:
    2
    can we pass video streaming data to unity c# from javascript?
    if yes how? and how to play video in unity webgl from steaming data?
    please help me out.
     
  11. pretender

    pretender

    Joined:
    Mar 6, 2010
    Posts:
    865
    can you use this to replace UnityWebRequest for larger files to avoid memory allocation that can't be freed later?