Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions fxmanifest.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
fx_version 'bodacious'

version '0.13.0-beta.1'
version '0.13.0-beta.2'

game "gta5"

Expand All @@ -23,4 +23,4 @@ protocol 'http'
-- bytes per second for nui protocol
-- change this as you like
images_bps '1000000'
stream_bps '5000000'
stream_bps '5000000'
44 changes: 25 additions & 19 deletions game/nui/src/capture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,19 @@ type CaptureRequest = {
export class Capture {
#gameView: any;
#canvas: HTMLCanvasElement | null = null;
#queue: Promise<void> = 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);
});
}
});

Expand Down Expand Up @@ -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) {
Expand Down