Adding save fetch capabilities.
This commit is contained in:
parent
7ffeb360e7
commit
07273a40bf
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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}
|
||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user