Search Unity

How does saving work in webgl

Discussion in 'Web' started by witcher101, Mar 8, 2016.

  1. witcher101

    witcher101

    Joined:
    Sep 9, 2015
    Posts:
    516
    Does any1 know where is your save file located in webgl game.
    Also is it possible to manually specifiy a save location in a webgl game
     
  2. alexsuvorov

    alexsuvorov

    Unity Technologies

    Joined:
    Nov 15, 2015
    Posts:
    327
    Hello witcher101.

    WebGL does not have direct access to the local file system, as the content is run in a browser. All the files are therefore stored in the browser indexedDB. For example, PlayerPrefs can be found at IndexedDB - your_origin - /idbfs - FILE_DATA
     
    crns13, IM_prove and anton_moskalenko like this.
  3. witcher101

    witcher101

    Joined:
    Sep 9, 2015
    Posts:
    516
    Thanks
    Is it possible to save a file in a webserver and load it from there??
     
  4. alexsuvorov

    alexsuvorov

    Unity Technologies

    Joined:
    Nov 15, 2015
    Posts:
    327
    Note that while WebGL content is stored on a web server, it is actually executed on the client machine in the browser. So for a running WebGL application the web server is an external resource. WebGL can interact with the web server in the same way as any other web page. The web server should however be able to handle such interaction.
    A simple setup would be, for example, a php script on the server side, which receives data from the application in the url search string, and returns requested data back to the application. WebGL application can interact with such php script through WWW class. The php script can store the received data in the server file system or in the server database.

    If you need more sophisticated interaction (for example using multiple authorization steps etc.) then you might consider implementing interaction code in pure JavaScript using jslib plugin (http://docs.unity3d.com/Manual/webgl-interactingwithbrowserscripting.html).
    Note that if the domain of the web server you are interacting with is different from the WebGL content domain, then you should setup proper CORS headers on the web server side (http://docs.unity3d.com/Manual/webgl-networking.html)
     
    Last edited: Mar 9, 2016
    russisunni, crns13 and IM_prove like this.
  5. josiperez

    josiperez

    Joined:
    Jan 12, 2017
    Posts:
    32
    Hi,
    I am using Unity 5.5.2f1 in a local server with Wamp in Windows 10 and I am trying to write a file constructed with the game stages; in Editor or Standalone build it is ok - I see the files created, but when build to webGL, no.
    The debug.log for persistentDataPath is something like
    /idbfs/5402568062381725d960ff2f031ec669/myFile.csv
    but I can't find /idbfs even keeping system files as no hidden in the operating system.

    I searched at IndexedDB/your_origin and there, there is only log files.
    In c# code I used HandleIO.jslib and SyncFiles after close the file, as suggested in this forum.

    There is also a emscripten working with the idbfs filesystem. I need to mount the filesystem in the jslib function?
    Sorry, but I am a little confused.
    Can someone give me one direction?

    Thanks in advance
     
    Luis0413 likes this.
  6. Marco-Trivellato

    Marco-Trivellato

    Unity Technologies

    Joined:
    Jul 9, 2013
    Posts:
    1,654
    Saving to persistent data (to persistentDataPath) is implemented via IndexedDB and should work fine.

    I did a simple test that saves and loads a text file via System.IO.File.WriteAllText/ReadAllText, which seems to work. The only thing you need to be aware of is that modifications to the file system are not flushed immediately to IndexedDB, so it's better to implicitly do that by calling:
    Code (csharp):
    1. Application.ExternalEval("_JS_FileSystem_Sync();");
     
  7. josiperez

    josiperez

    Joined:
    Jan 12, 2017
    Posts:
    32
    Thank you Marco-Trivellato.
    Now, using your sync command, I can reopen the file from the IndexedDB and get the contentFile.

    My next step is to send this file or content to the webserver - for test purposes, at localhost:8080/execWEB.
    I create a results.txt inside execWEB project and sent a formWeb inside a coroutine in Unity:
    IEnumerator uploadFile(string fileName, string contentFile)
    {
    WWWForm formData = new WWWForm ();
    formData.AddField ("fileName", fileName);
    formData.AddField ("fileContent", contentFile);

    string loginURL = webProtocol + gameServerLocation + "/results.txt";
    WWW w = new WWW (loginURL, formData);
    yield return w;

    if (w.error != null) {
    Debug.Log ("w.error = " + w.error);
    } else {
    Debug.Log("w.text = " + w.text);
    }
    }

    I am thinking that results.txt will be growing and I can write a crontab awk, on the server, to send each file to a database, but:
    - results.txt is always 0 size;
    - apache log shows "POST /execWEB/results.txt HTTP/1.1" 200 - (200 it is a good code);
    - apache error log do not show something that looks my problem;
    - w.error and w.text are empty.

    What I am thinking or doing wrong? Can someone give me a direction?
    Thanks in advance.
     
  8. Brice-xCIT

    Brice-xCIT

    Joined:
    Jun 22, 2017
    Posts:
    5
    I'm unearthing this thread since, as of 2018.2.3, Application.ExternalEval is deprecated.

    Code (CSharp):
    1. [CS0618] `UnityEngine.Application.ExternalEval(string)' is obsolete:
    2. `Application.ExternalEval is deprecated. See https//docs.unity3d.com/Manual/webgl-interactingwithbrowserscripting.html for alternatives.'
    @Marco-Trivellato, is calling
    Application.ExternalEval("_JS_FileSystem_Sync();");
    still needed at all? Are there alternatives?
     
  9. JJJohan

    JJJohan

    Joined:
    Mar 18, 2016
    Posts:
    214
    Rather than calling ExternalEval you would invoke it directly - see Interacting with browser scripting.

    Code (CSharp):
    1. [DllImport("__Internal")]
    2. private static extern void JS_FileSystem_Sync();
    then elsewhere in your code call it.

    Code (CSharp):
    1. private void SyncJS()
    2. {
    3.     JS_FileSystem_Sync();
    4. }
    I omitted the _ prefix since it looks like it is no longer present in FileSystem.js
     
    Last edited: Sep 17, 2018
    abozhinov likes this.
  10. Brice-xCIT

    Brice-xCIT

    Joined:
    Jun 22, 2017
    Posts:
    5
    @JJJohan thanks for your reply. Your solution gives me a
    System.EntryPointNotFoundException: _JS_FileSystem_Sync
    exception, whether I prefix the method name with an underscore or not...
     
  11. JJJohan

    JJJohan

    Joined:
    Mar 18, 2016
    Posts:
    214
    Whoops - perhaps this method doesn't get compiled anymore, I'm not sure. What I use for my own project is my own jslib file which I can guarantee works, I just don't know if it's still the recommended way of doing it.

    e.g. in your own jslib file:

    Code (JavaScript):
    1.  //put into Assets/Plugins/WebGL/HandleIO.jslib
    2. var HandleIO = {
    3.      SyncFiles : function()
    4.      {
    5.          FS.syncfs(false,function (err) {
    6.              // handle callback
    7.          });
    8.      }
    9. };
    10. mergeInto(LibraryManager.library, HandleIO);
    Paired with this in C#

    Code (CSharp):
    1. [DllImport("__Internal")]
    2. private static extern void SyncFiles();
     
  12. abozhinov

    abozhinov

    Joined:
    Jun 9, 2019
    Posts:
    1
    This works in 2023 and seems to be the ideal solution for me.