From 123760e9ac3b9b52b109f30570ce17241a0f3d50 Mon Sep 17 00:00:00 2001
From: Ethan O'Brien <77750390+ethanaobrien@users.noreply.github.com>
Date: Mon, 3 Jul 2023 12:03:00 -0500
Subject: [PATCH] Keep states in browser
---
data/GameManager.js | 12 +++++----
data/emulator.js | 62 +++++++++++++++++++++++++++++++--------------
2 files changed, 50 insertions(+), 24 deletions(-)
diff --git a/data/GameManager.js b/data/GameManager.js
index 984286f..0bb7c54 100644
--- a/data/GameManager.js
+++ b/data/GameManager.js
@@ -82,16 +82,18 @@ class EJS_GameManager {
this.FS.writeFile('/game.state', state);
this.functions.loadState("game.state", 0);
setTimeout(() => {
- this.FS.unlink('game.state');
+ try {
+ this.FS.unlink('game.state');
+ } catch(e){}
}, 5000)
}
screenshot() {
this.functions.screenshot();
return this.FS.readFile('screenshot.png');
}
- quickSave() {
+ quickSave(slot) {
+ if (!slot) slot = 1;
(async () => {
- let slot = 0;
let name = slot + '-quick.state';
try {
this.FS.unlink(name);
@@ -100,9 +102,9 @@ class EJS_GameManager {
this.FS.writeFile('/'+name, data);
})();
}
- quickLoad() {
+ quickLoad(slot) {
+ if (!slot) slot = 1;
(async () => {
- let slot = 0;
let name = slot + '-quick.state';
this.functions.loadState(name, 0);
})();
diff --git a/data/emulator.js b/data/emulator.js
index f12b1a4..a9c3bf5 100644
--- a/data/emulator.js
+++ b/data/emulator.js
@@ -175,7 +175,8 @@ class EmulatorJS {
this.storage = {
rom: new window.EJS_STORAGE("EmulatorJS-roms", "rom"),
bios: new window.EJS_STORAGE("EmulatorJS-bios", "bios"),
- core: new window.EJS_STORAGE("EmulatorJS-core", "core")
+ core: new window.EJS_STORAGE("EmulatorJS-core", "core"),
+ states: new window.EJS_STORAGE("EmulatorJS-states", "states")
}
this.game.classList.add("ejs_game");
@@ -508,7 +509,7 @@ class EmulatorJS {
getBaseFileName() {
//Only once game and core is loaded
if (!this.started) return null;
- if (this.config.gameName) {
+ if (typeof this.config.gameName === "string") {
const invalidCharacters = /[#<$+%>!`&*'|{}/\\?"=@:^\r\n]/ig;
const name = this.config.gameName.replace(invalidCharacters, "").trim();
if (name) return name;
@@ -517,6 +518,9 @@ class EmulatorJS {
parts.splice(parts.length-1, 1);
return parts.join(".");
}
+ saveInBrowserSupported() {
+ return !!window.indexedDB && (typeof this.config.gameName === "string" || !this.config.gameUrl.startsWith("blob:"));
+ }
downloadStartState() {
if (typeof this.config.loadState !== "string") {
this.startGame();
@@ -798,11 +802,13 @@ class EmulatorJS {
hideMenu();
});
const qSave = addButton("Quick Save", false, () => {
- this.gameManager.quickSave();
+ const slot = this.settings['save-state-slot'] ? this.settings['save-state-slot'] : "1";
+ this.gameManager.quickSave(slot);
hideMenu();
});
const qLoad = addButton("Quick Load", false, () => {
- this.gameManager.quickLoad();
+ const slot = this.settings['save-state-slot'] ? this.settings['save-state-slot'] : "1";
+ this.gameManager.quickLoad(slot);
hideMenu();
});
addButton("EmulatorJS", false, () => {
@@ -989,19 +995,29 @@ class EmulatorJS {
});
if (called > 0) return;
if (stateUrl) URL.revokeObjectURL(stateUrl);
- const blob = new Blob([state]);
- stateUrl = URL.createObjectURL(blob);
- const a = this.createElement("a");
- a.href = stateUrl;
- a.download = this.getBaseFileName()+".state";
- a.click();
+ if (this.settings['save-state-location'] === "browser" && this.saveInBrowserSupported()) {
+ this.storage.states.put(this.getBaseFileName()+".state", state);
+ } else {
+ const blob = new Blob([state]);
+ stateUrl = URL.createObjectURL(blob);
+ const a = this.createElement("a");
+ a.href = stateUrl;
+ a.download = this.getBaseFileName()+".state";
+ a.click();
+ }
});
const loadState = addButton("Load State", '', async () => {
const called = this.callEvent("load");
if (called > 0) return;
- const file = await this.selectFile();
- const state = new Uint8Array(await file.arrayBuffer());
- this.gameManager.loadState(state);
+ if (this.settings['save-state-location'] === "browser" && this.saveInBrowserSupported()) {
+ this.storage.states.get(this.getBaseFileName()+".state").then(e => {
+ this.gameManager.loadState(e);
+ })
+ } else {
+ const file = await this.selectFile();
+ const state = new Uint8Array(await file.arrayBuffer());
+ this.gameManager.loadState(state);
+ }
});
const controlMenu = addButton("Control Settings", '', () => {
this.controlMenu.style.display = "";
@@ -2136,6 +2152,7 @@ class EmulatorJS {
}
menuOptionChanged(option, value) {
this.saveSettings();
+ console.log(option, value);
if (option === "shader") {
try {
this.Module.FS.unlink("/shader/shader.glslp");
@@ -2289,12 +2306,6 @@ class EmulatorJS {
addToMenu(this.localization("Disk"), "disk", diskLabels, this.gameManager.getCurrentDisk().toString());
}
-
- addToMenu(this.localization('FPS'), 'fps', {
- 'show': this.localization("show"),
- 'hide': this.localization("hide")
- }, 'hide');
-
if (window.EJS_SHADERS) {
addToMenu(this.localization('Shaders'), 'shader', {
'disabled': this.localization("Disabled"),
@@ -2307,6 +2318,19 @@ class EmulatorJS {
}, 'disabled');
}
+ addToMenu(this.localization('FPS'), 'fps', {
+ 'show': this.localization("show"),
+ 'hide': this.localization("hide")
+ }, 'hide');
+
+ if (this.saveInBrowserSupported()) {
+ addToMenu(this.localization('Save State Slot'), 'save-state-slot', ["1", "2", "3", "4", "5", "6", "7", "8", "9"], "1");
+ addToMenu(this.localization('Save State Location'), 'save-state-location', {
+ 'download': this.localization("Download"),
+ 'browser': this.localization("Keep in Browser")
+ }, 'download');
+ }
+
this.gameManager.getCoreOptions().split('\n').forEach((line, index) => {
let option = line.split('; ');
let name = option[0];