@@ -389,6 +389,45 @@ window.EJS_onSaveState = async function ({
389389window .EJS_onGameStart = async () => {
390390 sessionStartTime .value = new Date ();
391391
392+ // Install netplay overrides synchronously, before any await below, so they
393+ // are in place before room polling or a Create/Join action can start.
394+ // EmulatorJS' nightly netplay builds its URLs from `netplay.url` (the page
395+ // host by default), which does not match how RomM serves netplay: the room
396+ // list lives at /api/netplay/list and the socket at /netplay/socket.io. Point
397+ // both at the right place so netplay works behind any reverse proxy / domain.
398+ const netplay = window .EJS_emulator ?.netplay ;
399+ if (netplay ) {
400+ // Room-list polling: use RomM's REST endpoint with a root-relative path,
401+ // instead of `netplay.url + "/list"` (which resolves relative to the SPA
402+ // route and duplicates the domain inside the request path).
403+ netplay .getOpenRooms = async () => {
404+ try {
405+ const response = await fetch (
406+ ` /api/netplay/list?game_id=${window .EJS_gameID } ` ,
407+ );
408+ if (! response .ok ) return {};
409+ return await response .json ();
410+ } catch (error ) {
411+ console .error (" Error fetching netplay rooms:" , error );
412+ return {};
413+ }
414+ };
415+ }
416+
417+ // EmulatorJS connects with `io(netplay.url)` using Socket.IO's default path.
418+ // Wrap the bundled global `io` so netplay uses RomM's mounted socket path.
419+ // Only EmulatorJS uses this global; RomM's own app socket imports the client.
420+ if (window .io && ! window .io .__rommNetplayPatched ) {
421+ const originalIo = window .io ;
422+ const patchedIo = ((url : string , opts ? : Record <string , unknown >) =>
423+ originalIo (url , {
424+ ... opts ,
425+ path: " /netplay/socket.io" ,
426+ })) as NonNullable <Window [" io" ]>;
427+ patchedIo .__rommNetplayPatched = true ;
428+ window .io = patchedIo ;
429+ }
430+
392431 void (async () => {
393432 const ready = await waitForGameManager ();
394433 if (! ready ) {
@@ -470,43 +509,6 @@ window.EJS_onGameStart = async () => {
470509 romsStore .update (romRef .value );
471510 immediateExit ();
472511 });
473-
474- // EmulatorJS' nightly netplay builds its URLs from `netplay.url` (the page
475- // host by default), which does not match how RomM serves netplay: the room
476- // list lives at /api/netplay/list and the socket at /netplay/socket.io. Point
477- // both at the right place so netplay works behind any reverse proxy / domain.
478- const netplay = window .EJS_emulator ?.netplay ;
479- if (netplay ) {
480- // Room-list polling: use RomM's REST endpoint with a root-relative path,
481- // instead of `netplay.url + "/list"` (which resolves relative to the SPA
482- // route and duplicates the domain inside the request path).
483- netplay .getOpenRooms = async () => {
484- try {
485- const response = await fetch (
486- ` /api/netplay/list?game_id=${window .EJS_gameID } ` ,
487- );
488- if (! response .ok ) return {};
489- return await response .json ();
490- } catch (error ) {
491- console .error (" Error fetching netplay rooms:" , error );
492- return {};
493- }
494- };
495- }
496-
497- // EmulatorJS connects with `io(netplay.url)` using Socket.IO's default path.
498- // Wrap the bundled global `io` so netplay uses RomM's mounted socket path.
499- // Only EmulatorJS uses this global; RomM's own app socket imports the client.
500- if (window .io && ! window .io .__rommNetplayPatched ) {
501- const originalIo = window .io ;
502- const patchedIo = ((url : string , opts ? : Record <string , unknown >) =>
503- originalIo (url , {
504- ... opts ,
505- path: " /netplay/socket.io" ,
506- })) as NonNullable <Window [" io" ]>;
507- patchedIo .__rommNetplayPatched = true ;
508- window .io = patchedIo ;
509- }
510512};
511513
512514function immediateExit() {
0 commit comments