add config entry to enable netplay

This commit is contained in:
Georges-Antoine Assi
2025-12-08 22:58:48 -05:00
parent 86098ef1d9
commit 27c83e4736
14 changed files with 90 additions and 41 deletions

View File

@@ -18,6 +18,7 @@ export type ConfigResponse = {
SKIP_HASH_CALCULATION: boolean;
EJS_DEBUG: boolean;
EJS_CACHE_LIMIT: (number | null);
EJS_NETPLAY_ENABLED: boolean;
EJS_NETPLAY_ICE_SERVERS: Array<NetplayICEServer>;
EJS_SETTINGS: Record<string, Record<string, string>>;
EJS_CONTROLS: Record<string, EjsControls>;

View File

@@ -84,8 +84,8 @@ export type DetailedRomSchema = {
missing_from_fs: boolean;
siblings: Array<SiblingRomSchema>;
rom_user: RomUserSchema;
merged_ra_metadata: (RomRAMetadata | null);
merged_screenshots: Array<string>;
merged_ra_metadata: (RomRAMetadata | null);
user_saves: Array<SaveSchema>;
user_states: Array<StateSchema>;
user_screenshots: Array<ScreenshotSchema>;

View File

@@ -79,7 +79,7 @@ export type SimpleRomSchema = {
missing_from_fs: boolean;
siblings: Array<SiblingRomSchema>;
rom_user: RomUserSchema;
merged_ra_metadata: (RomRAMetadata | null);
merged_screenshots: Array<string>;
merged_ra_metadata: (RomRAMetadata | null);
};

View File

@@ -607,9 +607,11 @@ async function boot() {
// Allow route transition animation to settle
await new Promise((r) => setTimeout(r, 50));
const EMULATORJS_VERSION = "4.2.3";
const LOCAL_PATH = "/assets/emulatorjs/data/";
const CDN_PATH = `https://cdn.emulatorjs.org/${EMULATORJS_VERSION}/data/`;
const EMULATORJS_VERSION = configStore.config.EJS_NETPLAY_ENABLED
? "nightly"
: "4.2.3";
const LOCAL_PATH = "/assets/emulatorjs/data";
const CDN_PATH = `https://cdn.emulatorjs.org/${EMULATORJS_VERSION}/data`;
function loadScript(src: string): Promise<void> {
return new Promise((resolve, reject) => {
@@ -625,15 +627,19 @@ async function boot() {
async function attemptLoad(path: string, label: "local" | "cdn") {
loaderStatus.value = label === "local" ? "loading-local" : "loading-cdn";
window.EJS_pathtodata = path;
await loadScript(`${path}loader.js`);
await loadScript(`${path}/loader.js`);
}
try {
try {
await attemptLoad(LOCAL_PATH, "local");
(await configStore.config.EJS_NETPLAY_ENABLED)
? attemptLoad(CDN_PATH, "cdn")
: attemptLoad(LOCAL_PATH, "local");
} catch (e) {
console.warn("[Play] Local loader failed, trying CDN", e);
await attemptLoad(CDN_PATH, "cdn");
(await configStore.config.EJS_NETPLAY_ENABLED)
? attemptLoad(LOCAL_PATH, "local")
: attemptLoad(CDN_PATH, "cdn");
}
// Wait for emulator bootstrap
const startDeadline = Date.now() + 8000; // 8s

View File

@@ -24,6 +24,7 @@ const defaultConfig = {
PLATFORMS_VERSIONS: {},
SKIP_HASH_CALCULATION: false,
EJS_DEBUG: false,
EJS_NETPLAY_ENABLED: false,
EJS_CACHE_LIMIT: null,
EJS_NETPLAY_ICE_SERVERS: [],
EJS_SETTINGS: {},

View File

@@ -14,6 +14,7 @@ import { ROUTES } from "@/plugins/router";
import firmwareApi from "@/services/api/firmware";
import romApi from "@/services/api/rom";
import storeAuth from "@/stores/auth";
import storeConfig from "@/stores/config";
import storePlaying from "@/stores/playing";
import { type DetailedRom } from "@/stores/roms";
import { formatTimestamp, getSupportedEJSCores } from "@/utils";
@@ -21,13 +22,12 @@ import { getEmptyCoverImage } from "@/utils/covers";
import CacheDialog from "@/views/Player/EmulatorJS/CacheDialog.vue";
import Player from "@/views/Player/EmulatorJS/Player.vue";
const EMULATORJS_VERSION = "nightly";
const { t, locale } = useI18n();
const { smAndDown } = useDisplay();
const route = useRoute();
const auth = storeAuth();
const playingStore = storePlaying();
const configStore = storeConfig();
const { playing, fullScreen } = storeToRefs(playingStore);
const rom = ref<DetailedRom | null>(null);
const firmwareOptions = ref<FirmwareSchema[]>([]);
@@ -42,7 +42,7 @@ const supportedCores = ref<string[]>([]);
const gameRunning = ref(false);
const fullScreenOnPlay = useLocalStorage("emulation.fullScreenOnPlay", true);
function onPlay() {
async function onPlay() {
if (rom.value && auth.scopes.includes("roms.user.write")) {
romApi.updateUserRomProps({
romId: rom.value.id,
@@ -56,33 +56,44 @@ function onPlay() {
fullScreen.value = fullScreenOnPlay.value;
playing.value = true;
const LOCAL_PATH = "/assets/emulatorjs/data/";
const CDN_PATH = `https://cdn.emulatorjs.org/${EMULATORJS_VERSION}/data/`;
const EMULATORJS_VERSION = configStore.config.EJS_NETPLAY_ENABLED
? "nightly"
: "4.2.3";
const LOCAL_PATH = "/assets/emulatorjs/data";
const CDN_PATH = `https://cdn.emulatorjs.org/${EMULATORJS_VERSION}/data`;
// Try loading local loader.js via fetch to validate it's real JS
fetch(`${LOCAL_PATH}loader.js`)
.then((res) => {
const type = res.headers.get("content-type") || "";
if (!res.ok || !type.includes("javascript")) {
throw new Error("Invalid local loader.js");
}
window.EJS_pathtodata = LOCAL_PATH;
return res.text();
})
.then((jsCode) => {
playing.value = true;
fullScreen.value = fullScreenOnPlay.value;
const script = document.createElement("script");
script.textContent = jsCode;
document.body.appendChild(script);
})
.catch(() => {
console.warn("Local EmulatorJS failed, falling back to CDN");
window.EJS_pathtodata = CDN_PATH;
const fallbackScript = document.createElement("script");
fallbackScript.src = `${CDN_PATH}loader.js`;
document.body.appendChild(fallbackScript);
function loadScript(src: string): Promise<void> {
return new Promise((resolve, reject) => {
const s = document.createElement("script");
s.src = src;
s.async = true;
s.onload = () => resolve();
s.onerror = () => reject(new Error("Failed loading " + src));
document.body.appendChild(s);
});
}
async function attemptLoad(path: string) {
window.EJS_pathtodata = path;
await loadScript(`${path}/loader.js`);
}
try {
try {
await attemptLoad(
configStore.config.EJS_NETPLAY_ENABLED ? CDN_PATH : LOCAL_PATH,
);
} catch (e) {
console.warn("[Play] Local loader failed, trying CDN", e);
await attemptLoad(
configStore.config.EJS_NETPLAY_ENABLED ? LOCAL_PATH : CDN_PATH,
);
}
playing.value = true;
fullScreen.value = fullScreenOnPlay.value;
} catch (err) {
console.error("[Play] Emulator load failure:", err);
}
}
function onFullScreenChange() {

View File

@@ -144,11 +144,16 @@ window.EJS_gameName = romRef.value.fs_name_no_tags
window.EJS_language = selectedLanguage.value.value.replace("_", "-");
window.EJS_disableAutoLang = true;
const { EJS_DEBUG, EJS_CACHE_LIMIT, EJS_NETPLAY_ICE_SERVERS } =
configStore.config;
window.EJS_netplayServer = window.location.host;
window.EJS_netplayICEServers = EJS_NETPLAY_ICE_SERVERS;
const {
EJS_DEBUG,
EJS_CACHE_LIMIT,
EJS_NETPLAY_ICE_SERVERS,
EJS_NETPLAY_ENABLED,
} = configStore.config;
window.EJS_netplayServer = EJS_NETPLAY_ENABLED ? window.location.host : "";
window.EJS_netplayICEServers = EJS_NETPLAY_ENABLED
? EJS_NETPLAY_ICE_SERVERS
: [];
if (EJS_CACHE_LIMIT !== null) window.EJS_CacheLimit = EJS_CACHE_LIMIT;
window.EJS_DEBUG_XX = EJS_DEBUG;