Add real PinMAME (VPinMAME.Controller) integration for ROM-based tables
Statically links the real PinMAME emulation core (libpinmame) instead of leaving VPinMAME.Controller creation to fail, which was crashing table scripts on ROM-based tables before they could spawn a ball. PinMAME's own run_game()->cpu_run() loop is split into a one-shot init, a per-frame step, and a one-shot teardown (patches/pinmame/0004) so it runs cooperatively on the same frame callback as vpinball's own loop instead of on a real std::thread, which hard-aborts under Emscripten's single-threaded runtime - three smaller wasm32 portability fixes to libpinmame itself round out the patch set (0001-0003). Adds pinball.loadRom() to supply a ROM zip, written to the table-relative pinmame/roms/ path vpinball's own plugin already checks. Confirmed against a real community ROM-based table: Controller creation and game identification succeed, and a missing ROM now fails cleanly instead of crashing the page - actual ROM-driven gameplay is still unconfirmed since no ROM was available (or sought out) to test with. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SoSarxLgY33Kax5UNXcafZ
This commit is contained in:
+17
-1
@@ -12,7 +12,16 @@ const UPLOADED_TABLE_PATH = '/tables/uploaded.vpx';
|
||||
* canvas and returns a handle to control its lifecycle.
|
||||
*/
|
||||
export async function loadPinball(options: LoadPinballOptions): Promise<PinballInstance> {
|
||||
const baseUrl = options.baseUrl ?? '.';
|
||||
// Resolved to an absolute URL against the *page's* location up front,
|
||||
// rather than used as-is: a bare relative baseUrl works for
|
||||
// Module.locateFile and wireDownloadProgress's fetch() (both resolve
|
||||
// relative to the page), but not for the dynamic import() below, whose
|
||||
// relative-specifier resolution is against *this module's own* URL
|
||||
// (dist/index.js) instead - the two disagree for any page location that
|
||||
// doesn't happen to cancel the difference out (as examples/basic/'s
|
||||
// '../../dist' accidentally does). Resolving once here, to an absolute
|
||||
// URL, makes every use of it agree.
|
||||
const baseUrl = new URL(options.baseUrl ?? '.', document.baseURI).href.replace(/\/$/, '');
|
||||
let tablePath = DEFAULT_TABLE_PATH;
|
||||
|
||||
const moduleArgs: Record<string, unknown> = {
|
||||
@@ -43,6 +52,10 @@ export async function loadPinball(options: LoadPinballOptions): Promise<PinballI
|
||||
module.FS.writeFile(UPLOADED_TABLE_PATH, new Uint8Array(vpxBytes));
|
||||
tablePath = UPLOADED_TABLE_PATH;
|
||||
},
|
||||
loadRom(gameName: string, romZipBytes: ArrayBuffer) {
|
||||
module.FS.mkdirTree(PINMAME_ROMS_DIR);
|
||||
module.FS.writeFile(`${PINMAME_ROMS_DIR}/${gameName}.zip`, new Uint8Array(romZipBytes));
|
||||
},
|
||||
start() {
|
||||
module.ccall?.('vpinball_wasm_start', 'number', ['string'], [tablePath]);
|
||||
},
|
||||
@@ -116,6 +129,9 @@ async function wireDownloadProgress(
|
||||
interface EmscriptenModule {
|
||||
FS: {
|
||||
writeFile(path: string, data: Uint8Array): void;
|
||||
mkdirTree(path: string): void;
|
||||
};
|
||||
ccall?: (name: string, returnType: string | null, argTypes: string[], args: unknown[]) => unknown;
|
||||
}
|
||||
|
||||
const PINMAME_ROMS_DIR = '/tables/pinmame/roms';
|
||||
|
||||
Reference in New Issue
Block a user