Search Unity

WebGL Read/Write

Discussion in 'Works In Progress - Archive' started by lorenalexm, Jun 25, 2015.

  1. lorenalexm

    lorenalexm

    Joined:
    Dec 14, 2012
    Posts:
    307
    A few months ago a discussion was started regarding being able to pass data back and forth between the desktop and WebPlayer/WebGL. Given a slow night at work I was able to able to whip up a proof of concept proving that this was possible, and was then promptly forgotten.

    Fast forward a couple of months to me cleaning up my projects folder, and I rediscover this hacked together mess. I took two hours out of my afternoon and rewrote the code in its entirety for readability and to demonstrate more was possible then just passing arbitrary strings, and threw everything up on GitHub. I have no immediate intentions of using this bit of code, and hoped that someone within the community could find some use of the sample instead of it collecting dust once again.

    The code and sample should explain itself, but if there are any questions or issues please feel free to ask and if any improvements are bugs are found feel free to report it on GitHub or send a pull request if fixed yourself!

    tl;dr; - Pass text data (text, xml, json) back and forth between the WebGL player and your desktop. Sources in GitHub repo, prebuilt demo and data file can be found in webgl folder. WebPlayer may prove to be compatible, but as it's on the way out I haven't done any testing.

    Source - https://github.com/lorenalexm/unity-browser-saving
    Demo - http://lorenalexm.github.io/unity-browser-saving/webgl/

    Screenshot (albiet not interesting)
    Screen Shot 2015-06-25 at 7.59.15 AM.png
     
    Last edited: Jun 25, 2015
  2. Tomnnn

    Tomnnn

    Joined:
    May 23, 2013
    Posts:
    4,148
    Yes, yes it was.

    It's great that you got the save button inside the save button working within the app. Is there any way to have the upload functionality inside the app also? The concern I raised in the previous discussion was about the utility of this on a web portal - would they let you modify the page is on to make use of the upload feature?
     
  3. lorenalexm

    lorenalexm

    Joined:
    Dec 14, 2012
    Posts:
    307
    It could definitely look into moving all the browser functionality into a WebGL jslib plugin, which would be bundled into the package output from Unity, but both methods require DOM manipulation in its current state.

    I am not aware of which portal(s) you are looking to publish to, but it may be worth taking note Kongregate (which seems to be one of the mainstream portals) allows you to either upload your own HTML and data files or embed to their page through an iframe - both of which meet the requirements of the package in its current state.
     
  4. Tomnnn

    Tomnnn

    Joined:
    May 23, 2013
    Posts:
    4,148
    If kongregate will let you do that, then it's fine :D

    Excellent work. The future of web based voxel planets with local storage is upon us.
     
  5. lorenalexm

    lorenalexm

    Joined:
    Dec 14, 2012
    Posts:
    307
    Thank you very much! I'm glad that you were able to find use of this package. If you have any questions, find anything wonky or just a suggestion please let me know!
     
  6. sumpfkraut

    sumpfkraut

    Joined:
    Jan 18, 2013
    Posts:
    242
    Thank you for sharing.
    I use a jslib for my project now, and save a text string.
    my jslib's:

    Save Text
    Code (JavaScript):
    1. var TextDownloaderPlugin = {
    2.   TextDownloader: function(str, fn) {
    3.       var msg = Pointer_stringify(str);
    4.       var fname = Pointer_stringify(fn);
    5.       var data = new Blob([msg], {type: 'text/plain'});
    6.       var link = document.createElement('a');
    7.       link.download = fname;
    8.       link.innerHTML = 'DownloadFile';
    9.       link.setAttribute('id', 'TextDownloaderLink');
    10.       if(window.webkitURL != null)
    11.       {
    12.           link.href = window.webkitURL.createObjectURL(data);
    13.       }
    14.       else
    15.       {
    16.           link.href = window.URL.createObjectURL(data);
    17.           link.onclick = function()
    18.           {
    19.               var child = document.getElementById('TextDownloaderLink');
    20.               child.parentNode.removeChild(child);
    21.           };
    22.           link.style.display = 'none';
    23.           document.body.appendChild(link);
    24.       }
    25.       link.click();
    26.   }
    27. };
    28. mergeInto(LibraryManager.library, TextDownloaderPlugin);
    c#
    Code (CSharp):
    1. using System.Runtime.InteropServices;
    2.  
    3. ...
    4.  
    5. [DllImport("__Internal")]
    6. private static extern void TextDownloader(string str, string fn);
    7.  
    8. ...
    9.  
    10. TextDownloader(saveString, fileName);

    Save Image
    Code (JavaScript):
    1. var ImageDownloaderPlugin = {
    2.   ImageDownloader: function(str, fn) {
    3.       var msg = Pointer_stringify(str);
    4.       var fname = Pointer_stringify(fn);
    5.       var contentType = 'image/jpeg';
    6.       function fixBinary (bin)
    7.       {
    8.         var length = bin.length;
    9.         var buf = new ArrayBuffer(length);
    10.         var arr = new Uint8Array(buf);
    11.         for (var i = 0; i < length; i++)
    12.         {
    13.               arr[i] = bin.charCodeAt(i);
    14.         }
    15.         return buf;
    16.       }
    17.       var binary = fixBinary(atob(msg));
    18.       var data = new Blob([binary], {type: contentType});
    19.       var link = document.createElement('a');
    20.       link.download = fname;
    21.       link.innerHTML = 'DownloadFile';
    22.       link.setAttribute('id', 'ImageDownloaderLink');
    23.       if(window.webkitURL != null)
    24.       {
    25.           link.href = window.webkitURL.createObjectURL(data);
    26.       }
    27.       else
    28.       {
    29.           link.href = window.URL.createObjectURL(data);
    30.           link.onclick = function()
    31.           {
    32.               var child = document.getElementById('ImageDownloaderLink');
    33.               child.parentNode.removeChild(child);
    34.           };
    35.           link.style.display = 'none';
    36.           document.body.appendChild(link);
    37.       }
    38.       link.click();
    39.   }
    40. };
    41. mergeInto(LibraryManager.library, ImageDownloaderPlugin);
    Code (CSharp):
    1. using System.Runtime.InteropServices;
    2.  
    3. ...
    4.  
    5. [DllImport("__Internal")]
    6. private static extern void ImageDownloader(string str, string fn);
    7. ...
    8.  
    9. //byte[] imageData = null;
    10. ImageDownloader(System.Convert.ToBase64String(imageData), imageFilename);

    Load Text
    Code (JavaScript):
    1. var TextUploaderPlugin = {
    2.   TextUploaderCaptureClick: function() {
    3.     if (!document.getElementById('TextUploaderInput')) {
    4.       var fileInput = document.createElement('input');
    5.       fileInput.setAttribute('type', 'file');
    6.       fileInput.setAttribute('id', 'TextUploaderInput');
    7.       fileInput.setAttribute('accept', 'text/txt');
    8.       fileInput.style.visibility = 'hidden';
    9.       fileInput.onclick = function (event) {
    10.         this.value = null;
    11.       };
    12.       fileInput.onchange = function (event) {
    13.         SendMessage('MYGAMEOBJECT', 'SavedFileSelected', URL.createObjectURL(event.target.files[0]));
    14.       }
    15.       document.body.appendChild(fileInput);
    16.     }
    17.     var OpenFileDialog = function() {
    18.       document.getElementById('TextUploaderInput').click();
    19.       document.getElementById('canvas').removeEventListener('click', OpenFileDialog);
    20.     };
    21.     document.getElementById('canvas').addEventListener('click', OpenFileDialog, false);
    22.   }
    23. };
    24. mergeInto(LibraryManager.library, TextUploaderPlugin);
    Code (CSharp):
    1. using System.Runtime.InteropServices;
    2.  
    3. ...
    4.  
    5. [DllImport("__Internal")]
    6. private static extern void TextUploaderCaptureClick();
    7.  
    8. ...
    9.  
    10. TextUploaderCaptureClick();
    11.  
    12. ...
    13.  
    14. void SavedFileSelected (string url) {
    15.     StartCoroutine(LoadText (url));
    16. }
    17. IEnumerator LoadText (string url) {
    18.     WWW sav = new WWW (url);
    19.     yield return sav;
    20.     string savedData = sav.text;
    21. }

    Load Image
    Code (JavaScript):
    1. var ImageUploaderPlugin = {
    2.   ImageUploaderCaptureClick: function() {
    3.     if (!document.getElementById('ImageUploaderInput')) {
    4.       var fileInput = document.createElement('input');
    5.       fileInput.setAttribute('type', 'file');
    6.       fileInput.setAttribute('id', 'ImageUploaderInput');
    7.       fileInput.setAttribute('accept', 'image/x-png, image/jpeg');
    8.       fileInput.style.visibility = 'hidden';
    9.       fileInput.onclick = function (event) {
    10.         this.value = null;
    11.       };
    12.       fileInput.onchange = function (event) {
    13.         SendMessage('MYGAMEOBJECT', 'FileSelected', URL.createObjectURL(event.target.files[0]));
    14.       }
    15.       document.body.appendChild(fileInput);
    16.     }
    17.     var OpenFileDialog = function() {
    18.       document.getElementById('ImageUploaderInput').click();
    19.       document.getElementById('canvas').removeEventListener('click', OpenFileDialog);
    20.     };
    21.     document.getElementById('canvas').addEventListener('click', OpenFileDialog, false);
    22.   }
    23. };
    24. mergeInto(LibraryManager.library, ImageUploaderPlugin);
    Code (CSharp):
    1. using System.Runtime.InteropServices;
    2.  
    3. ...
    4.  
    5. [DllImport("__Internal")]
    6. private static extern void ImageUploaderCaptureClick();
    7.  
    8. ...
    9.  
    10. ImageUploaderCaptureClick();
    11.  
    12. ...
    13.  
    14. void FileSelected (string url) {
    15.     StartCoroutine(LoadTexture (url));
    16. }
    17.  
    18. IEnumerator LoadTexture (string url)
    19. {
    20.     WWW image = new WWW (url);
    21.     yield return image;
    22.     Texture2D texture = new Texture2D (1, 1);
    23.     image.LoadImageIntoTexture (texture);
    24. }

    Sources:
    Image to blob
    Load image into WebGL

    Tested with Firefox, Chrome and Edge. Edge works too, but return a wrong (random) filename.
    (bug in edge)
     
    Last edited: Jun 16, 2016
    oranchad and KamilCSPS like this.