Search Unity

  1. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice
  2. Enter the 2020.2 Beta Sweepstakes for a chance to win an Oculus Quest 2.
    Dismiss Notice

Put the C# to wasm build into single HTML

Discussion in 'Project Tiny' started by egonaraujo, Oct 15, 2019.

  1. egonaraujo


    Jan 21, 2015
    Has anyone been able to put the C# to wasm build into a single html file?

    I've done some progress on this but I cannot understand how the "*.symbols" and "Data" folder are accessed.

    I've managed to:
    - transform the .js into a script tag on the html
    - transform the wasm into base64 string, that gets decoded and executed inside the html file

    But I have no idea how the ".symbols" file work, if it gets read by the js or the wasm.. I have a pretty good understanding of what symbols are in programming, but I see no reference to this file.

    The Data folder is accessed using "CORS", from what I understand it is basically another type of request between servers, yet I do not know how to point this access to, for example, a base64 encoded version of the files inside the html.
  2. sercand


    Nov 7, 2013
    I believe that you can remove the ".symbols" file. I removed it before deploying the tiny project.
    But we don't deploy it with a single HTML file so I can't help you with that.
  3. egonaraujo


    Jan 21, 2015
    The ".symbols" file could really be removed, thanks sercand !

    For the curious out there, I was able to generate a single html5 file for my game by following these steps (I could not yet automate this process):

    1. Find <NameProject>\Library\PackageCache\com.unity.tiny@0.16.1-preview\DotsModules\Unity.Tiny.Image2DIOHTML\js~\ImageLoadingHTML.js;
    Inside, find the "js_html_loadImage" function and add this line
    Code (JavaScript):
    1. colorName = realAddress(colorName);
    before the "//start actual load" comment

    2. Find <NameProject>\Library\PackageCache\com.unity.tiny@0.16.1-preview\DotsModules\Unity.Tiny.AudioHTML\js~\AudioHTML.js;
    Inside, find the "js_html_audioStartLoadFile" function
    Find this line:
    Code (JavaScript):
    1. var request = new XMLHttpRequest();
    change the function from that line (inclusive) onward to this:
    Code (JavaScript):
    2.       self.audioBuffers[audioClipIdx] = 'loading';
    3.       var oldAudioName = audioClipName;
    4.       audioClipName = realAddress(audioClipName);
    5.       if(oldAudioName != audioClipName){
    6.          result = Uint8Array.from(atob(audioClipName), c => c.charCodeAt(0)).buffer;
    7.          self.audioContext.decodeAudioData(result, function (buffer) {
    8.             self.audioBuffers[audioClipIdx] = buffer;
    9.           });
    10.       }else{
    11.         self.audioBuffers[audioClipIdx] = 'error';
    12.       }
    13.       return audioClipIdx;
    3. Rebuild the project

    4. Find your <NameProject>.html and empty the initial <script> tag

    5. Find <NameProject>.js, inside find the function "__emscripten_fetch_xhr";
    Follow these steps in order, following the code, there are many calls to onerror and onsuccess so try to stick to the steps and aways find "the next bit of code that contains the string specified"

    • Find the line "var url_=UTF8ToString(url);"
    • Add below it "var newUrl = realAddress(url_);"
    • change "var xhr = new XMLHTTPRequest();" to "var xhr = {}";
    • remove " ..... timeoutMsecs;"
    • change "xhr.url_=url_" to "xhr.url_=newUrl; xhr.oldUrl = url_"
    • remove "if(overridden......RequestHeader(keyStr,valueStr)}}" (delete both '}')
    • change "xhr.onload=function(e){"to
      • if (xhr.oldUrl != xhr.url_){
      • xhr.response = Uint8Array.from(atob(xhr.url_), c => c.charCodeAt(0)).buffer;
    • add above
      • HEAPU16[fetch+40>>1]=xhr.readyState;
    • the lines
      • xhr.readyState=4;
      • xhr.status=0;
    • change 'e' in both onsuccess() and onerror() calls to "new ProgressEvent("type")"
      • -- check if the function has the closing ')'
    • change ';xhr.onerror=function(e){' to 'else{'
    • change 'e' to 'new ProgressEvent("type")' on onerror call
    • remove 'xhr.ontimeout......onerror......onerror(fetch,xhr,e)}' (delete two onerror calls)

    6. add
    NameProject.js in a new script tag below the closing script tag

    7. Encode the ".wasm" in base 64
    [for Windows]
    Code (Boo):
    1.  [Convert]::ToBase64String([IO.File]::ReadAllBytes($filename)) | Out-File -FilePath .\wamsbase64.txt
    8. change the whole initial <script> tag to:
    Code (JavaScript):
    2.   var Module = {};
    3.   var wasm_base64 = "<insert contents of file generated on 8>";
    4.   Module.wasm = Uint8Array.from(atob(wasm_base64), c => c.charCodeAt(0)).buffer;
    9. create realAddress() function, on the initial script tag, below step 8.
    returning the base64 version of each asset that calls it
    add "data:image/gif;base64," before the images, adjusting image type.
    Code (JavaScript):
    2. function realAddress(origAddress){
    3.   var imgPrefix = "data:image/png;base64,"
    4.   switch(origAddress){
    5.     case "Data/06d0a78b7523e833ed43a2db99db271e":
    7.       break;
    8.     case "Data/06d9b46da705bfa9fa2630444b62a4aa":
    9.       return imgPrefix + "iVBORw0KGgoAAAA.....RH/IAAAAASUVORK5CYII=";
    10.       break;
    11.     default:
    12.       return origAddress;
    13.       break;
    14.     }
    15. }
    Notes on findings with this method:
    base64 string with lots of A on the begginings are scenes
    base64 string with "iVBOR..." are pngs
    base64 string with "T2dn..." are oggs
    base64 string with "R0lGOD" are gifs

    This worked for project tiny 0.16.1
    DavidHutch and mgear like this.