Adding save fetch capabilities.
This commit is contained in:
parent
7ffeb360e7
commit
07273a40bf
|
@ -12,6 +12,7 @@ export interface OverlayMenuProps {
|
||||||
setIsFullscreen: (c: boolean) => void
|
setIsFullscreen: (c: boolean) => void
|
||||||
firstMenuElement: React.RefObject<HTMLAnchorElement>
|
firstMenuElement: React.RefObject<HTMLAnchorElement>
|
||||||
websocket: WebSocket | null
|
websocket: WebSocket | null
|
||||||
|
onSaveResponseLambdas: Map<bigint, (saveFile: Uint8Array) => void>
|
||||||
};
|
};
|
||||||
|
|
||||||
type Style = Record<string, string>
|
type Style = Record<string, string>
|
||||||
|
@ -19,7 +20,7 @@ type Style = Record<string, string>
|
||||||
export default function OverlayMenu ({
|
export default function OverlayMenu ({
|
||||||
hiddenMenu, setHiddenMenu, emulationStarted,
|
hiddenMenu, setHiddenMenu, emulationStarted,
|
||||||
setHiddenFormSelectFiles, screenRef, isFullscreen, setIsFullscreen,
|
setHiddenFormSelectFiles, screenRef, isFullscreen, setIsFullscreen,
|
||||||
firstMenuElement, websocket
|
firstMenuElement, websocket, onSaveResponseLambdas
|
||||||
}: OverlayMenuProps): JSX.Element {
|
}: OverlayMenuProps): JSX.Element {
|
||||||
function exitMenu (): void {
|
function exitMenu (): void {
|
||||||
setHiddenMenu(true)
|
setHiddenMenu(true)
|
||||||
|
@ -68,6 +69,25 @@ export default function OverlayMenu ({
|
||||||
}
|
}
|
||||||
const currentSave = saveIdentifier
|
const currentSave = saveIdentifier
|
||||||
setSaveidentifier((c: bigint) => c + 1n)
|
setSaveidentifier((c: bigint) => c + 1n)
|
||||||
|
console.log('Reachs here')
|
||||||
|
onSaveResponseLambdas.set(currentSave, (saveFile: Uint8Array) => {
|
||||||
|
const anchor = document.createElement('a')
|
||||||
|
const blobSaveResponseFile = new Blob([saveFile.buffer])
|
||||||
|
const fileReader = new FileReader()
|
||||||
|
fileReader.onload = () => {
|
||||||
|
if (typeof fileReader.result === 'string') {
|
||||||
|
anchor.style.display = 'none'
|
||||||
|
document.body.appendChild(anchor)
|
||||||
|
anchor.href = fileReader.result
|
||||||
|
anchor.download = 'ruby.ss1'
|
||||||
|
anchor.click()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
fileReader.readAsDataURL(blobSaveResponseFile)
|
||||||
|
})
|
||||||
|
console.log(onSaveResponseLambdas)
|
||||||
sendSaveRequest(websocket, currentSave)
|
sendSaveRequest(websocket, currentSave)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,11 +5,11 @@ import CanvasGBAEmulator from '@msgba/components/canvas-gba-emulator'
|
||||||
import OverlayControls from '@msgba/components/overlay-controls'
|
import OverlayControls from '@msgba/components/overlay-controls'
|
||||||
import OverlayMenu from '@msgba/components/overlay-menu'
|
import OverlayMenu from '@msgba/components/overlay-menu'
|
||||||
import OverlaySelectFiles from '@msgba/components/overlay-select-files'
|
import OverlaySelectFiles from '@msgba/components/overlay-select-files'
|
||||||
import { sendHello, handleSendFrame } from '@msgba/packet'
|
import { sendHello, handleSendFrame, handleSaveResponse } from '@msgba/packet'
|
||||||
|
|
||||||
import Endian from '@msgba/endian'
|
import Endian from '@msgba/endian'
|
||||||
|
|
||||||
import { MIN_WIDTH_GBA, MIN_HEIGHT_GBA, MIN_WIDTH_GBC, MIN_HEIGHT_GBC, PACKET_ID_SEND_FRAME } from '@msgba/constants'
|
import { MIN_WIDTH_GBA, MIN_HEIGHT_GBA, MIN_WIDTH_GBC, MIN_HEIGHT_GBC, PACKET_ID_SEND_FRAME, PACKET_ID_SAVE_RESPONSE } from '@msgba/constants'
|
||||||
|
|
||||||
export interface handleClickStartEmulationButtonObjectArgs {
|
export interface handleClickStartEmulationButtonObjectArgs {
|
||||||
e: React.MouseEvent<HTMLInputElement>
|
e: React.MouseEvent<HTMLInputElement>
|
||||||
|
@ -23,85 +23,41 @@ export interface handleClickStartEmulationButtonObjectArgs {
|
||||||
isGBC: boolean
|
isGBC: boolean
|
||||||
setIsGBC: (c: boolean) => void
|
setIsGBC: (c: boolean) => void
|
||||||
controlsRef: React.RefObject<HTMLDivElement>
|
controlsRef: React.RefObject<HTMLDivElement>
|
||||||
}
|
onSaveResponseLambdas: Map<bigint, (saveFile: Uint8Array) => void>
|
||||||
|
|
||||||
function handleClickStartEmulationButton ({
|
|
||||||
e, inputRom, inputSaveState, canvas,
|
|
||||||
setEmulationStarted, setHiddenMenu,
|
|
||||||
setHiddenFormSelectFiles, setWebSocket,
|
|
||||||
isGBC, setIsGBC, controlsRef
|
|
||||||
}: handleClickStartEmulationButtonObjectArgs): void {
|
|
||||||
e.preventDefault()
|
|
||||||
if (canvas.current == null) {
|
|
||||||
alert('Canvas does not exists?')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const ctx = canvas.current.getContext('2d')
|
|
||||||
if (ctx == null) {
|
|
||||||
alert('Unable to create canvas context, doing nothing')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (inputRom == null || inputSaveState == null || inputRom.files == null || inputSaveState.files == null) {
|
|
||||||
alert('Unable to read the files ')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (inputRom.files.length === 0) {
|
|
||||||
alert('There is no rom still')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (inputSaveState.files.length === 0) {
|
|
||||||
alert('There is no savestate still')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const romFile = inputRom.files[0]
|
|
||||||
const savestateFile = inputSaveState.files[0]
|
|
||||||
romFile.arrayBuffer().then((romBuffer) => {
|
|
||||||
savestateFile.arrayBuffer().then((savestateBuffer) => {
|
|
||||||
const romArray = new Uint8Array(romBuffer)
|
|
||||||
const savestateArray = new Uint8Array(savestateBuffer)
|
|
||||||
const webSocket = new WebSocket(`ws://${window.location.host}/ws`)
|
|
||||||
setWebSocket(webSocket)
|
|
||||||
webSocket.binaryType = 'arraybuffer'
|
|
||||||
webSocket.onclose = (message) => {
|
|
||||||
setEmulationStarted(false)
|
|
||||||
console.log('Closing websocket.')
|
|
||||||
setWebSocket(null)
|
|
||||||
}
|
|
||||||
webSocket.onopen = () => {
|
|
||||||
console.log('Opened websocket.')
|
|
||||||
setEmulationStarted(true)
|
|
||||||
sendHello(webSocket, romArray, savestateArray)
|
|
||||||
setHiddenMenu(true)
|
|
||||||
setHiddenFormSelectFiles(true)
|
|
||||||
}
|
|
||||||
webSocket.addEventListener('message', (event) => {
|
|
||||||
onWebSocketPacket(event, canvas.current, ctx, isGBC, setIsGBC)
|
|
||||||
})
|
|
||||||
}).catch((c: string) => {
|
|
||||||
console.log('Unable to convert file to array_buffer')
|
|
||||||
})
|
|
||||||
}).catch((c: string) => {
|
|
||||||
console.log('Unable to convert file to array_buffer')
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function onWebSocketPacket (event: MessageEvent,
|
function onWebSocketPacket (event: MessageEvent,
|
||||||
canvas: HTMLCanvasElement | null,
|
canvas: HTMLCanvasElement | null,
|
||||||
ctx: CanvasRenderingContext2D,
|
ctx: CanvasRenderingContext2D,
|
||||||
isGBC: boolean, setIsGBC: (c: boolean) => void): void {
|
isGBC: boolean, setIsGBC: (c: boolean) => void,
|
||||||
|
onSaveResponseLambdas: Map<bigint, (saveFile: Uint8Array) => void>): void {
|
||||||
const buffer = event.data
|
const buffer = event.data
|
||||||
let packetU8: Uint8Array | null = new Uint8Array(buffer)
|
let packetU8: Uint8Array | null = new Uint8Array(buffer)
|
||||||
const id = Endian.byteArrayToU64BigEndian(packetU8.slice(0, 8))
|
const id = Endian.byteArrayToU64BigEndian(packetU8.slice(0, 8))
|
||||||
packetU8 = packetU8.slice(8, packetU8.length)
|
packetU8 = packetU8.slice(8, packetU8.length)
|
||||||
const size = Endian.byteArrayToU64BigEndian(packetU8.slice(0, 8))
|
const size = Endian.byteArrayToU64BigEndian(packetU8.slice(0, 8))
|
||||||
const rawData = packetU8.slice(8, Number(size))
|
console.log(size)
|
||||||
|
const rawData = packetU8.slice(8, Number(size) + 8)
|
||||||
|
console.log(rawData.length)
|
||||||
packetU8 = null
|
packetU8 = null
|
||||||
|
handlePacket(id, rawData, canvas, setIsGBC, onSaveResponseLambdas).catch((error: string) => {
|
||||||
|
console.log('Error handling packet', error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handlePacket (id: bigint, rawData: Uint8Array,
|
||||||
|
canvas: HTMLCanvasElement | null,
|
||||||
|
setIsGBC: (c: boolean) => void,
|
||||||
|
onSaveResponseLambdas: Map<bigint, (saveFile: Uint8Array) => void>): Promise<void> {
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case PACKET_ID_SEND_FRAME:
|
case PACKET_ID_SEND_FRAME:
|
||||||
handleSendFrame(rawData, canvas, setIsGBC)
|
handleSendFrame(rawData, canvas, setIsGBC)
|
||||||
break
|
break
|
||||||
|
case PACKET_ID_SAVE_RESPONSE:
|
||||||
|
handleSaveResponse(rawData, canvas, onSaveResponseLambdas)
|
||||||
|
break
|
||||||
default:
|
default:
|
||||||
console.log(`Received unknown packet ${id}`)
|
throw new Error(`Received unknown packet ${id}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,6 +89,7 @@ export default function Page (): JSX.Element {
|
||||||
const [emulationStarted, setEmulationStarted] = React.useState<boolean>(false)
|
const [emulationStarted, setEmulationStarted] = React.useState<boolean>(false)
|
||||||
const [hiddenMenu, setHiddenMenu] = React.useState<boolean>(true)
|
const [hiddenMenu, setHiddenMenu] = React.useState<boolean>(true)
|
||||||
const [webSocket, setWebSocket] = React.useState<WebSocket | null>(null)
|
const [webSocket, setWebSocket] = React.useState<WebSocket | null>(null)
|
||||||
|
const [onSaveResponseLambdas] = React.useState(new Map<bigint, (saveResponseFile: Uint8Array) => void>())
|
||||||
|
|
||||||
const controlsRef = React.useRef<HTMLDivElement>(null)
|
const controlsRef = React.useRef<HTMLDivElement>(null)
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
@ -156,21 +113,65 @@ export default function Page (): JSX.Element {
|
||||||
}
|
}
|
||||||
}, 100)
|
}, 100)
|
||||||
}, [hiddenMenu, hiddenFormSelectFiles])
|
}, [hiddenMenu, hiddenFormSelectFiles])
|
||||||
const onStartEmulation = (e: React.MouseEvent<HTMLInputElement>): void => {
|
function handleClickStartEmulationButton (e: React.MouseEvent<HTMLInputElement>): void {
|
||||||
handleClickStartEmulationButton({
|
e.preventDefault()
|
||||||
e,
|
if (canvasRef.current == null) {
|
||||||
setEmulationStarted,
|
alert('Canvas does not exists?')
|
||||||
inputRom: refInputRom.current,
|
return
|
||||||
inputSaveState: refInputSaveState.current,
|
}
|
||||||
canvas: canvasRef,
|
const ctx = canvasRef.current.getContext('2d')
|
||||||
setHiddenMenu,
|
if (ctx == null) {
|
||||||
setHiddenFormSelectFiles,
|
alert('Unable to create canvas context, doing nothing')
|
||||||
setWebSocket,
|
return
|
||||||
isGBC,
|
}
|
||||||
setIsGBC,
|
const inputRom = refInputRom.current
|
||||||
controlsRef
|
const inputSaveState = refInputSaveState.current
|
||||||
|
if (inputRom == null || inputSaveState == null || inputRom.files == null || inputSaveState.files == null) {
|
||||||
|
alert('Unable to read the files ')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (inputRom.files.length === 0) {
|
||||||
|
alert('There is no rom still')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (inputSaveState.files.length === 0) {
|
||||||
|
alert('There is no savestate still')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const romFile = inputRom.files[0]
|
||||||
|
const savestateFile = inputSaveState.files[0]
|
||||||
|
romFile.arrayBuffer().then((romBuffer) => {
|
||||||
|
savestateFile.arrayBuffer().then((savestateBuffer) => {
|
||||||
|
const romArray = new Uint8Array(romBuffer)
|
||||||
|
const savestateArray = new Uint8Array(savestateBuffer)
|
||||||
|
const webSocket = new WebSocket(`ws://${window.location.host}/ws`)
|
||||||
|
setWebSocket(webSocket)
|
||||||
|
webSocket.binaryType = 'arraybuffer'
|
||||||
|
webSocket.onclose = (message) => {
|
||||||
|
setEmulationStarted(false)
|
||||||
|
console.log('Closing websocket.')
|
||||||
|
setWebSocket(null)
|
||||||
|
}
|
||||||
|
webSocket.onopen = () => {
|
||||||
|
console.log('Opened websocket.')
|
||||||
|
setEmulationStarted(true)
|
||||||
|
sendHello(webSocket, romArray, savestateArray)
|
||||||
|
setHiddenMenu(true)
|
||||||
|
setHiddenFormSelectFiles(true)
|
||||||
|
}
|
||||||
|
webSocket.addEventListener('message', (event) => {
|
||||||
|
onWebSocketPacket(event, canvasRef.current, ctx, isGBC, setIsGBC, onSaveResponseLambdas)
|
||||||
|
})
|
||||||
|
}).catch((c: string) => {
|
||||||
|
console.log('Unable to convert file to array_buffer')
|
||||||
|
})
|
||||||
|
}).catch((c: string) => {
|
||||||
|
console.log('Unable to convert file to array_buffer')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
const onStartEmulation = (e: React.MouseEvent<HTMLInputElement>): void => {
|
||||||
|
handleClickStartEmulationButton(e)
|
||||||
|
}
|
||||||
const firstMenuElement = React.useRef<HTMLAnchorElement>(null)
|
const firstMenuElement = React.useRef<HTMLAnchorElement>(null)
|
||||||
const screenRef = React.useRef<HTMLDivElement>(null)
|
const screenRef = React.useRef<HTMLDivElement>(null)
|
||||||
const [isFullscreen, setIsFullscreen] = React.useState<boolean>(false)
|
const [isFullscreen, setIsFullscreen] = React.useState<boolean>(false)
|
||||||
|
@ -182,7 +183,8 @@ export default function Page (): JSX.Element {
|
||||||
setHiddenMenu={setHiddenMenu} emulationStarted={emulationStarted}
|
setHiddenMenu={setHiddenMenu} emulationStarted={emulationStarted}
|
||||||
setHiddenFormSelectFiles={setHiddenFormSelectFiles} screenRef={screenRef}
|
setHiddenFormSelectFiles={setHiddenFormSelectFiles} screenRef={screenRef}
|
||||||
isFullscreen={isFullscreen} setIsFullscreen={setIsFullscreen}
|
isFullscreen={isFullscreen} setIsFullscreen={setIsFullscreen}
|
||||||
firstMenuElement={firstMenuElement} websocket={webSocket}/>
|
firstMenuElement={firstMenuElement} websocket={webSocket}
|
||||||
|
onSaveResponseLambdas={onSaveResponseLambdas}/>
|
||||||
<OverlaySelectFiles hiddenFormSelectFiles={hiddenFormSelectFiles}
|
<OverlaySelectFiles hiddenFormSelectFiles={hiddenFormSelectFiles}
|
||||||
setHiddenFormSelectFiles={setHiddenFormSelectFiles}
|
setHiddenFormSelectFiles={setHiddenFormSelectFiles}
|
||||||
refInputRom={refInputRom} refInputSaveState={refInputSaveState}
|
refInputRom={refInputRom} refInputSaveState={refInputSaveState}
|
||||||
|
|
|
@ -47,6 +47,25 @@ export function sendPacket (websocket: WebSocket, id: bigint, rawData: Uint8Arra
|
||||||
websocket.send(packetBuffer)
|
websocket.send(packetBuffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function handleSaveResponse (rawData: Uint8Array, canvas: HTMLCanvasElement | null, onSaveResponseLambdas: Map<bigint, (saveFile: Uint8Array) => void>): void {
|
||||||
|
let data = rawData
|
||||||
|
console.log(data.length)
|
||||||
|
const identifier = Endian.byteArrayToU64BigEndian(data.slice(0, 8))
|
||||||
|
console.log(data.length)
|
||||||
|
data = data.slice(8, data.length)
|
||||||
|
console.log(data.length)
|
||||||
|
const saveFileSize = Endian.byteArrayToU64BigEndian(data.slice(0, 8))
|
||||||
|
console.log(data.length)
|
||||||
|
const saveFile = data.slice(8, Number(saveFileSize) + 8)
|
||||||
|
console.log(data.length)
|
||||||
|
const currentLambda = onSaveResponseLambdas.get(identifier)
|
||||||
|
console.log(onSaveResponseLambdas)
|
||||||
|
if (currentLambda == null) {
|
||||||
|
throw new Error(`We received a save request for an unknown identifier ${identifier}`)
|
||||||
|
}
|
||||||
|
currentLambda(saveFile)
|
||||||
|
}
|
||||||
|
|
||||||
export function handleSendFrame (rawData: Uint8Array, canvas: HTMLCanvasElement | null, setIsGBC: (c: boolean) => void): void {
|
export function handleSendFrame (rawData: Uint8Array, canvas: HTMLCanvasElement | null, setIsGBC: (c: boolean) => void): void {
|
||||||
if (canvas == null) {
|
if (canvas == null) {
|
||||||
console.log('No canvas')
|
console.log('No canvas')
|
||||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue