torch2424 / wasmboy

Game Boy / Game Boy Color Emulator Library, ๐ŸŽฎwritten for WebAssembly using AssemblyScript. ๐Ÿš€Demos built with Preact and Svelte. โš›๏ธ
https://wasmboy.app/
GNU General Public License v3.0
1.4k stars 65 forks source link

"TypeError: idbKeyval.get is not a function" when attempting to save state in headless mode #312

Closed TheBlackParrot closed 4 years ago

TheBlackParrot commented 4 years ago
WasmBoy.saveState().then(function(state) {
    fs.writeFileSync(JSON.stringify(state), "./latest.sav");
    WasmBoy.play();
});
(node:36271) UnhandledPromiseRejectionWarning: TypeError: idbKeyval.get is not a function
    at saveStateTask (/home/theblackparrot/Games/Blockland/Add-Ons/Gamemode_BL_Plays_Pokemon/node_modules/wasmboy/dist/wasmboy.wasm.cjs.js:3060:45)
    at WasmBoyMemoryService.saveState (/home/theblackparrot/Games/Blockland/Add-Ons/Gamemode_BL_Plays_Pokemon/node_modules/wasmboy/dist/wasmboy.wasm.cjs.js:3111:12)
    at saveStateTask (/home/theblackparrot/Games/Blockland/Add-Ons/Gamemode_BL_Plays_Pokemon/node_modules/wasmboy/dist/wasmboy.wasm.cjs.js:5723:45)

Cool project so far! I just can't save states it seems.

torch2424 commented 4 years ago

@TheBlackParrot Ah oops! Yep that is a bug, IndexedDB wouldn't be available in Node, and it's a bug on my end, I'll try and fix it real quick :smile:

torch2424 commented 4 years ago

@TheBlackParrot This should now be published with a fix in version 0.5.1 :smile:

TheBlackParrot commented 4 years ago

Not getting the error anymore, but I can't load states as well it seems. Dunno if I'm not saving it correctly or what.

(node:18927) UnhandledPromiseRejectionWarning: TypeError: Found invalid object in transferList
    at Worker.postMessage (internal/worker.js:379:23)
    at SmartWorker.postMessage (/home/theblackparrot/Games/Blockland/Add-Ons/Gamemode_BL_Plays_Pokemon/node_modules/wasmboy/dist/wasmboy.wasm.cjs.js:3529:17)
    at loadStateTask (/home/theblackparrot/Games/Blockland/Add-Ons/Gamemode_BL_Plays_Pokemon/node_modules/wasmboy/dist/wasmboy.wasm.cjs.js:3158:25)
    at WasmBoyMemoryService.loadState (/home/theblackparrot/Games/Blockland/Add-Ons/Gamemode_BL_Plays_Pokemon/node_modules/wasmboy/dist/wasmboy.wasm.cjs.js:3173:12)
    at loadStateTask (/home/theblackparrot/Games/Blockland/Add-Ons/Gamemode_BL_Plays_Pokemon/node_modules/wasmboy/dist/wasmboy.wasm.cjs.js:5769:27)
    WasmBoy.loadROM(rom).then(function() {
        console.log("ROM loaded!");
        WasmBoy.play().then(function() {
            console.log("Playing!");
            try {
                WasmBoy.loadState(JSON.parse(fs.readFileSync("./latest.sav")));
            } catch(e) {
                console.error(e);
            }

latest.json.txt (Pokemon Red is the game I'm running if this is of any use to you (filenames are different, Github was being difficult about file types))

torch2424 commented 4 years ago

Ah so this is totally because I'm using WebWorker Transferables which needs to be a typed array. But since you are doing a JSON.parse() on a file, it's going to become a stringified array.

Ideally, I should detect and fix that. And I opened an issue at #314

In the meantime, can you convert the arrays in the object returned by JSON.parse() to a Uint8Array? That should fix it ๐Ÿ˜„

Also, since you are JSON.stringify-ing the typed Uint8Arrays, you may want to also convert those to normal arrays first, that way it isn't stringified a an object? ๐Ÿ‘

Let me know if that helps! Thankss! ๐Ÿ˜„

TheBlackParrot commented 4 years ago

That helped! Thanks! :tada:

WasmBoy.config(WasmBoyOptions, canvas).then(() => {
    console.log('WasmBoy is configured!');
    WasmBoy.loadROM(rom).then(function() {
        console.log("ROM loaded!");

        WasmBoy.play().then(function() {
            console.log("Playing!");

            setTimeout(async function() {
                try {
                    let state = JSON.parse(fs.readFileSync("./latest.sav"));

                    let nwIS = Uint8Array.from(state.wasmboyMemory.wasmBoyInternalState);
                    state.wasmboyMemory.wasmBoyInternalState = nwIS;
                    let nwPM = Uint8Array.from(state.wasmboyMemory.wasmBoyPaletteMemory);
                    state.wasmboyMemory.wasmBoyPaletteMemory = nwPM;
                    let ngBM = Uint8Array.from(state.wasmboyMemory.gameBoyMemory);
                    state.wasmboyMemory.gameBoyMemory = ngBM;
                    let ncR = Uint8Array.from(state.wasmboyMemory.cartridgeRam);
                    state.wasmboyMemory.cartridgeRam = ncR;

                    await WasmBoy.loadState(state);
                } catch(e) {
                    console.error(e);
                }
WasmBoy.saveState().then(function(state) {
    let nwIS = Array.from(state.wasmboyMemory.wasmBoyInternalState);
    state.wasmboyMemory.wasmBoyInternalState = nwIS;
    let nwPM = Array.from(state.wasmboyMemory.wasmBoyPaletteMemory);
    state.wasmboyMemory.wasmBoyPaletteMemory = nwPM;
    let ngBM = Array.from(state.wasmboyMemory.gameBoyMemory);
    state.wasmboyMemory.gameBoyMemory = ngBM;
    let ncR = Array.from(state.wasmboyMemory.cartridgeRam);
    state.wasmboyMemory.cartridgeRam = ncR;

    fs.writeFileSync("./latest.sav", JSON.stringify(state));
    WasmBoy.play();
});
torch2424 commented 4 years ago

Awesome! I'm glad it helped! @TheBlackParrot ๐Ÿ˜„ ๐Ÿ‘