New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Emscripten: Allow replacing the filesystem used for "Save" folder #1173

Merged
merged 2 commits into from May 21, 2017

Conversation

Projects
None yet
3 participants
@Ghabry
Member

Ghabry commented May 20, 2017

This allows replacing the storage used by simply editing the index.html emscripten shell (Module.EASYRPG_FS = MY_FS) and implementing MY_FS.

Motivation: This allows somebody who hosts our Player to provide e.g. a web based storage (session based) instead of the default local storage.

Mostly for rmarchiv because it wants to provide server-baked storage.

Bonus:

Reference client implementation of a FS doing AJAX via VanillaJS to transmit save files. The server part is more work ;)

Format is in both directions.

{
    "1": "BASE64 OF SAVE01.LSD",
    "14": "BASE64 OF SAVE14.LSD"
}

Request URL hardcoded to "/save"

var SAMPLEFS = {
    mount: function(mount) {
    // reuse all of the core MEMFS functionality
    return MEMFS.mount.apply(null, arguments);
  },
  to_binary: function(dataURI){
    var base64 = dataURI.substring(0);
    var raw = window.atob(base64);
    var rawLength = raw.length;
    var array = new Uint8Array(new ArrayBuffer(rawLength));

    for(i = 0; i < rawLength; i++) {
      array[i] = raw.charCodeAt(i);
    }
    
    return array;
  },
  syncfs: function(mount, populate, callback) {
    //if (err) return callback(err); TODO Error handling
    if (populate) {
      var xhr = new XMLHttpRequest();
      xhr.withCredentials = true;
      xhr.onreadystatechange = function () {
        if (xhr.readyState === 4) {
          if (xhr.status === 200) {
            var obj = JSON.parse(xhr.responseText);

            for (var property in obj) {
              if (obj.hasOwnProperty(property)) {
                var nal = property.length == 1 ? "0" : "";
                var bin = SAMPLEFS.to_binary(obj[property]);
                var stream = FS.open(mount.mountpoint + "/Save" + nal + property + ".lsd", "w");
                FS.write(stream, bin, 0, bin.length, 0);
                FS.close(stream);
              }
            }
          } else {
            console.log('Error: ' + xhr.status);
          }
        }
      };
      xhr.open('GET', '/save');
      xhr.send(null);
    } else {
      var xhr = new XMLHttpRequest();
      xhr.withCredentials = true;
      xhr.onreadystatechange = function () {
        if (xhr.readyState === 4) {
          if (xhr.status !== 200) {
            console.log('Error: ' + xhr.status);
          }
        }
      };
      xhr.open('POST', '/save');

      var obj = {}
        FS.readdir(mount.mountpoint).forEach(function(x) {
        var num = parseInt(x.substr(4,2));
        if (!isNaN(num) && num >= 1 && num <= 15) {
          obj[num.toString()] = btoa(String.fromCharCode.apply(null, FS.readFile(mount.mountpoint + "/" + x)));
        }
      });
      xhr.send(JSON.stringify(obj));
    }

    callback(null);
  }
};
Module.EASYRPG_FS=SAMPLEFS;

Super basic test server (Lacks sanity checks!)

Put emscripten shell with the client code in the same folder as the python-script. Put a game in subfolder "game" (don't forget to create a index.json), run the script and visit localhost:5000

from flask import Flask,send_file
app = Flask(__name__)
from flask import request
import json

@app.route("/index.html.mem")
def mem():
    return send_file(open("index.html.mem", "rb"),mimetype="application/octet-stream")

@app.route("/")
def index():
    return open("index.html", "r").read()

@app.route("/<f>")
def start(f):
    return open(f, "r").read()

@app.route("/save", methods=['GET', 'POST'])
def save():
    if request.method == "POST":
        j = request.get_json(force=True)
        f=open("save.json", "w")
        f.write(json.dumps(j))
        print(j)
        f.close()
        return ""
    else:
        return open("save.json", "r").read()

@app.route("/play/games/default/<path:f>")
def game(f):
    return send_file(open("game/"+f, "rb"),mimetype="application/octet-stream")

if __name__ == "__main__":
    app.run()
Emscripten: Allow replacing the filesystem used for "Save" (by defaul…
…t IDBFS) with a custom file system.

This can be achived by providing a custom emscripten shell file which sets Module.EASYRPG_FS.
Cancel fast forward when the webplayer waits for important files.
Resulted in "Map not found" errors because they waiting was skipped.

Fixes #1174

@fdelapena fdelapena added this to the 0.5.2 milestone May 21, 2017

@carstene1ns carstene1ns merged commit 2e8352f into EasyRPG:master May 21, 2017

6 checks passed

Android (armeabi-v7a) Build finished.
Details
GNU/Linux Build finished.
Details
OSX Build finished.
Details
Windows (x64) Build finished.
Details
Windows (x86) Build finished.
Details
web Build finished.
Details

@Ghabry Ghabry deleted the Ghabry:emscripten-custom-save branch May 28, 2017

Ghabry pushed a commit to libretro/easyrpg-libretro that referenced this pull request May 22, 2018

Merge pull request #1173 from Ghabry/emscripten-custom-save
Emscripten: Allow replacing the filesystem used for "Save" folder
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment