diff --git a/fxmanifest.lua b/fxmanifest.lua index 2c14e35..e8c935a 100644 --- a/fxmanifest.lua +++ b/fxmanifest.lua @@ -1,6 +1,6 @@ fx_version 'bodacious' -version '0.13.0-beta.1' +version '0.13.0-beta.2' game "gta5" @@ -23,4 +23,4 @@ protocol 'http' -- bytes per second for nui protocol -- change this as you like images_bps '1000000' -stream_bps '5000000' \ No newline at end of file +stream_bps '5000000' diff --git a/game/nui/src/capture.ts b/game/nui/src/capture.ts index 49aa979..ea69f8c 100644 --- a/game/nui/src/capture.ts +++ b/game/nui/src/capture.ts @@ -23,16 +23,19 @@ type CaptureRequest = { export class Capture { #gameView: any; #canvas: HTMLCanvasElement | null = null; + #queue: Promise = Promise.resolve(); private readonly MAX_WIDTH = 1920; private readonly MAX_HEIGHT = 1080; start() { - window.addEventListener('message', async (event) => { + window.addEventListener('message', (event) => { const data = event.data as CaptureRequest; if (data.action === 'capture') { - await this.captureScreen(data); + this.#queue = this.#queue.then(() => this.captureScreen(data)).catch((err) => { + console.error('[screencapture] capture error:', err); + }); } }); @@ -74,26 +77,29 @@ export class Capture { this.#gameView = createGameView(this.#canvas); this.#gameView.resize(width, height); - // Wait for the FiveM WebGL hook to populate the game framebuffer - await this.waitForFrames(3); + try { + // Wait for the FiveM WebGL hook to populate the game framebuffer + await this.waitForFrames(3); - const enc = request.encoding ?? 'png'; - let imageData: string | Blob; - // callbackUrl is only set on the screenshot-basic requestScreenshot path; - // everything else is handled server-side via the upload endpoint - if (request.callbackUrl) { - imageData = await this.createDataURL(this.#canvas, enc, request.quality); - } else { - imageData = await this.createBlob(this.#canvas, enc, request.quality); - } + const enc = request.encoding ?? 'png'; + let imageData: string | Blob; + // callbackUrl is only set on the screenshot-basic requestScreenshot path; + // everything else is handled server-side via the upload endpoint + if (request.callbackUrl) { + imageData = await this.createDataURL(this.#canvas, enc, request.quality); + } else { + imageData = await this.createBlob(this.#canvas, enc, request.quality); + } - if (!imageData) return console.error('No image available'); + if (!imageData) return console.error('No image available'); - await this.httpUploadImage(request, imageData); - this.#gameView.dispose(); - this.#canvas.remove(); - this.#gameView = null; - this.#canvas = null; + await this.httpUploadImage(request, imageData); + } finally { + this.#gameView.dispose(); + this.#canvas.remove(); + this.#gameView = null; + this.#canvas = null; + } } async httpUploadImage(request: CaptureRequest, imageData: string | Blob) {