mirror of
https://github.com/EmulatorJS/EmulatorJS.git
synced 2024-09-20 02:46:23 +00:00
Compare commits
No commits in common. "735c20b3be3b31d6f9b9a41c3952b3c51a425c25" and "8ab41f94480dd6c8ca9d6883507e72ee15013f08" have entirely different histories.
735c20b3be
...
8ab41f9448
6 changed files with 173 additions and 236 deletions
|
@ -6,8 +6,7 @@
|
||||||
"storage.js",
|
"storage.js",
|
||||||
"gamepad.js",
|
"gamepad.js",
|
||||||
"GameManager.js",
|
"GameManager.js",
|
||||||
"socket.io.min.js",
|
"socket.io.min.js"
|
||||||
"compression.js"
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -9,8 +9,7 @@ const scripts = [
|
||||||
"storage.js",
|
"storage.js",
|
||||||
"gamepad.js",
|
"gamepad.js",
|
||||||
"GameManager.js",
|
"GameManager.js",
|
||||||
"socket.io.min.js",
|
"socket.io.min.js"
|
||||||
"compression.js"
|
|
||||||
];
|
];
|
||||||
let code = "(function() {\n";
|
let code = "(function() {\n";
|
||||||
for (let i=0; i<scripts.length; i++) {
|
for (let i=0; i<scripts.length; i++) {
|
||||||
|
|
|
@ -39,17 +39,14 @@ class EJS_GameManager {
|
||||||
|
|
||||||
this.writeFile("/home/web_user/retroarch/userdata/retroarch.cfg", this.getRetroArchCfg());
|
this.writeFile("/home/web_user/retroarch/userdata/retroarch.cfg", this.getRetroArchCfg());
|
||||||
|
|
||||||
this.FS.mount(this.FS.filesystems.IDBFS, {autoPersist: true}, '/data/saves');
|
this.FS.mount(IDBFS, {}, '/data/saves');
|
||||||
//this.FS.syncfs(true, () => {});
|
this.FS.syncfs(true, () => {});
|
||||||
|
|
||||||
this.initShaders();
|
this.initShaders();
|
||||||
|
|
||||||
this.EJS.on("exit", () => {
|
this.EJS.addEventListener(window, "beforeunload", () => {
|
||||||
this.toggleMainLoop(0);
|
this.saveSaveFiles();
|
||||||
this.functions.saveSaveFiles();
|
this.FS.syncfs(() => {});
|
||||||
setTimeout(() => {
|
|
||||||
try {window.abort()} catch(e){};
|
|
||||||
}, 1000);
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
loadExternalFiles() {
|
loadExternalFiles() {
|
||||||
|
@ -162,7 +159,7 @@ class EJS_GameManager {
|
||||||
return new Promise(async resolve => {
|
return new Promise(async resolve => {
|
||||||
while (1) {
|
while (1) {
|
||||||
try {
|
try {
|
||||||
this.FS.stat("/screenshot.png");
|
FS.stat("/screenshot.png");
|
||||||
return resolve(this.FS.readFile("/screenshot.png"));
|
return resolve(this.FS.readFile("/screenshot.png"));
|
||||||
} catch(e) {}
|
} catch(e) {}
|
||||||
|
|
||||||
|
@ -271,14 +268,14 @@ class EJS_GameManager {
|
||||||
}
|
}
|
||||||
for (let i=0; i<fileNames.length; i++) {
|
for (let i=0; i<fileNames.length; i++) {
|
||||||
const contents = " FILE \""+fileNames[i]+"\" BINARY\n TRACK 01 MODE1/2352\n INDEX 01 00:00:00";
|
const contents = " FILE \""+fileNames[i]+"\" BINARY\n TRACK 01 MODE1/2352\n INDEX 01 00:00:00";
|
||||||
this.FS.writeFile("/"+baseFileName+"-"+i+".cue", contents);
|
FS.writeFile("/"+baseFileName+"-"+i+".cue", contents);
|
||||||
}
|
}
|
||||||
if (fileNames.length > 1) {
|
if (fileNames.length > 1) {
|
||||||
let contents = "";
|
let contents = "";
|
||||||
for (let i=0; i<fileNames.length; i++) {
|
for (let i=0; i<fileNames.length; i++) {
|
||||||
contents += "/"+baseFileName+"-"+i+".cue\n";
|
contents += "/"+baseFileName+"-"+i+".cue\n";
|
||||||
}
|
}
|
||||||
this.FS.writeFile("/"+baseFileName+".m3u", contents);
|
FS.writeFile("/"+baseFileName+".m3u", contents);
|
||||||
}
|
}
|
||||||
return (fileNames.length === 1) ? baseFileName+"-0.cue" : baseFileName+".m3u";
|
return (fileNames.length === 1) ? baseFileName+"-0.cue" : baseFileName+".m3u";
|
||||||
}
|
}
|
||||||
|
@ -302,7 +299,7 @@ class EJS_GameManager {
|
||||||
if (paths[i] === "") continue;
|
if (paths[i] === "") continue;
|
||||||
cp += "/"+paths[i];
|
cp += "/"+paths[i];
|
||||||
if (!FS.analyzePath(cp).exists) {
|
if (!FS.analyzePath(cp).exists) {
|
||||||
this.FS.mkdir(cp);
|
FS.mkdir(cp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.FS.writeFile(path, data);
|
this.FS.writeFile(path, data);
|
||||||
|
@ -347,15 +344,15 @@ class EJS_GameManager {
|
||||||
}
|
}
|
||||||
saveSaveFiles() {
|
saveSaveFiles() {
|
||||||
this.functions.saveSaveFiles();
|
this.functions.saveSaveFiles();
|
||||||
//this.FS.syncfs(false, () => {});
|
this.FS.syncfs(false, () => {});
|
||||||
}
|
}
|
||||||
supportsStates() {
|
supportsStates() {
|
||||||
return !!this.functions.supportsStates();
|
return !!this.functions.supportsStates();
|
||||||
}
|
}
|
||||||
getSaveFile() {
|
getSaveFile() {
|
||||||
this.saveSaveFiles();
|
this.saveSaveFiles();
|
||||||
const exists = this.FS.analyzePath(this.getSaveFilePath()).exists;
|
const exists = FS.analyzePath(this.getSaveFilePath()).exists;
|
||||||
return (exists ? this.FS.readFile(this.getSaveFilePath()) : null);
|
return (exists ? FS.readFile(this.getSaveFilePath()) : null);
|
||||||
}
|
}
|
||||||
loadSaveFiles() {
|
loadSaveFiles() {
|
||||||
this.clearEJSResetTimer();
|
this.clearEJSResetTimer();
|
||||||
|
|
|
@ -1,104 +0,0 @@
|
||||||
class EJS_COMPRESSION {
|
|
||||||
cache = {};
|
|
||||||
constructor(EJS) {
|
|
||||||
this.EJS = EJS;
|
|
||||||
}
|
|
||||||
isCompressed(data) { //https://www.garykessler.net/library/file_sigs.html
|
|
||||||
//todo. Use hex instead of numbers
|
|
||||||
if ((data[0] === 80 && data[1] === 75) && ((data[2] === 3 && data[3] === 4) || (data[2] === 5 && data[3] === 6) || (data[2] === 7 && data[3] === 8))) {
|
|
||||||
return 'zip';
|
|
||||||
} else if (data[0] === 55 && data[1] === 122 && data[2] === 188 && data[3] === 175 && data[4] === 39 && data[5] === 28) {
|
|
||||||
return '7z';
|
|
||||||
} else if ((data[0] === 82 && data[1] === 97 && data[2] === 114 && data[3] === 33 && data[4] === 26 && data[5] === 7) && ((data[6] === 0) || (data[6] === 1 && data[7] == 0))) {
|
|
||||||
return 'rar';
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
decompress(data, updateMsg, fileCbFunc) {
|
|
||||||
const compressed = this.isCompressed(data.slice(0, 10));
|
|
||||||
if (compressed === null) {
|
|
||||||
if (typeof fileCbFunc === "function") {
|
|
||||||
fileCbFunc("!!notCompressedData", data);
|
|
||||||
}
|
|
||||||
return new Promise(resolve => resolve({"!!notCompressedData": data}));
|
|
||||||
}
|
|
||||||
return this.decompressFile(compressed, data, updateMsg, fileCbFunc);
|
|
||||||
}
|
|
||||||
getWorkerFile(method) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
let path, obj;
|
|
||||||
if (method === "7z") {
|
|
||||||
path = "compression/extract7z.js";
|
|
||||||
obj = "sevenZip";
|
|
||||||
} else if (method === "zip") {
|
|
||||||
path = "compression/extractzip.js";
|
|
||||||
obj = "zip";
|
|
||||||
} else if (method === "rar") {
|
|
||||||
path = "compression/libunrar.js";
|
|
||||||
obj = "rar";
|
|
||||||
}
|
|
||||||
if (this.cache[obj]) {
|
|
||||||
return this.cache[obj];
|
|
||||||
}
|
|
||||||
this.EJS.downloadFile(path, (res) => {
|
|
||||||
if (res === -1) {
|
|
||||||
this.EJS.startGameError(this.EJS.localization('Network Error'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (method === "rar") {
|
|
||||||
// Do not cache rar. This shouldnt normally be used more than once anyways.
|
|
||||||
this.EJS.downloadFile("compression/libunrar.wasm", (res2) => {
|
|
||||||
if (res2 === -1) {
|
|
||||||
this.EJS.startGameError(this.EJS.localization('Network Error'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const path = URL.createObjectURL(new Blob([res2.data], {type: "application/wasm"}));
|
|
||||||
let data = '\nlet dataToPass = [];\nModule = {\n monitorRunDependencies: function(left) {\n if (left == 0) {\n setTimeout(function() {\n unrar(dataToPass, null);\n }, 100);\n }\n },\n onRuntimeInitialized: function() {\n },\n locateFile: function(file) {\n return \''+path+'\';\n }\n};\n'+res.data+'\nlet unrar = function(data, password) {\n let cb = function(fileName, fileSize, progress) {\n postMessage({"t":4,"current":progress,"total":fileSize, "name": fileName});\n };\n\n let rarContent = readRARContent(data.map(function(d) {\n return {\n name: d.name,\n content: new Uint8Array(d.content)\n }\n }), password, cb)\n let rec = function(entry) {\n if (!entry) return;\n if (entry.type === \'file\') {\n postMessage({"t":2,"file":entry.fullFileName,"size":entry.fileSize,"data":entry.fileContent});\n } else if (entry.type === \'dir\') {\n Object.keys(entry.ls).forEach(function(k) {\n rec(entry.ls[k]);\n })\n } else {\n throw "Unknown type";\n }\n }\n rec(rarContent);\n postMessage({"t":1});\n return rarContent;\n};\nonmessage = function(data) {\n dataToPass.push({name: \'test.rar\', content: data.data});\n};\n ';
|
|
||||||
const blob = new Blob([data], {
|
|
||||||
type: 'application/javascript'
|
|
||||||
})
|
|
||||||
resolve(blob);
|
|
||||||
}, null, false, {responseType: "arraybuffer", method: "GET"});
|
|
||||||
} else {
|
|
||||||
const blob = new Blob([res.data], {
|
|
||||||
type: 'application/javascript'
|
|
||||||
})
|
|
||||||
this.cache[obj] = blob;
|
|
||||||
resolve(blob);
|
|
||||||
}
|
|
||||||
}, null, false, {responseType: "arraybuffer", method: "GET"});
|
|
||||||
})
|
|
||||||
}
|
|
||||||
decompressFile(method, data, updateMsg, fileCbFunc) {
|
|
||||||
return new Promise(async callback => {
|
|
||||||
const file = await this.getWorkerFile(method);
|
|
||||||
const worker = new Worker(URL.createObjectURL(file));
|
|
||||||
const files = {};
|
|
||||||
worker.onmessage = (data) => {
|
|
||||||
if (!data.data) return;
|
|
||||||
//data.data.t/ 4=progress, 2 is file, 1 is zip done
|
|
||||||
if (data.data.t === 4) {
|
|
||||||
const pg = data.data;
|
|
||||||
const num = Math.floor(pg.current / pg.total * 100);
|
|
||||||
if (isNaN(num)) return;
|
|
||||||
const progress = ' '+num.toString()+'%';
|
|
||||||
updateMsg(progress, true);
|
|
||||||
}
|
|
||||||
if (data.data.t === 2) {
|
|
||||||
if (typeof fileCbFunc === "function") {
|
|
||||||
fileCbFunc(data.data.file, data.data.data);
|
|
||||||
files[data.data.file] = true;
|
|
||||||
} else {
|
|
||||||
files[data.data.file] = data.data.data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (data.data.t === 1) {
|
|
||||||
callback(files);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
worker.postMessage(data);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
window.EJS_COMPRESSION = EJS_COMPRESSION;
|
|
|
@ -202,29 +202,20 @@ class EmulatorJS {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
checkForUpdates() {
|
checkForUpdates() {
|
||||||
if (this.ejs_version.endsWith("-beta")) {
|
|
||||||
console.warn("Using EmulatorJS beta. Not checking for updates. This instance may be out of date. Using stable is highly recommended unless you build and ship your own cores.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
fetch('https://cdn.emulatorjs.org/stable/data/version.json').then(response => {
|
fetch('https://cdn.emulatorjs.org/stable/data/version.json').then(response => {
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
response.text().then(body => {
|
response.text().then(body => {
|
||||||
let version = JSON.parse(body);
|
let version = JSON.parse(body);
|
||||||
if (this.versionAsInt(this.ejs_version) < this.versionAsInt(version.current_version)) {
|
if (this.ejs_num_version < version.current_version) {
|
||||||
console.log('Using EmulatorJS version ' + this.versionAsInt(this.ejs_version) + ' but the newest version is ' + this.versionAsInt(version.current_version) + '\nopen https://github.com/EmulatorJS/EmulatorJS to update');
|
console.log('Using EmulatorJS version ' + this.ejs_num_version + ' but the newest version is ' + version.current_version + '\nopen https://github.com/EmulatorJS/EmulatorJS to update');
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
versionAsInt(ver) {
|
|
||||||
if (ver.endsWith("-beta")) {
|
|
||||||
return 99999999;
|
|
||||||
}
|
|
||||||
return parseInt(ver.split(".").join(""));
|
|
||||||
}
|
|
||||||
constructor(element, config) {
|
constructor(element, config) {
|
||||||
this.ejs_version = "4.0.13-beta";
|
this.ejs_version = "4.0.12";
|
||||||
|
this.ejs_num_version = 401.2;
|
||||||
this.debug = (window.EJS_DEBUG_XX === true);
|
this.debug = (window.EJS_DEBUG_XX === true);
|
||||||
if (this.debug || (window.location && ['localhost', '127.0.0.1'].includes(location.hostname))) this.checkForUpdates();
|
if (this.debug || (window.location && ['localhost', '127.0.0.1'].includes(location.hostname))) this.checkForUpdates();
|
||||||
this.netplayEnabled = (window.EJS_DEBUG_XX === true) && (window.EJS_EXPERIMENTAL_NETPLAY === true);
|
this.netplayEnabled = (window.EJS_DEBUG_XX === true) && (window.EJS_EXPERIMENTAL_NETPLAY === true);
|
||||||
|
@ -484,16 +475,126 @@ class EmulatorJS {
|
||||||
}
|
}
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
checkCompression(data, msg, fileCbFunc) {
|
isCompressed(data) { //https://www.garykessler.net/library/file_sigs.html
|
||||||
if (!this.compression) {
|
//todo. Use hex instead of numbers
|
||||||
this.compression = new window.EJS_COMPRESSION(this);
|
if ((data[0] === 80 && data[1] === 75) && ((data[2] === 3 && data[3] === 4) || (data[2] === 5 && data[3] === 6) || (data[2] === 7 && data[3] === 8))) {
|
||||||
|
return 'zip';
|
||||||
|
} else if (data[0] === 55 && data[1] === 122 && data[2] === 188 && data[3] === 175 && data[4] === 39 && data[5] === 28) {
|
||||||
|
return '7z';
|
||||||
|
} else if ((data[0] === 82 && data[1] === 97 && data[2] === 114 && data[3] === 33 && data[4] === 26 && data[5] === 7) && ((data[6] === 0) || (data[6] === 1 && data[7] == 0))) {
|
||||||
|
return 'rar';
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
checkCompression(data, msg, fileCbFunc) {
|
||||||
if (msg) {
|
if (msg) {
|
||||||
this.textElem.innerText = msg;
|
this.textElem.innerText = msg;
|
||||||
}
|
}
|
||||||
return this.compression.decompress(data, (m, appendMsg) => {
|
//to be put in another file
|
||||||
this.textElem.innerText = appendMsg ? (msg + m) : m;
|
const createWorker = (path) => {
|
||||||
}, fileCbFunc);
|
return new Promise((resolve, reject) => {
|
||||||
|
this.downloadFile(path, (res) => {
|
||||||
|
if (res === -1) {
|
||||||
|
this.startGameError(this.localization('Network Error'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const blob = new Blob([res.data], {
|
||||||
|
'type': 'application/javascript'
|
||||||
|
})
|
||||||
|
const url = window.URL.createObjectURL(blob);
|
||||||
|
resolve(new Worker(url));
|
||||||
|
}, null, false, {responseType: "arraybuffer", method: "GET"});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const files = {};
|
||||||
|
let res;
|
||||||
|
const onMessage = (data) => {
|
||||||
|
if (!data.data) return;
|
||||||
|
//data.data.t/ 4=progress, 2 is file, 1 is zip done
|
||||||
|
if (data.data.t === 4 && msg) {
|
||||||
|
const pg = data.data;
|
||||||
|
const num = Math.floor(pg.current / pg.total * 100);
|
||||||
|
if (isNaN(num)) return;
|
||||||
|
const progress = ' '+num.toString()+'%';
|
||||||
|
this.textElem.innerText = msg + progress;
|
||||||
|
}
|
||||||
|
if (data.data.t === 2) {
|
||||||
|
if (typeof fileCbFunc === "function") {
|
||||||
|
fileCbFunc(data.data.file, data.data.data);
|
||||||
|
files[data.data.file] = true;
|
||||||
|
} else {
|
||||||
|
files[data.data.file] = data.data.data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (data.data.t === 1) {
|
||||||
|
res(files);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const decompress7z = (file) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
res = resolve;
|
||||||
|
|
||||||
|
createWorker('compression/extract7z.js').then((worker) => {
|
||||||
|
worker.onmessage = onMessage;
|
||||||
|
worker.postMessage(file);
|
||||||
|
//console.log(file);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const decompressRar = (file) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
res = resolve;
|
||||||
|
|
||||||
|
this.downloadFile("compression/libunrar.js", (res) => {
|
||||||
|
this.downloadFile("compression/libunrar.wasm", (res2) => {
|
||||||
|
if (res === -1 || res2 === -1) {
|
||||||
|
this.startGameError(this.localization('Network Error'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const path = URL.createObjectURL(new Blob([res2.data], {type: "application/wasm"}));
|
||||||
|
let data = '\nlet dataToPass = [];\nModule = {\n monitorRunDependencies: function(left) {\n if (left == 0) {\n setTimeout(function() {\n unrar(dataToPass, null);\n }, 100);\n }\n },\n onRuntimeInitialized: function() {\n },\n locateFile: function(file) {\n return \''+path+'\';\n }\n};\n'+res.data+'\nlet unrar = function(data, password) {\n let cb = function(fileName, fileSize, progress) {\n postMessage({"t":4,"current":progress,"total":fileSize, "name": fileName});\n };\n\n let rarContent = readRARContent(data.map(function(d) {\n return {\n name: d.name,\n content: new Uint8Array(d.content)\n }\n }), password, cb)\n let rec = function(entry) {\n if (!entry) return;\n if (entry.type === \'file\') {\n postMessage({"t":2,"file":entry.fullFileName,"size":entry.fileSize,"data":entry.fileContent});\n } else if (entry.type === \'dir\') {\n Object.keys(entry.ls).forEach(function(k) {\n rec(entry.ls[k]);\n })\n } else {\n throw "Unknown type";\n }\n }\n rec(rarContent);\n postMessage({"t":1});\n return rarContent;\n};\nonmessage = function(data) {\n dataToPass.push({name: \'test.rar\', content: data.data});\n};\n ';
|
||||||
|
const blob = new Blob([data], {
|
||||||
|
'type': 'application/javascript'
|
||||||
|
})
|
||||||
|
const url = window.URL.createObjectURL(blob);
|
||||||
|
const worker = new Worker(url);
|
||||||
|
worker.onmessage = onMessage;
|
||||||
|
worker.postMessage(file);
|
||||||
|
}, null, false, {responseType: "arraybuffer", method: "GET"})
|
||||||
|
}, null, false, {responseType: "text", method: "GET"});
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const decompressZip = (file) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
res = resolve;
|
||||||
|
|
||||||
|
createWorker('compression/extractzip.js').then((worker) => {
|
||||||
|
worker.onmessage = onMessage;
|
||||||
|
worker.postMessage(file);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const compression = this.isCompressed(data.slice(0, 10));
|
||||||
|
if (compression) {
|
||||||
|
//Need to do zip and rar still
|
||||||
|
if (compression === "7z") {
|
||||||
|
return decompress7z(data);
|
||||||
|
} else if (compression === "zip") {
|
||||||
|
return decompressZip(data);
|
||||||
|
} else if (compression === "rar") {
|
||||||
|
return decompressRar(data);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (typeof fileCbFunc === "function") {
|
||||||
|
fileCbFunc("!!notCompressedData", data);
|
||||||
|
return new Promise(resolve => resolve({"!!notCompressedData": true}));
|
||||||
|
} else {
|
||||||
|
return new Promise(resolve => resolve({"!!notCompressedData": data}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
versionAsInt(ver) {
|
||||||
|
return parseInt(ver.split(".").join(""));
|
||||||
}
|
}
|
||||||
checkCoreCompatibility(version) {
|
checkCoreCompatibility(version) {
|
||||||
// Leave commented until next release - this is ready to go.
|
// Leave commented until next release - this is ready to go.
|
||||||
|
@ -561,11 +662,11 @@ class EmulatorJS {
|
||||||
let legacy = (this.supportsWebgl2 && this.webgl2Enabled ? "" : "-legacy");
|
let legacy = (this.supportsWebgl2 && this.webgl2Enabled ? "" : "-legacy");
|
||||||
let filename = this.getCore()+(this.config.threads ? "-thread" : "")+legacy+"-wasm.data";
|
let filename = this.getCore()+(this.config.threads ? "-thread" : "")+legacy+"-wasm.data";
|
||||||
this.storage.core.get(filename).then((result) => {
|
this.storage.core.get(filename).then((result) => {
|
||||||
if (result && result.version === rep.buildStart && !this.debug) {
|
if (result && result.version === rep.buildStart && !this.debug) {
|
||||||
gotCore(result.data);
|
gotCore(result.data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const corePath = 'cores/'+filename;
|
const corePath = 'cores/'+filename;
|
||||||
this.downloadFile(corePath, (res) => {
|
this.downloadFile(corePath, (res) => {
|
||||||
if (res === -1) {
|
if (res === -1) {
|
||||||
console.log("File not found, attemping to fetch from emulatorjs cdn");
|
console.log("File not found, attemping to fetch from emulatorjs cdn");
|
||||||
|
@ -601,11 +702,9 @@ class EmulatorJS {
|
||||||
}, null, false, {responseType: "text", method: "GET"});
|
}, null, false, {responseType: "text", method: "GET"});
|
||||||
}
|
}
|
||||||
initGameCore(js, wasm, thread) {
|
initGameCore(js, wasm, thread) {
|
||||||
|
this.initModule(wasm, thread);
|
||||||
let script = this.createElement("script");
|
let script = this.createElement("script");
|
||||||
script.src = URL.createObjectURL(new Blob([js], {type: "application/javascript"}));
|
script.src = URL.createObjectURL(new Blob([js], {type: "application/javascript"}));
|
||||||
script.addEventListener("load", () => {
|
|
||||||
this.initModule(wasm, thread);
|
|
||||||
});
|
|
||||||
document.body.appendChild(script);
|
document.body.appendChild(script);
|
||||||
}
|
}
|
||||||
getBaseFileName(force) {
|
getBaseFileName(force) {
|
||||||
|
@ -674,11 +773,11 @@ class EmulatorJS {
|
||||||
this.checkCompression(new Uint8Array(data), this.localization("Decompress Game Patch")).then((data) => {
|
this.checkCompression(new Uint8Array(data), this.localization("Decompress Game Patch")).then((data) => {
|
||||||
for (const k in data) {
|
for (const k in data) {
|
||||||
if (k === "!!notCompressedData") {
|
if (k === "!!notCompressedData") {
|
||||||
this.gameManager.FS.writeFile(this.config.gamePatchUrl.split('/').pop().split("#")[0].split("?")[0], data[k]);
|
FS.writeFile(this.config.gamePatchUrl.split('/').pop().split("#")[0].split("?")[0], data[k]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (k.endsWith('/')) continue;
|
if (k.endsWith('/')) continue;
|
||||||
this.gameManager.FS.writeFile("/" + k.split('/').pop(), data[k]);
|
FS.writeFile("/" + k.split('/').pop(), data[k]);
|
||||||
}
|
}
|
||||||
resolve();
|
resolve();
|
||||||
})
|
})
|
||||||
|
@ -724,11 +823,11 @@ class EmulatorJS {
|
||||||
this.checkCompression(new Uint8Array(data), this.localization("Decompress Game Parent")).then((data) => {
|
this.checkCompression(new Uint8Array(data), this.localization("Decompress Game Parent")).then((data) => {
|
||||||
for (const k in data) {
|
for (const k in data) {
|
||||||
if (k === "!!notCompressedData") {
|
if (k === "!!notCompressedData") {
|
||||||
this.gameManager.FS.writeFile(this.config.gameParentUrl.split('/').pop().split("#")[0].split("?")[0], data[k]);
|
FS.writeFile(this.config.gameParentUrl.split('/').pop().split("#")[0].split("?")[0], data[k]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (k.endsWith('/')) continue;
|
if (k.endsWith('/')) continue;
|
||||||
this.gameManager.FS.writeFile("/" + k.split('/').pop(), data[k]);
|
FS.writeFile("/" + k.split('/').pop(), data[k]);
|
||||||
}
|
}
|
||||||
resolve();
|
resolve();
|
||||||
})
|
})
|
||||||
|
@ -774,11 +873,11 @@ class EmulatorJS {
|
||||||
this.checkCompression(new Uint8Array(data), this.localization("Decompress Game BIOS")).then((data) => {
|
this.checkCompression(new Uint8Array(data), this.localization("Decompress Game BIOS")).then((data) => {
|
||||||
for (const k in data) {
|
for (const k in data) {
|
||||||
if (k === "!!notCompressedData") {
|
if (k === "!!notCompressedData") {
|
||||||
this.gameManager.FS.writeFile(this.config.biosUrl.split('/').pop().split("#")[0].split("?")[0], data[k]);
|
FS.writeFile(this.config.biosUrl.split('/').pop().split("#")[0].split("?")[0], data[k]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (k.endsWith('/')) continue;
|
if (k.endsWith('/')) continue;
|
||||||
this.gameManager.FS.writeFile("/" + k.split('/').pop(), data[k]);
|
FS.writeFile("/" + k.split('/').pop(), data[k]);
|
||||||
}
|
}
|
||||||
resolve();
|
resolve();
|
||||||
})
|
})
|
||||||
|
@ -829,7 +928,7 @@ class EmulatorJS {
|
||||||
const gotGameData = (data) => {
|
const gotGameData = (data) => {
|
||||||
if (['arcade', 'mame'].includes(this.getCore(true))) {
|
if (['arcade', 'mame'].includes(this.getCore(true))) {
|
||||||
this.fileName = this.getBaseFileName(true);
|
this.fileName = this.getBaseFileName(true);
|
||||||
this.gameManager.FS.writeFile(this.fileName, new Uint8Array(data));
|
FS.writeFile(this.fileName, new Uint8Array(data));
|
||||||
resolve();
|
resolve();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -851,20 +950,20 @@ class EmulatorJS {
|
||||||
for (let i=0; i<paths.length-1; i++) {
|
for (let i=0; i<paths.length-1; i++) {
|
||||||
if (paths[i] === "") continue;
|
if (paths[i] === "") continue;
|
||||||
cp += `/${paths[i]}`;
|
cp += `/${paths[i]}`;
|
||||||
if (!this.gameManager.FS.analyzePath(cp).exists) {
|
if (!FS.analyzePath(cp).exists) {
|
||||||
this.gameManager.FS.mkdir(cp);
|
FS.mkdir(cp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (fileName.endsWith('/')) {
|
if (fileName.endsWith('/')) {
|
||||||
this.gameManager.FS.mkdir(fileName);
|
FS.mkdir(fileName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (fileName === "!!notCompressedData") {
|
if (fileName === "!!notCompressedData") {
|
||||||
this.gameManager.FS.writeFile(altName, fileData);
|
FS.writeFile(altName, fileData);
|
||||||
fileNames.push(altName);
|
fileNames.push(altName);
|
||||||
} else {
|
} else {
|
||||||
this.gameManager.FS.writeFile(`/${fileName}`, fileData);
|
FS.writeFile(`/${fileName}`, fileData);
|
||||||
fileNames.push(fileName);
|
fileNames.push(fileName);
|
||||||
}
|
}
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
|
@ -968,28 +1067,26 @@ class EmulatorJS {
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
initModule(wasmData, threadData) {
|
initModule(wasmData, threadData) {
|
||||||
window.EJS_Runtime({
|
window.Module = {
|
||||||
noInitialRun: true,
|
'noInitialRun': true,
|
||||||
onRuntimeInitialized: null,
|
'onRuntimeInitialized': this.downloadFiles.bind(this),
|
||||||
arguments: [],
|
'arguments': [],
|
||||||
preRun: [],
|
'preRun': [],
|
||||||
postRun: [],
|
'postRun': [],
|
||||||
canvas: this.canvas,
|
'canvas': this.canvas,
|
||||||
print: (msg) => {
|
'print': (msg) => {
|
||||||
if (this.debug) {
|
if (this.debug) {
|
||||||
console.log(msg);
|
console.log(msg);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
printErr: (msg) => {
|
'printErr': (msg) => {
|
||||||
if (this.debug) {
|
if (this.debug) {
|
||||||
console.log(msg);
|
console.log(msg);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
totalDependencies: 0,
|
'totalDependencies': 0,
|
||||||
monitorRunDependencies: () => {},
|
'monitorRunDependencies': () => {},
|
||||||
locateFile: function(fileName) {
|
'locateFile': function(fileName) {
|
||||||
if (this.debug) console.log(fileName);
|
if (this.debug) console.log(fileName);
|
||||||
if (fileName.endsWith(".wasm")) {
|
if (fileName.endsWith(".wasm")) {
|
||||||
return URL.createObjectURL(new Blob([wasmData], {type: "application/wasm"}));
|
return URL.createObjectURL(new Blob([wasmData], {type: "application/wasm"}));
|
||||||
|
@ -997,10 +1094,8 @@ class EmulatorJS {
|
||||||
return URL.createObjectURL(new Blob([threadData], {type: "application/javascript"}));
|
return URL.createObjectURL(new Blob([threadData], {type: "application/javascript"}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).then(module => {
|
};
|
||||||
this.Module = module;
|
this.Module = window.Module;
|
||||||
this.downloadFiles();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
startGame() {
|
startGame() {
|
||||||
try {
|
try {
|
||||||
|
@ -1591,18 +1686,19 @@ class EmulatorJS {
|
||||||
|
|
||||||
const restartButton = addButton("Restart", '<svg viewBox="0 0 512 512"><path d="M496 48V192c0 17.69-14.31 32-32 32H320c-17.69 0-32-14.31-32-32s14.31-32 32-32h63.39c-29.97-39.7-77.25-63.78-127.6-63.78C167.7 96.22 96 167.9 96 256s71.69 159.8 159.8 159.8c34.88 0 68.03-11.03 95.88-31.94c14.22-10.53 34.22-7.75 44.81 6.375c10.59 14.16 7.75 34.22-6.375 44.81c-39.03 29.28-85.36 44.86-134.2 44.86C132.5 479.9 32 379.4 32 256s100.5-223.9 223.9-223.9c69.15 0 134 32.47 176.1 86.12V48c0-17.69 14.31-32 32-32S496 30.31 496 48z"/></svg>', () => {
|
const restartButton = addButton("Restart", '<svg viewBox="0 0 512 512"><path d="M496 48V192c0 17.69-14.31 32-32 32H320c-17.69 0-32-14.31-32-32s14.31-32 32-32h63.39c-29.97-39.7-77.25-63.78-127.6-63.78C167.7 96.22 96 167.9 96 256s71.69 159.8 159.8 159.8c34.88 0 68.03-11.03 95.88-31.94c14.22-10.53 34.22-7.75 44.81 6.375c10.59 14.16 7.75 34.22-6.375 44.81c-39.03 29.28-85.36 44.86-134.2 44.86C132.5 479.9 32 379.4 32 256s100.5-223.9 223.9-223.9c69.15 0 134 32.47 176.1 86.12V48c0-17.69 14.31-32 32-32S496 30.31 496 48z"/></svg>', () => {
|
||||||
if (this.isNetplay && this.netplay.owner) {
|
if (this.isNetplay && this.netplay.owner) {
|
||||||
|
this.gameManager.saveSaveFiles();
|
||||||
this.gameManager.restart();
|
this.gameManager.restart();
|
||||||
this.netplay.reset();
|
this.netplay.reset();
|
||||||
this.netplay.sendMessage({restart:true});
|
this.netplay.sendMessage({restart:true});
|
||||||
this.play();
|
this.play();
|
||||||
} else if (!this.isNetplay) {
|
} else if (!this.isNetplay) {
|
||||||
|
this.gameManager.saveSaveFiles();
|
||||||
this.gameManager.restart();
|
this.gameManager.restart();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const pauseButton = addButton("Pause", '<svg viewBox="0 0 320 512"><path d="M272 63.1l-32 0c-26.51 0-48 21.49-48 47.1v288c0 26.51 21.49 48 48 48L272 448c26.51 0 48-21.49 48-48v-288C320 85.49 298.5 63.1 272 63.1zM80 63.1l-32 0c-26.51 0-48 21.49-48 48v288C0 426.5 21.49 448 48 448l32 0c26.51 0 48-21.49 48-48v-288C128 85.49 106.5 63.1 80 63.1z"/></svg>', () => {
|
const pauseButton = addButton("Pause", '<svg viewBox="0 0 320 512"><path d="M272 63.1l-32 0c-26.51 0-48 21.49-48 47.1v288c0 26.51 21.49 48 48 48L272 448c26.51 0 48-21.49 48-48v-288C320 85.49 298.5 63.1 272 63.1zM80 63.1l-32 0c-26.51 0-48 21.49-48 48v288C0 426.5 21.49 448 48 448l32 0c26.51 0 48-21.49 48-48v-288C128 85.49 106.5 63.1 80 63.1z"/></svg>', () => {
|
||||||
if (this.isNetplay && this.netplay.owner) {
|
if (this.isNetplay && this.netplay.owner) {
|
||||||
this.pause();
|
this.pause();
|
||||||
this.gameManager.saveSaveFiles();
|
|
||||||
this.netplay.sendMessage({pause:true});
|
this.netplay.sendMessage({pause:true});
|
||||||
} else if (!this.isNetplay) {
|
} else if (!this.isNetplay) {
|
||||||
this.pause();
|
this.pause();
|
||||||
|
@ -1720,10 +1816,10 @@ class EmulatorJS {
|
||||||
for (let i=0; i<paths.length-1; i++) {
|
for (let i=0; i<paths.length-1; i++) {
|
||||||
if (paths[i] === "") continue;
|
if (paths[i] === "") continue;
|
||||||
cp += "/"+paths[i];
|
cp += "/"+paths[i];
|
||||||
if (!this.gameManager.FS.analyzePath(cp).exists) this.gameManager.FS.mkdir(cp);
|
if (!FS.analyzePath(cp).exists) FS.mkdir(cp);
|
||||||
}
|
}
|
||||||
if (this.gameManager.FS.analyzePath(path).exists) this.gameManager.FS.unlink(path);
|
if (FS.analyzePath(path).exists) FS.unlink(path);
|
||||||
this.gameManager.FS.writeFile(path, sav);
|
FS.writeFile(path, sav);
|
||||||
this.gameManager.loadSaveFiles();
|
this.gameManager.loadSaveFiles();
|
||||||
});
|
});
|
||||||
const netplay = addButton("Netplay", '<svg viewBox="0 0 512 512"><path fill="currentColor" d="M364.215 192h131.43c5.439 20.419 8.354 41.868 8.354 64s-2.915 43.581-8.354 64h-131.43c5.154-43.049 4.939-86.746 0-128zM185.214 352c10.678 53.68 33.173 112.514 70.125 151.992.221.001.44.008.661.008s.44-.008.661-.008c37.012-39.543 59.467-98.414 70.125-151.992H185.214zm174.13-192h125.385C452.802 84.024 384.128 27.305 300.95 12.075c30.238 43.12 48.821 96.332 58.394 147.925zm-27.35 32H180.006c-5.339 41.914-5.345 86.037 0 128h151.989c5.339-41.915 5.345-86.037-.001-128zM152.656 352H27.271c31.926 75.976 100.6 132.695 183.778 147.925-30.246-43.136-48.823-96.35-58.393-147.925zm206.688 0c-9.575 51.605-28.163 104.814-58.394 147.925 83.178-15.23 151.852-71.949 183.778-147.925H359.344zm-32.558-192c-10.678-53.68-33.174-112.514-70.125-151.992-.221 0-.44-.008-.661-.008s-.44.008-.661.008C218.327 47.551 195.872 106.422 185.214 160h141.572zM16.355 192C10.915 212.419 8 233.868 8 256s2.915 43.581 8.355 64h131.43c-4.939-41.254-5.154-84.951 0-128H16.355zm136.301-32c9.575-51.602 28.161-104.81 58.394-147.925C127.872 27.305 59.198 84.024 27.271 160h125.385z"/></svg>', async () => {
|
const netplay = addButton("Netplay", '<svg viewBox="0 0 512 512"><path fill="currentColor" d="M364.215 192h131.43c5.439 20.419 8.354 41.868 8.354 64s-2.915 43.581-8.354 64h-131.43c5.154-43.049 4.939-86.746 0-128zM185.214 352c10.678 53.68 33.173 112.514 70.125 151.992.221.001.44.008.661.008s.44-.008.661-.008c37.012-39.543 59.467-98.414 70.125-151.992H185.214zm174.13-192h125.385C452.802 84.024 384.128 27.305 300.95 12.075c30.238 43.12 48.821 96.332 58.394 147.925zm-27.35 32H180.006c-5.339 41.914-5.345 86.037 0 128h151.989c5.339-41.915 5.345-86.037-.001-128zM152.656 352H27.271c31.926 75.976 100.6 132.695 183.778 147.925-30.246-43.136-48.823-96.35-58.393-147.925zm206.688 0c-9.575 51.605-28.163 104.814-58.394 147.925 83.178-15.23 151.852-71.949 183.778-147.925H359.344zm-32.558-192c-10.678-53.68-33.174-112.514-70.125-151.992-.221 0-.44-.008-.661-.008s-.44.008-.661.008C218.327 47.551 195.872 106.422 185.214 160h141.572zM16.355 192C10.915 212.419 8 233.868 8 256s2.915 43.581 8.355 64h131.43c-4.939-41.254-5.154-84.951 0-128H16.355zm136.301-32c9.575-51.602 28.161-104.81 58.394-147.925C127.872 27.305 59.198 84.024 27.271 160h125.385z"/></svg>', async () => {
|
||||||
|
@ -1911,56 +2007,6 @@ class EmulatorJS {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const exitEmulation = addButton("Exit EmulatorJS", '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 460 460"><path style="fill:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(255,255,255);stroke-opacity:1;stroke-miterlimit:4;" d="M 14.000061 7.636414 L 14.000061 4.5 C 14.000061 4.223877 13.776123 3.999939 13.5 3.999939 L 4.5 3.999939 C 4.223877 3.999939 3.999939 4.223877 3.999939 4.5 L 3.999939 19.5 C 3.999939 19.776123 4.223877 20.000061 4.5 20.000061 L 13.5 20.000061 C 13.776123 20.000061 14.000061 19.776123 14.000061 19.5 L 14.000061 16.363586 " transform="matrix(21.333333,0,0,21.333333,0,0)"/><path style="fill:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(255,255,255);stroke-opacity:1;stroke-miterlimit:4;" d="M 9.999939 12 L 21 12 M 21 12 L 18.000366 8.499939 M 21 12 L 18 15.500061 " transform="matrix(21.333333,0,0,21.333333,0,0)"/></svg>', async () => {
|
|
||||||
const popups = this.createSubPopup();
|
|
||||||
this.game.appendChild(popups[0]);
|
|
||||||
popups[1].classList.add("ejs_cheat_parent");
|
|
||||||
popups[1].style.width = "100%";
|
|
||||||
const popup = popups[1];
|
|
||||||
const header = this.createElement("div");
|
|
||||||
header.classList.add("ejs_cheat_header");
|
|
||||||
const title = this.createElement("h2");
|
|
||||||
title.innerText = this.localization("Are you sure you want to exit?");
|
|
||||||
title.classList.add("ejs_cheat_heading");
|
|
||||||
const close = this.createElement("button");
|
|
||||||
close.classList.add("ejs_cheat_close");
|
|
||||||
header.appendChild(title);
|
|
||||||
header.appendChild(close);
|
|
||||||
popup.appendChild(header);
|
|
||||||
this.addEventListener(close, "click", (e) => {
|
|
||||||
popups[0].remove();
|
|
||||||
})
|
|
||||||
popup.appendChild(this.createElement("br"));
|
|
||||||
|
|
||||||
const footer = this.createElement("footer");
|
|
||||||
const submit = this.createElement("button");
|
|
||||||
const closeButton = this.createElement("button");
|
|
||||||
submit.innerText = this.localization("Exit");
|
|
||||||
closeButton.innerText = this.localization("Cancel");
|
|
||||||
submit.classList.add("ejs_button_button");
|
|
||||||
closeButton.classList.add("ejs_button_button");
|
|
||||||
submit.classList.add("ejs_popup_submit");
|
|
||||||
closeButton.classList.add("ejs_popup_submit");
|
|
||||||
submit.style["background-color"] = "rgba(var(--ejs-primary-color),1)";
|
|
||||||
footer.appendChild(submit);
|
|
||||||
const span = this.createElement("span");
|
|
||||||
span.innerText = " ";
|
|
||||||
footer.appendChild(span);
|
|
||||||
footer.appendChild(closeButton);
|
|
||||||
popup.appendChild(footer);
|
|
||||||
|
|
||||||
this.addEventListener(closeButton, "click", (e) => {
|
|
||||||
popups[0].remove();
|
|
||||||
})
|
|
||||||
|
|
||||||
this.addEventListener(submit, "click", (e) => {
|
|
||||||
popups[0].remove();
|
|
||||||
const body = this.createPopup("EmulatorJS has exited", {});
|
|
||||||
this.callEvent("exit");
|
|
||||||
})
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
this.addEventListener(document, "webkitfullscreenchange mozfullscreenchange fullscreenchange", (e) => {
|
this.addEventListener(document, "webkitfullscreenchange mozfullscreenchange fullscreenchange", (e) => {
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
{ "current_version": "4.0.12" }
|
{ "current_version": 401.2 }
|
||||||
|
|
Loading…
Reference in a new issue