get saving working

This commit is contained in:
Corwin 2024-04-10 23:24:44 +01:00
parent 5365ce6188
commit 418f792ef2
No known key found for this signature in database
3 changed files with 75 additions and 30 deletions

View file

@ -10,12 +10,11 @@ import { GbaKey, KeyBindings } from "./bindings";
import { styled } from "styled-components";
import { useFrameSkip } from "./useFrameSkip.hook";
import { useController } from "./useController.hook";
type Module = any;
import { useLocalStorage } from "./useLocalStorage.hook";
interface MgbaProps {
gameUrl: string;
volume?: Number;
volume?: number;
controls: KeyBindings;
paused: boolean;
}
@ -55,14 +54,58 @@ async function downloadGame(gameUrl: string): Promise<ArrayBuffer> {
}
}
interface SaveGame {
[gameName: string]: number[];
}
export const Mgba = forwardRef<MgbaHandle, MgbaProps>(
({ gameUrl, volume, controls, paused }, ref) => {
const canvas = useRef(null);
const mgbaModule = useRef<Module>({} as mGBAEmulator);
const mgbaModule = useRef<mGBAEmulator>();
const [saveGame, setSaveGame] = useLocalStorage<SaveGame>(
{},
"agbrswebplayer/savegames"
);
const [state, setState] = useState(MgbaState.Uninitialised);
const [gameLoaded, setGameLoaded] = useState(false);
useEffect(() => {
function beforeUnload() {
const gameSplit = gameUrl.split("/");
const gameBaseName = gameSplit[gameSplit.length - 1];
const save = mgbaModule.current?.getSave();
if (!save) return;
setSaveGame({
...saveGame,
[gameBaseName]: [...save],
});
}
window.addEventListener("beforeunload", beforeUnload);
return () => {
window.removeEventListener("beforeunload", beforeUnload);
};
}, [gameUrl, saveGame, setSaveGame]);
useEffect(() => {
if (state !== MgbaState.Initialised) return;
const gameSplit = gameUrl.split("/");
const gameBaseName = gameSplit[gameSplit.length - 1];
const save = saveGame[gameBaseName];
if (!save) return;
const savePath = `${MGBA_ROM_DIRECTORY}/${gameBaseName}.sav`;
mgbaModule.current?.FS.writeFile(savePath, new Uint8Array([0, 1, 2, 3]));
}, [gameUrl, saveGame, state]);
useEffect(() => {
if (state !== MgbaState.Initialised) return;
(async () => {
@ -71,9 +114,9 @@ export const Mgba = forwardRef<MgbaHandle, MgbaProps>(
const gameBaseName = gameSplit[gameSplit.length - 1];
const gamePath = `${MGBA_ROM_DIRECTORY}/${gameBaseName}`;
mgbaModule.current.FS.writeFile(gamePath, new Uint8Array(gameData));
mgbaModule.current.loadGame(gamePath);
mgbaModule.current.setVolume(0.1); // for some reason you have to do this or you get no sound
mgbaModule.current?.FS.writeFile(gamePath, new Uint8Array(gameData));
mgbaModule.current?.loadGame(gamePath);
mgbaModule.current?.setVolume(0.1); // for some reason you have to do this or you get no sound
setGameLoaded(true);
})();
}, [state, gameUrl]);
@ -85,22 +128,19 @@ export const Mgba = forwardRef<MgbaHandle, MgbaProps>(
if (state !== MgbaState.Uninitialised) return;
setState(MgbaState.Initialising);
mgbaModule.current = {
canvas: canvas.current,
};
mGBA(mgbaModule.current).then((module: Module) => {
mgbaModule.current = module;
module.FSInit();
setState(MgbaState.Initialised);
});
const mModule = await mGBA({ canvas: canvas.current });
mgbaModule.current = mModule;
await mModule.FSInit();
await mModule.FSSync();
setState(MgbaState.Initialised);
})();
if (state === MgbaState.Initialised)
return () => {
try {
mgbaModule.current.quitGame();
mgbaModule.current.quitMgba();
mgbaModule.current?.quitGame();
mgbaModule.current?.quitMgba();
} catch {}
};
}, [state]);
@ -119,30 +159,31 @@ export const Mgba = forwardRef<MgbaHandle, MgbaProps>(
? "Return"
: value.toLowerCase().replace("arrow", "").replace("key", "");
mgbaModule.current.bindKey(binding, key);
mgbaModule.current?.bindKey(binding, key);
}
}, [controls, gameLoaded]);
useEffect(() => {
if (!gameLoaded) return;
mgbaModule.current.setVolume(volume ?? 1.0);
mgbaModule.current?.setVolume(volume ?? 1.0);
}, [gameLoaded, volume]);
useEffect(() => {
if (!gameLoaded) return;
if (paused) {
mgbaModule.current.pauseGame();
mgbaModule.current?.pauseGame();
} else {
mgbaModule.current.resumeGame();
mgbaModule.current?.resumeGame();
}
}, [gameLoaded, paused]);
useImperativeHandle(ref, () => {
return {
restart: () => mgbaModule.current.quickReload(),
buttonPress: (key: GbaKey) => mgbaModule.current.buttonPress(key),
buttonRelease: (key: GbaKey) => mgbaModule.current.buttonUnpress(key),
restart: () => mgbaModule.current?.quickReload(),
buttonPress: (key: GbaKey) => mgbaModule.current?.buttonPress(key),
buttonRelease: (key: GbaKey) => mgbaModule.current?.buttonUnpress(key),
saveGame: () => {},
};
});

View file

@ -2,7 +2,9 @@ import { MutableRefObject, useEffect } from "react";
import { mGBAEmulator } from "./vendor/mgba";
import { GbaKey } from "./bindings";
export function useController(mgbaModule: MutableRefObject<mGBAEmulator>) {
export function useController(
mgbaModule: MutableRefObject<mGBAEmulator | undefined>
) {
useEffect(() => {
let stopped = false;
@ -64,13 +66,13 @@ export function useController(mgbaModule: MutableRefObject<mGBAEmulator>) {
for (let oldButton of previouslyPressedButtons) {
if (!currentlyPressed.has(oldButton)) {
mgbaModule.current.buttonUnpress(oldButton);
mgbaModule.current?.buttonUnpress(oldButton);
}
}
for (let newButton of currentlyPressed) {
if (!previouslyPressedButtons.has(newButton)) {
mgbaModule.current.buttonPress(newButton);
mgbaModule.current?.buttonPress(newButton);
}
}

View file

@ -1,7 +1,9 @@
import { MutableRefObject, useEffect } from "react";
import { mGBAEmulator } from "./vendor/mgba";
export function useFrameSkip(mgbaModule: MutableRefObject<mGBAEmulator>) {
export function useFrameSkip(
mgbaModule: MutableRefObject<mGBAEmulator | undefined>
) {
useEffect(() => {
let previous: number | undefined = undefined;
let stopped = false;
@ -23,12 +25,12 @@ export function useFrameSkip(mgbaModule: MutableRefObject<mGBAEmulator>) {
if (totalTime >= 1 / 60) {
totalTime -= 1 / 60;
if (paused) {
mgbaModule.current.resumeGame();
mgbaModule.current?.resumeGame();
paused = false;
}
} else {
if (!paused) {
mgbaModule.current.pauseGame();
mgbaModule.current?.pauseGame();
paused = true;
}
}