Persistent save file with online play compiled with Emscripten

Hoping we have someone with Emscripten knowledge who can help me further with this.

In short, after restarting the browser, my interpreter does no longer see the save file that was stored in the browser’s IndexedDB during the previous session.

Longer:
I recompiled my interpreter that is written in C so it can be run in a browser. I used a jquery terminal, Emscripten and help from forum member jkj yuio to glue everything together. Emscripten compiles the sources to a .wasm, a .js a datafile and an html file.
And it works, as you can see here (click).

What remains is an issue with the save file. Because the code does not have access to the local file system everything is stored in the browser. Save and restore work, but as soon as you close the browser the save data is gone.

Emscripten optionally supports the indexedDB file system which is persistent. So I recompiled with this option.
After a save I can see the save file with the browser’s dev tools. After I shut down the browser and restart the interpreter, the save file is still there, but the interpreter does not see it anymore. A restore gives a file not found error.

I feel I’m missing an action to reconnect to the database or so but I cannot find any examples.

I checked the Inform online play and they also keep the save files after the browser closes. But I don’t see any files in the IndexedDB so I think they use another mechanism.

1 Like

Have you mounted and enabled IDBFS persistence? In Infocom-Frotz I did so like this:

Module.preRun = () => {
    // Set up the saves folder with IDBFS
    FS.mkdir('/saves')
    FS.mount(IDBFS, {autoPersist: true}, '/saves')
    FS.chdir('/saves')
    FS.syncfs(true, err => {
        if (err) {
            console.log(err)
        }
    })
}

Not the autopersist and chdir (I include the full path when saving the file). Will add the autopersist and see what happens.

This routine is for when there’s no save directory yet and it is created. When you start the interpreter how can you check that the directory is already there from previous play? Maybe I must only mount it when it is already present?

I’ve been looking for an overview of all the FS-methods but cannot find one.

You do it in the preRun function so that it happens before the app starts up. The autoPersist option takes care of preparing the files.

Here are the docs: File System API — Emscripten 5.0.1-git (dev) documentation

I changed my C-code to this

int32_t InitIndexedDB() {
  // EM_ASM is a macro to call in-line JavaScript code.
  EM_ASM(
      // Make a directory other than '/'
      FS.mkdir('/XVAN_savefiles');

      // Then mount with IDBFS type

      FS.mount(IDBFS, {autoPersist: true}, '/XVAN_savefiles');

      // Then sync
      FS.syncfs(true, function (err) {
          // Error
      });
    );

  return(OK);
}

And it seems to work now. I can save and restore and when I close the browser, restart it and use restore as the first command I am back at the saved position. I must do more testing but it looks good.

Thank you very much for your help.

I now only have the possibility for one save file. Once I’m confident this works I want to expand for more save files, like with inform online play. How do you keep track of the saved files and filenames? With the fs.readdir() method? Or have you built something yourself?

I’ve only used it in Infocom-Frotz and I don’t know exactly how it does it. I assume through the regular C API for listing files in a directory.

If you allow players to choose filenames, then that is probably the way, though I guess you could remember the filenames in a separate file.

An idea I might try is having a limited number of slots, e.g. 20, and then you can just check that a filename like “save#.xyz” exists, where # is replaced by the slot number. Something like the save/restore screen from Doom or Quake. The downside is that players would need to re-use slots once they use all 20 for a particular game.

Yes, I was thinking about a separate file too, that is read when the interpreter starts. When the player types restore present all the filenames and let them pick one. I’ll see if I can get this working.