Adding save fetch capabilities.

This commit is contained in:
Sergiotarxz 2023-04-02 17:28:27 +02:00
parent 7ffeb360e7
commit 07273a40bf
4 changed files with 133 additions and 92 deletions

View File

@ -12,6 +12,7 @@ export interface OverlayMenuProps {
setIsFullscreen: (c: boolean) => void
firstMenuElement: React.RefObject<HTMLAnchorElement>
websocket: WebSocket | null
onSaveResponseLambdas: Map<bigint, (saveFile: Uint8Array) => void>
};
type Style = Record<string, string>
@ -19,7 +20,7 @@ type Style = Record<string, string>
export default function OverlayMenu ({
hiddenMenu, setHiddenMenu, emulationStarted,
setHiddenFormSelectFiles, screenRef, isFullscreen, setIsFullscreen,
firstMenuElement, websocket
firstMenuElement, websocket, onSaveResponseLambdas
}: OverlayMenuProps): JSX.Element {
function exitMenu (): void {
setHiddenMenu(true)
@ -68,6 +69,25 @@ export default function OverlayMenu ({
}
const currentSave = saveIdentifier
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)
}

View File

@ -5,11 +5,11 @@ import CanvasGBAEmulator from '@msgba/components/canvas-gba-emulator'
import OverlayControls from '@msgba/components/overlay-controls'
import OverlayMenu from '@msgba/components/overlay-menu'
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 { 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 {
e: React.MouseEvent<HTMLInputElement>
@ -23,85 +23,41 @@ export interface handleClickStartEmulationButtonObjectArgs {
isGBC: boolean
setIsGBC: (c: boolean) => void
controlsRef: React.RefObject<HTMLDivElement>
}
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')
})
onSaveResponseLambdas: Map<bigint, (saveFile: Uint8Array) => void>
}
function onWebSocketPacket (event: MessageEvent,
canvas: HTMLCanvasElement | null,
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
let packetU8: Uint8Array | null = new Uint8Array(buffer)
const id = Endian.byteArrayToU64BigEndian(packetU8.slice(0, 8))
packetU8 = packetU8.slice(8, packetU8.length)
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
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) {
case PACKET_ID_SEND_FRAME:
handleSendFrame(rawData, canvas, setIsGBC)
break
case PACKET_ID_SAVE_RESPONSE:
handleSaveResponse(rawData, canvas, onSaveResponseLambdas)
break
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 [hiddenMenu, setHiddenMenu] = React.useState<boolean>(true)
const [webSocket, setWebSocket] = React.useState<WebSocket | null>(null)
const [onSaveResponseLambdas] = React.useState(new Map<bigint, (saveResponseFile: Uint8Array) => void>())
const controlsRef = React.useRef<HTMLDivElement>(null)
React.useEffect(() => {
@ -156,21 +113,65 @@ export default function Page (): JSX.Element {
}
}, 100)
}, [hiddenMenu, hiddenFormSelectFiles])
const onStartEmulation = (e: React.MouseEvent<HTMLInputElement>): void => {
handleClickStartEmulationButton({
e,
setEmulationStarted,
inputRom: refInputRom.current,
inputSaveState: refInputSaveState.current,
canvas: canvasRef,
setHiddenMenu,
setHiddenFormSelectFiles,
setWebSocket,
isGBC,
setIsGBC,
controlsRef
function handleClickStartEmulationButton (e: React.MouseEvent<HTMLInputElement>): void {
e.preventDefault()
if (canvasRef.current == null) {
alert('Canvas does not exists?')
return
}
const ctx = canvasRef.current.getContext('2d')
if (ctx == null) {
alert('Unable to create canvas context, doing nothing')
return
}
const inputRom = refInputRom.current
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 screenRef = React.useRef<HTMLDivElement>(null)
const [isFullscreen, setIsFullscreen] = React.useState<boolean>(false)
@ -182,7 +183,8 @@ export default function Page (): JSX.Element {
setHiddenMenu={setHiddenMenu} emulationStarted={emulationStarted}
setHiddenFormSelectFiles={setHiddenFormSelectFiles} screenRef={screenRef}
isFullscreen={isFullscreen} setIsFullscreen={setIsFullscreen}
firstMenuElement={firstMenuElement} websocket={webSocket}/>
firstMenuElement={firstMenuElement} websocket={webSocket}
onSaveResponseLambdas={onSaveResponseLambdas}/>
<OverlaySelectFiles hiddenFormSelectFiles={hiddenFormSelectFiles}
setHiddenFormSelectFiles={setHiddenFormSelectFiles}
refInputRom={refInputRom} refInputSaveState={refInputSaveState}

View File

@ -47,6 +47,25 @@ export function sendPacket (websocket: WebSocket, id: bigint, rawData: Uint8Arra
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 {
if (canvas == null) {
console.log('No canvas')

File diff suppressed because one or more lines are too long