diff --git a/index.html b/index.html
index 1ff6044..8fb8f05 100644
--- a/index.html
+++ b/index.html
@@ -5,7 +5,7 @@
diff --git a/src/css/main.css b/src/css/main.css
index 07206c4..5c5eed3 100644
--- a/src/css/main.css
+++ b/src/css/main.css
@@ -52,3 +52,8 @@
font-size: 12px;
color: #bcbcbc;
}
+
+.ejs_canvas {
+ width: 100%;
+ height: 100%;
+}
diff --git a/src/emulator.js b/src/emulator.js
index 9969d27..6f541c0 100644
--- a/src/emulator.js
+++ b/src/emulator.js
@@ -2,11 +2,12 @@ class EmulatorJS {
createElement(type) {
return document.createElement(type);
}
- downloadFile(path, cb, progressCB) {
+ downloadFile(path, cb, progressCB, notWithPath) {
//todo. Progress callback
- fetch(this.config.dataPath + path).then(async res => {
+ const basePath = notWithPath ? '' : this.config.dataPath;
+ fetch(basePath + path).then(async res => {
const ab = await res.arrayBuffer();
- cb(ab);
+ cb(new Uint8Array(ab));
});
}
@@ -14,6 +15,8 @@ class EmulatorJS {
this.setElements(element);
this.listeners = [];
this.config = config;
+ this.canvas = this.createElement('canvas');
+ this.canvas.classList.add('ejs_canvas');
this.game.classList.add("ejs_game");
@@ -46,20 +49,20 @@ class EmulatorJS {
e.preventDefault();
e.target.remove();
this.createText();
- this.downloadRom();
+ this.downloadGameCore();
}
// End start button
createText() {
- const text = this.createElement("div");
- text.classList.add("ejs_loading_text");
- text.innerText = this.localization("Loading...");
- this.elements.parent.appendChild(text);
+ this.textElem = this.createElement("div");
+ this.textElem.classList.add("ejs_loading_text");
+ this.textElem.innerText = this.localization("Loading...");
+ this.elements.parent.appendChild(this.textElem);
}
localization(text) {
//todo
return text;
}
- checkCompression(e) {
+ checkCompression(data) {
function 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))) {
@@ -70,27 +73,145 @@ class EmulatorJS {
return 'rar';
}
}
- async function decompressZip7z() {
-
+ const createWorker = (path) => {
+ return new Promise((resolve, reject) => {
+ this.downloadFile(path, (fileData) => {
+ const blob = new Blob([fileData], {
+ 'type': 'application/javascript'
+ })
+ const url = window.URL.createObjectURL(blob);
+ resolve(new Worker(url));
+ });
+ })
+ }
+ const decompress7z = (file) => {
+ return new Promise((resolve, reject) => {
+ const files = {};
+ function onMessage(data) {
+ if (!data.data) return;
+ //data.data.t/ 4=progress, 2 is file, 1 is zip done
+ if (data.data.t === 2) {
+ files[data.data.file] = data.data.data;
+ }
+ if (data.data.t === 1) {
+ resolve(files);
+ }
+ }
+
+ createWorker('compression/extract7z.js').then((worker) => {
+ worker.onmessage = onMessage;
+ worker.postMessage(file);
+ //console.log(file);
+ })
+ })
}
async function decompressRar() {
}
- const compression = isCompressed(e);
+ const compression = isCompressed(data.slice(0, 10));
if (compression) {
- console.log(compression); //where I left off
+ //Need to do zip and rar still
+ return decompress7z(data);
} else {
- return new Promise(resolve => resolve(e));
+ return new Promise(resolve => resolve(data));
}
- return e;
+ }
+ downloadGameCore() {
+ this.downloadFile('cores/'+this.getCore()+'-wasm.data', (e) => {
+ this.checkCompression(e).then((data) => {
+ //console.log(data);
+ let js, wasm;
+ for (let k in data) {
+ if (k.endsWith(".wasm")) {
+ wasm = data[k];
+ } else if (k.endsWith(".js")) {
+ js = data[k];
+ }
+ }
+ this.initGameCore(js, wasm);
+ });
+ });
+
+ }
+ initGameCore(js, wasm) {
+ this.initModule(wasm);
+ let script = this.createElement("script");
+ script.src = URL.createObjectURL(new Blob([js], {type: "application/javascript"}));
+ script.onload = this.downloadRom.bind(this);
+ document.body.appendChild(script);
+ }
+ getCore() {
+ const core = this.config.system;
+ //switch case or an object holding this data
+ if (core === 'nes') {
+ return 'fceumm';
+ }
}
downloadRom() {
this.downloadFile(this.config.gameUrl, (e) => {
this.checkCompression(e).then((data) => {
- console.log(e);
+ FS.writeFile("/game", data);
+ this.startGame();
});
- });
+ }, null, true);
+ }
+ initModule(wasmData) {
+ window.Module = {
+ 'TOTAL_MEMORY': 0x10000000,
+ 'noInitialRun': true,
+ 'arguments': [],
+ 'preRun': [],
+ 'postRun': [],
+ 'canvas': this.canvas,
+ 'print': function(msg) {
+ if (window.EJS_DEBUG_XX === true) {
+ console.log(msg);
+ }
+ },
+ 'printErr': function(msg) {
+ if (window.EJS_DEBUG_XX === true) {
+ console.log(msg);
+ }
+ },
+ 'totalDependencies': 0,
+ 'monitorRunDependencies': () => {},
+ 'locateFile': function(fileName) {
+ console.log(fileName);
+ if (fileName.endsWith(".wasm")) {
+ return URL.createObjectURL(new Blob([wasmData], {type: "application/wasm"}));
+ }
+ },
+ 'readAsync': function(_0x20d016, _0x9d2de4, _0x1425ee) {
+ console.log(_0x20d016, _0x9d2de4, _0x1425ee)
+ }
+ };
+ }
+ startGame() {
+ this.bindListeners();
+ this.textElem.remove();
+ this.textElem = null;
+ this.game.classList.remove("ejs_game");
+ this.game.appendChild(this.canvas);
+ const args = [];
+ if (window.EJS_DEBUG_XX === true) args.push('-v');
+ args.push('/game');
+ Module.callMain(args);
+ Module.resumeMainLoop();
+ Module.setCanvasSize(800, 600);
+ let i=0;
+ // this needs to be fixed. Ugh
+ let j = setInterval(function() { // some cores have a messed up screen size on load (for example - gba)
+ if (i>20) clearInterval(j);
+ i++;
+ Module.setCanvasSize(800, 600);
+ }, 100)
+ }
+ bindListeners() {
+ //keyboard, etc...
+ this.addEventListener(this.game, 'contextmenu', (e) => {
+ e.preventDefault();
+ })
}
diff --git a/src/loader.js b/src/loader.js
index 023984d..aafaede 100644
--- a/src/loader.js
+++ b/src/loader.js
@@ -40,6 +40,7 @@
const config = {};
config.gameUrl = EJS_gameUrl;
config.dataPath = scriptPath;
+ 'undefined' != typeof EJS_core && (config.system = EJS_core);
new EmulatorJS(EJS_player, config);