diff --git a/data/loader.js b/data/loader.js index c15e727..7d62cad 100644 --- a/data/loader.js +++ b/data/loader.js @@ -202,4 +202,8 @@ if (typeof window.EJS_onSaveSave === "function") { window.EJS_emulator.on("saveSave", window.EJS_onSaveSave); } + if (typeof window.EJS_onSaveUpdate === "function") { + window.EJS_emulator.on("saveUpdate", window.EJS_onSaveUpdate); + window.EJS_emulator.enableSaveUpdateEvent(); + } })(); diff --git a/data/src/emulator.js b/data/src/emulator.js index 6727083..0308ba8 100644 --- a/data/src/emulator.js +++ b/data/src/emulator.js @@ -7176,5 +7176,54 @@ class EmulatorJS { return recorder; } + + enableSaveUpdateEvent() { + // https://stackoverflow.com/questions/7616461 + // Modified to accept a buffer instead of a string and return hex instead of an int + async function cyrb53(charBuffer, seed = 0) { + let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed; + for(let i = 0, ch; i < charBuffer.length; i++) { + ch = charBuffer[i]; + h1 = Math.imul(h1 ^ ch, 2654435761); + h2 = Math.imul(h2 ^ ch, 1597334677); + } + h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507); + h1 ^= Math.imul(h2 ^ (h2 >>> 13), 3266489909); + h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507); + h2 ^= Math.imul(h1 ^ (h1 >>> 13), 3266489909); + + // Cyrb53 is a 53-bit hash; we need 14 hex characters to represent it, and the first char will + // always be 0 or 1 (since it is only 1 bit) + return (4294967296 * (2097151 & h2) + (h1 >>> 0)).toString(16).padStart(14, "0"); + }; + + function withGameSaveHash(saveFile, callback) { + if (saveFile) { + cyrb53(saveFile).then(digest => callback(digest, saveFile)); + } else { + console.warn("Save file not found when attempting to hash"); + callback(null, null); + } + } + + var recentHash = null; + if (this.gameManager) { withGameSaveHash(this.gameManager.getSaveFile(false), (hash, _) => { recentHash = hash }) } + + this.on("saveSaveFiles", saveFile => { + withGameSaveHash(saveFile, (newHash, fileContents) => { + if (newHash && fileContents && newHash !== recentHash) { + recentHash = newHash; + this.takeScreenshot(this.capture.photo.source, this.capture.photo.format, this.capture.photo.upscale).then(({ screenshot, format }) => { + this.callEvent("saveUpdate", { + hash: newHash, + save: fileContents, + screenshot: screenshot, + format: format + }); + }) + } + }) + }) + } } window.EmulatorJS = EmulatorJS;