Autoload a savegame in the web player

Hello, I want to share a piece of code to silently load a savegame in the web player.

Context:
-A game have pre-existing savegame that needs to be present. It’s important as a meta-element to the story.
-We cannot use easyrpgPlayer.api.uploadSavegame because it’ll open a file selector dialog and we want the loading to be silent.
-Beside, the savegame is on the webserver, not on the player device.

Solution reached tonight:

async function autoLoadSave(saveFileUrl) { // mywebsite.com/Save15.lsd
    let slotNumber = saveFileUrl.substring(saveFileUrl.length-6, saveFileUrl.length-4);
    console.log("need to autoload " + saveFileUrl + " in the slot " + slotNumber);
    const dbName = "/easyrpg/910/Save"; //replace 910 by the number of your game
    const dbVersion = 21;

    // Check if the save already exists
    const saveExists = await checkSaveExists(dbName, "FILE_DATA", slotNumber);
    if (saveExists) {
        console.log(`Save ${slotNumber} already exists in IndexedDB, skipping import`);
        return;
    }

    // If save doesn't exist, proceed with loading
    const response = await fetch(saveFileUrl);
    const arrayBuffer = await response.arrayBuffer();
    const saveData = new Uint8Array(arrayBuffer);

    const buf = easyrpgPlayer._malloc(saveData.length);
    easyrpgPlayer.HEAPU8.set(saveData, buf);

    try {
        console.log("Loading save via private api.");
        easyrpgPlayer.api_private.uploadSavegameStep2(slotNumber, buf, saveData.length);
        easyrpgPlayer.api.refreshScene();
    } finally {
        easyrpgPlayer._free(buf);
    }
}

async function checkSaveExists(dbName, storeName, saveSlot) {
  return new Promise((resolve, reject) => {
      const request = indexedDB.open(dbName);
      request.onerror = () => reject(request.error);
      request.onsuccess = () => {
          const db = request.result;
          const transaction = db.transaction(storeName, 'readonly');
          const store = transaction.objectStore(storeName);
          
          // Construct the key path as it appears in the database
          const keyPath = `/easyrpg/910/Save/Save${saveSlot.padStart(2, '0')}.lsd`; //replace 910 here too
          const getRequest = store.get(keyPath);
          
          getRequest.onsuccess = () => {
              resolve(!!getRequest.result); // Convert to boolean
          };
          getRequest.onerror = () => reject(getRequest.error);
      };
  });
}

It needs to be called after easyrpgPlayer has been loaded, obviously.

See it in action here:

It’s not super clean (using setTimeout and a private api) but it works well enough.

Thanks again to all EasyRpg contributors, it’s really saving the hobby and makes people interested in playing/making RM200x games again.

Interesting. Instead of the IndexedDB API you can btw use the emscripten filesystem API which is imo cleaner (and works independent of the ?game variable). Is reachable via easyrpgPlayer.FS. The save folder is mounted in the Save subdirectory, so you can read it via easyrpgPlayer.FS.readdir("Save").

1 Like