diff --git a/data/GameManager.js b/data/GameManager.js index 08baf98..c27632a 100644 --- a/data/GameManager.js +++ b/data/GameManager.js @@ -209,6 +209,36 @@ class EJS_GameManager { } return (fileNames.length === 1) ? baseFileName+"-0.cue" : baseFileName+".m3u"; } + loadPpssppAssets() { + return new Promise(resolve => { + this.EJS.downloadFile('cores/ppsspp-assets.zip', (res) => { + this.EJS.checkCompression(new Uint8Array(res.data), this.EJS.localization("Decompress Game Data")).then((pspassets) => { + if (pspassets === -1) { + this.EJS.textElem.innerText = this.localization('Network Error'); + this.EJS.textElem.style.color = "red"; + return; + } + this.mkdir("/PPSSPP"); + + for (const file in pspassets) { + const data = pspassets[file]; + const path = "/PPSSPP/"+file; + const paths = path.split("/"); + let cp = ""; + for (let i=0; i { this.checkCompression(new Uint8Array(data), this.localization("Decompress Game Core")).then((data) => { - let js, wasm; + let js, thread, wasm; for (let k in data) { if (k.endsWith(".wasm")) { wasm = data[k]; + } else if (k.endsWith(".worker.js")) { + thread = data[k]; } else if (k.endsWith(".js")) { js = data[k]; } } - this.initGameCore(js, wasm); + this.initGameCore(js, wasm, thread); }); } this.storage.core.get(this.getCore()+'-wasm.data').then((result) => { @@ -569,8 +571,14 @@ class EmulatorJS { }, false, {responseType: "arraybuffer", method: "GET"}); }) } - initGameCore(js, wasm) { - this.initModule(wasm); + initGameCore(js, wasm, thread) { + if (thread && ((typeof window.SharedArrayBuffer) !== "function")) { + this.textElem.innerText = this.localization('Error for site owner')+"\n"+this.localization("Check console"); + this.textElem.style.color = "red"; + console.warn("The "+this.getCore()+" core requires threads, but threads requires 2 headers to be set when sending you html page. See https://stackoverflow.com/a/68630724"); + return; + } + this.initModule(wasm, thread); let script = this.createElement("script"); script.src = URL.createObjectURL(new Blob([js], {type: "application/javascript"})); document.body.appendChild(script); @@ -786,7 +794,6 @@ class EmulatorJS { } downloadRom() { return new Promise((resolve, reject) => { - this.gameManager = new window.EJS_GameManager(this.Module, this); this.textElem.innerText = this.localization("Download Game Data"); const gotGameData = (data) => { @@ -903,6 +910,10 @@ class EmulatorJS { } downloadFiles() { (async () => { + this.gameManager = new window.EJS_GameManager(this.Module, this); + if (this.getCore() === "ppsspp") { + await this.gameManager.loadPpssppAssets(); + } await this.downloadRom(); await this.downloadBios(); await this.downloadStartState(); @@ -911,7 +922,7 @@ class EmulatorJS { this.startGame(); })(); } - initModule(wasmData) { + initModule(wasmData, threadData) { window.Module = { 'noInitialRun': true, 'onRuntimeInitialized': this.downloadFiles.bind(this), @@ -935,6 +946,8 @@ class EmulatorJS { if (this.debug) console.log(fileName); if (fileName.endsWith(".wasm")) { return URL.createObjectURL(new Blob([wasmData], {type: "application/wasm"})); + } else if (fileName.endsWith(".worker.js")) { + return URL.createObjectURL(new Blob([threadData], {type: "application/javascript"})); } } }; @@ -942,7 +955,6 @@ class EmulatorJS { } startGame() { try { - const args = []; if (this.debug) args.push('-v'); args.push('/'+this.fileName); diff --git a/data/emulator.min.js b/data/emulator.min.js index 576d4a9..2466987 100644 --- a/data/emulator.min.js +++ b/data/emulator.min.js @@ -1 +1 @@ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define("nipplejs",[],t):"object"==typeof exports?exports.nipplejs=t():e.nipplejs=t()}(window,function(){return n=[function(e,t,n){"use strict";n.r(t);function _(e,t){var n=t.x-e.x,t=t.y-e.y;return Math.sqrt(n*n+t*t)}function T(e){return e*(Math.PI/180)}function o(e){f.has(e)&&clearTimeout(f.get(e)),f.set(e,setTimeout(e,100))}function s(e,t,n){for(var i,o=t.split(/[ ,]+/g),s=0;sthis.options.threshold){var r,l={};for(r in this.direction)this.direction.hasOwnProperty(r)&&(l[r]=this.direction[r]);var c={};for(r in this.direction={x:n,y:i,angle:t},e.direction=this.direction,l)l[r]===this.direction[r]&&(c[r]=!0);if(c.x&&c.y&&c.angle)return e;c.x&&c.y||this.trigger("plain",e),c.x||this.trigger("plain:"+n,e),c.y||this.trigger("plain:"+i,e),c.angle||this.trigger("dir dir:"+t,e)}else this.resetDirection();return e};var x=w;function E(e,t){this.nipples=[],this.idles=[],this.actives=[],this.ids=[],this.pressureIntervals={},this.manager=e,this.id=E.id,E.id+=1,this.defaults={zone:document.body,multitouch:!1,maxNumberOfNipples:10,mode:"dynamic",position:{top:0,left:0},catchDistance:200,size:100,threshold:.1,color:"white",fadeTime:250,dataOnly:!1,restJoystick:!0,restOpacity:.5,lockX:!1,lockY:!1,shape:"circle",dynamicPage:!1,follow:!1},this.config(t),"static"!==this.options.mode&&"semi"!==this.options.mode||(this.options.multitouch=!1),this.options.multitouch||(this.options.maxNumberOfNipples=1);e=getComputedStyle(this.options.zone.parentElement);return e&&"flex"===e.display&&(this.parentIsFlex=!0),this.updateBox(),this.prepareNipples(),this.bindings(),this.begin(),this.nipples}E.prototype=new m,(E.constructor=E).id=0,E.prototype.prepareNipples=function(){var i=this.nipples;i.on=this.on.bind(this),i.off=this.off.bind(this),i.options=this.options,i.destroy=this.destroy.bind(this),i.ids=this.ids,i.id=this.id,i.processOnMove=this.processOnMove.bind(this),i.processOnEnd=this.processOnEnd.bind(this),i.get=function(e){if(void 0===e)return i[0];for(var t=0,n=i.length;t