commit before switching this from static site to app
This commit is contained in:
264
public/emu/loader.js
Normal file
264
public/emu/loader.js
Normal file
@@ -0,0 +1,264 @@
|
||||
const folderPath = (path) => {
|
||||
const filename = path.split("/").pop();
|
||||
return path.substring(0, path.length - filename.length);
|
||||
};
|
||||
function isAbsoluteUrl(path) {
|
||||
return /^[a-zA-Z][\w.+-]*:\/\//i.test(path);
|
||||
}
|
||||
|
||||
let scriptPath = (typeof window.EJS_pathtodata === "string") ? window.EJS_pathtodata : folderPath((new URL(document.currentScript.src)).pathname);
|
||||
if (!scriptPath.endsWith("/")) {
|
||||
scriptPath += "/";
|
||||
}
|
||||
if (!scriptPath.startsWith("/") && !isAbsoluteUrl(scriptPath)) {
|
||||
scriptPath = "../" + scriptPath;
|
||||
}
|
||||
|
||||
const debug = window.EJS_DEBUG_XX === true;
|
||||
|
||||
if (debug) {
|
||||
console.log("Script Path:", scriptPath);
|
||||
}
|
||||
|
||||
function resolvePath(path) {
|
||||
if ("undefined" != typeof EJS_paths && typeof EJS_paths[path] === "string") {
|
||||
return EJS_paths[path];
|
||||
} else if (path.endsWith("emulator.min.js") || path.endsWith("css")) {
|
||||
return scriptPath + path;
|
||||
} else {
|
||||
return scriptPath + "src/" + path;
|
||||
}
|
||||
}
|
||||
|
||||
async function loadScript(file) {
|
||||
try {
|
||||
const script = resolvePath(file);
|
||||
const module = await import(script);
|
||||
return module.default;
|
||||
} catch(e) {
|
||||
if (debug) console.error(e);
|
||||
const module = await filesMissing(file);
|
||||
return module.default;
|
||||
}
|
||||
}
|
||||
|
||||
function loadStyle(file) {
|
||||
return new Promise(function(resolve) {
|
||||
let css = document.createElement("link");
|
||||
css.rel = "stylesheet";
|
||||
css.href = resolvePath(file);
|
||||
css.onload = resolve;
|
||||
css.onerror = () => {
|
||||
filesMissing(file).then(e => resolve());
|
||||
}
|
||||
document.head.appendChild(css);
|
||||
})
|
||||
}
|
||||
async function filesMissing(file) {
|
||||
console.error("Failed to load " + file);
|
||||
let minifiedFailed = file.includes("min");
|
||||
const errorMessage = `Failed to load ${file} because it's likely that the minified files are missing.
|
||||
To fix this you have 3 options:
|
||||
1. You can download the zip from the latest release here: https://github.com/EmulatorJS/EmulatorJS/releases/latest - Recommended
|
||||
2. You can download the zip from here: https://cdn.emulatorjs.org/stable/data/emulator.min.zip and extract it to the data/ folder
|
||||
3. You can build the files by running "npm i && npm run build" in the data/minify folder.`;
|
||||
console[minifiedFailed ? "warn" : "error"](errorMessage);
|
||||
if (minifiedFailed) {
|
||||
console.log("Attempting to load non-minified files");
|
||||
if (file === "emulator.min.js") {
|
||||
return await loadScript("emulator.js");
|
||||
} else {
|
||||
await loadStyle("emulator.css");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getLanguagePath(language) {
|
||||
if ("undefined" != typeof EJS_paths && typeof EJS_paths[language] === "string") {
|
||||
return { path: EJS_paths[language], fallback: null };
|
||||
}
|
||||
|
||||
const base = scriptPath + "localization/" + language + ".json";
|
||||
let fallback = null;
|
||||
|
||||
if (language.includes("-") || language.includes("_")) {
|
||||
fallback = scriptPath + "localization/" + language.split(/[-_]/)[0] + ".json";
|
||||
}
|
||||
|
||||
return { path: base, fallback };
|
||||
}
|
||||
|
||||
async function fetchJson(path) {
|
||||
try {
|
||||
const response = await fetch(path);
|
||||
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
||||
return await response.json();
|
||||
} catch (e) {
|
||||
console.warn("Failed to fetch language file:", path, e.message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function mergeLanguages(baseJson, overrideJson) {
|
||||
if (!baseJson || !overrideJson) return baseJson || overrideJson || {};
|
||||
return { ...baseJson, ...overrideJson };
|
||||
}
|
||||
|
||||
async function loadLanguage(config) {
|
||||
const defaultLangs = ["en", "en-US"];
|
||||
|
||||
if (!config.language || defaultLangs.includes(config.language)) return config;
|
||||
|
||||
console.log("Language:", config.language);
|
||||
|
||||
let langData = {};
|
||||
const paths = getLanguagePath(config.language);
|
||||
|
||||
try {
|
||||
const specificJson = await fetchJson(paths.path);
|
||||
|
||||
if (paths.fallback) {
|
||||
const fallbackJson = await fetchJson(paths.fallback);
|
||||
langData = mergeLanguages(fallbackJson, specificJson || {});
|
||||
} else {
|
||||
langData = specificJson || {};
|
||||
}
|
||||
|
||||
config.langJson = langData;
|
||||
|
||||
} catch (e) {
|
||||
if (paths.fallback) {
|
||||
const fallbackLang = config.language.split(/[-_]/)[0];
|
||||
console.warn(`Language '${config.language}' not found, trying '${fallbackLang}'`);
|
||||
|
||||
const fallbackJson = await fetchJson(paths.fallback);
|
||||
if (fallbackJson) {
|
||||
langData = fallbackJson;
|
||||
config.langJson = langData;
|
||||
config.language = fallbackLang;
|
||||
}
|
||||
} else {
|
||||
console.warn(`No language file found for '${config.language}'`);
|
||||
delete config.language;
|
||||
delete config.langJson;
|
||||
}
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
const config = {
|
||||
debug: debug,
|
||||
gameUrl: window.EJS_gameUrl,
|
||||
dataPath: scriptPath,
|
||||
system: window.EJS_core,
|
||||
biosUrl: window.EJS_biosUrl,
|
||||
gameName: window.EJS_gameName,
|
||||
color: window.EJS_color,
|
||||
adUrl: window.EJS_AdUrl,
|
||||
adMode: window.EJS_AdMode,
|
||||
adTimer: window.EJS_AdTimer,
|
||||
adSize: window.EJS_AdSize,
|
||||
alignStartButton: window.EJS_alignStartButton,
|
||||
VirtualGamepadSettings: window.EJS_VirtualGamepadSettings,
|
||||
buttonOpts: window.EJS_Buttons,
|
||||
volume: window.EJS_volume,
|
||||
defaultControllers: window.EJS_defaultControls,
|
||||
startOnLoad: window.EJS_startOnLoaded,
|
||||
fullscreenOnLoad: window.EJS_fullscreenOnLoaded,
|
||||
filePaths: window.EJS_paths,
|
||||
loadState: window.EJS_loadStateURL,
|
||||
cacheLimit: window.EJS_CacheLimit,
|
||||
cacheConfig: window.EJS_cacheConfig,
|
||||
cheats: window.EJS_cheats,
|
||||
cheatPath: window.EJS_cheatPath,
|
||||
defaultOptions: window.EJS_defaultOptions,
|
||||
gamePatchUrl: window.EJS_gamePatchUrl,
|
||||
gameParentUrl: window.EJS_gameParentUrl,
|
||||
netplayUrl: window.EJS_netplayServer,
|
||||
netplayICEServers: window.EJS_netplayICEServers,
|
||||
gameId: window.EJS_gameID,
|
||||
backgroundImg: window.EJS_backgroundImage,
|
||||
backgroundBlur: window.EJS_backgroundBlur,
|
||||
backgroundColor: window.EJS_backgroundColor,
|
||||
controlScheme: window.EJS_controlScheme,
|
||||
threads: window.EJS_threads,
|
||||
disableCue: window.EJS_disableCue,
|
||||
startBtnName: window.EJS_startButtonName,
|
||||
softLoad: window.EJS_softLoad,
|
||||
capture: window.EJS_screenCapture,
|
||||
externalFiles: window.EJS_externalFiles,
|
||||
dontExtractRom: window.EJS_dontExtractRom,
|
||||
dontExtractBIOS: window.EJS_dontExtractBIOS,
|
||||
disableLocalStorage: window.EJS_disableLocalStorage,
|
||||
forceLegacyCores: window.EJS_forceLegacyCores,
|
||||
noAutoFocus: window.EJS_noAutoFocus,
|
||||
videoRotation: window.EJS_videoRotation,
|
||||
hideSettings: window.EJS_hideSettings,
|
||||
browserMode: window.EJS_browserMode,
|
||||
additionalShaders: window.EJS_shaders,
|
||||
fixedSaveInterval: window.EJS_fixedSaveInterval,
|
||||
disableAutoUnload: window.EJS_disableAutoUnload,
|
||||
disableBatchBootup: window.EJS_disableBatchBootup
|
||||
};
|
||||
|
||||
async function prepareLanguage() {
|
||||
try {
|
||||
const systemLang = Intl.DateTimeFormat().resolvedOptions().locale;
|
||||
config.language = window.EJS_language || systemLang;
|
||||
|
||||
if (config.language && window.EJS_disableAutoLang !== false) {
|
||||
return await loadLanguage(config);
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("Language detection failed:", e.message);
|
||||
delete config.language;
|
||||
delete config.langJson;
|
||||
}
|
||||
}
|
||||
|
||||
(async function() {
|
||||
let EmulatorJS;
|
||||
if (debug) {
|
||||
EmulatorJS = await loadScript("emulator.js");
|
||||
await loadStyle("emulator.css");
|
||||
} else {
|
||||
EmulatorJS = await loadScript("emulator.min.js");
|
||||
await loadStyle("emulator.min.css");
|
||||
}
|
||||
|
||||
if (!EmulatorJS) {
|
||||
console.error("EmulatorJS failed to load. Check for missing files.");
|
||||
return;
|
||||
}
|
||||
|
||||
await prepareLanguage();
|
||||
|
||||
if (debug) {
|
||||
console.log("Language:", config.language);
|
||||
console.log("Language JSON loaded:", !!config.langJson);
|
||||
}
|
||||
|
||||
window.EJS_emulator = new EmulatorJS(EJS_player, config);
|
||||
window.EJS_adBlocked = (url, del) => window.EJS_emulator.adBlocked(url, del);
|
||||
|
||||
const handlers = [
|
||||
["ready", window.EJS_ready],
|
||||
["start", window.EJS_onGameStart],
|
||||
["loadState", window.EJS_onLoadState],
|
||||
["saveState", window.EJS_onSaveState],
|
||||
["loadSave", window.EJS_onLoadSave],
|
||||
["saveSave", window.EJS_onSaveSave]
|
||||
];
|
||||
|
||||
handlers.forEach(([event, callback]) => {
|
||||
if (typeof callback === "function") {
|
||||
window.EJS_emulator.on(event, callback);
|
||||
}
|
||||
});
|
||||
|
||||
if (typeof window.EJS_onSaveUpdate === "function") {
|
||||
window.EJS_emulator.on("saveUpdate", window.EJS_onSaveUpdate);
|
||||
window.EJS_emulator.enableSaveUpdateEvent();
|
||||
}
|
||||
})();
|
||||
Reference in New Issue
Block a user