210 lines
7.0 KiB
JavaScript
210 lines
7.0 KiB
JavaScript
/*
|
|
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
*/
|
|
|
|
const clientPlatfSPName = "clientPlatformSingleplayer";
|
|
|
|
function initializeClientPlatfSP(spImports) {
|
|
|
|
/** @type {Worker|null} */
|
|
var workerObj = null;
|
|
|
|
const clientMessageQueue = new EaglerLinkedQueue();
|
|
|
|
const workerBootstrapSource = "\"use strict\"; (function(ctx, globals) {" +
|
|
"globals.__eaglerXOnMessage = function(o) {" +
|
|
"globals.__eaglerXOnMessage = function(oo) { console.error(\"Dropped IPC packet that was sent too early!\"); };" +
|
|
"const eagRuntimeJSURL = URL.createObjectURL(new Blob([ o.eagruntimeJS ], { type: \"text/javascript;charset=utf-8\" }));" +
|
|
"ctx.getEaglercraftXOpts = function() { return o.eaglercraftXOpts; };" +
|
|
"ctx.getEagRuntimeJSURL = function() { return eagRuntimeJSURL; };" +
|
|
"ctx.getClassesWASMURL = function() { return o.classesWASM; };" +
|
|
"ctx.getClassesDeobfWASMURL = function() { return o.classesDeobfWASM; };" +
|
|
"ctx.getClassesTEADBGURL = function() { return o.classesTEADBG; };" +
|
|
"ctx.getEPKFiles = function() { return null; };" +
|
|
"ctx.getRootElement = function() { return null; };" +
|
|
"ctx.getMainArgs = function() { return [\"_worker_process_\"]; };" +
|
|
"ctx.getImageURL = function(idx) { return null; };" +
|
|
"ctx.runMain = function(mainFunc) { mainFunc(); };" +
|
|
"importScripts(eagRuntimeJSURL);" +
|
|
"};" +
|
|
"addEventListener(\"message\", function(evt) { globals.__eaglerXOnMessage(evt.data); });" +
|
|
"})(self.__eaglercraftXLoaderContext = {}, self);";
|
|
|
|
/** @type {string|null} */
|
|
var workerURL = null;
|
|
|
|
/**
|
|
* @return {Promise<boolean>}
|
|
*/
|
|
async function startIntegratedServerImpl() {
|
|
if(!workerURL) {
|
|
workerURL = URL.createObjectURL(new Blob([ workerBootstrapSource ], { "type": "text/javascript;charset=utf8" }));
|
|
}
|
|
|
|
try {
|
|
workerObj = new Worker(workerURL);
|
|
}catch(ex) {
|
|
eagStackTrace(ERROR, "Failed to create worker", ex);
|
|
return false;
|
|
}
|
|
|
|
workerObj.addEventListener("error", /** @type {function(Event)} */ (function(/** ErrorEvent */ evt) {
|
|
eagStackTrace(ERROR, "Worker Error", /** @type {Error} */ (evt.error));
|
|
}));
|
|
|
|
workerObj.addEventListener("message", /** @type {function(Event)} */ (function(/** MessageEvent */ evt) {
|
|
const channel = evt.data["ch"];
|
|
|
|
if(!channel) {
|
|
eagError("Recieved IPC packet with null channel");
|
|
return;
|
|
}
|
|
|
|
if(channel === "~!LOGGER") {
|
|
addLogMessageImpl(evt.data["txt"], evt.data["err"]);
|
|
return;
|
|
}
|
|
|
|
const buf = evt.data["dat"];
|
|
|
|
if(!buf) {
|
|
eagError("Recieved IPC packet with null buffer");
|
|
return;
|
|
}
|
|
|
|
if(serverLANPeerPassIPCFunc(channel, buf)) {
|
|
return;
|
|
}
|
|
|
|
clientMessageQueue.push({
|
|
"ch": channel,
|
|
"data": new Uint8Array(buf),
|
|
"_next": null
|
|
});
|
|
}));
|
|
|
|
const classesTEADBGCopy = new Int8Array(classesTEADBG.length);
|
|
classesTEADBGCopy.set(classesTEADBG, 0);
|
|
|
|
var eagRuntimeJS;
|
|
try {
|
|
eagRuntimeJS = await fetch(/** @type {string} */ (eagRuntimeJSURL), { "cache": "force-cache" })
|
|
.then((resp) => resp.arrayBuffer());
|
|
}catch(ex) {
|
|
eagStackTrace(ERROR, "Failed to fetch eagruntime.js contents", ex);
|
|
try {
|
|
workerObj.terminate();
|
|
}catch(exx) {
|
|
}
|
|
return false;
|
|
}
|
|
|
|
workerObj.postMessage({
|
|
"eaglercraftXOpts": eaglercraftXOpts,
|
|
"eagruntimeJS": eagRuntimeJS,
|
|
"classesWASM": classesWASMModule,
|
|
"classesDeobfWASM": classesDeobfWASMModule,
|
|
"classesTEADBG": classesTEADBGCopy.buffer
|
|
});
|
|
|
|
return true;
|
|
};
|
|
|
|
spImports["startIntegratedServer"] = new WebAssembly.Suspending(startIntegratedServerImpl);
|
|
|
|
/**
|
|
* @param {string} channel
|
|
* @param {Uint8Array} arr
|
|
*/
|
|
spImports["sendPacket"] = function(channel, arr) {
|
|
if(workerObj) {
|
|
const copiedArray = new Uint8Array(arr.length);
|
|
copiedArray.set(arr, 0);
|
|
workerObj.postMessage({
|
|
"ch": channel,
|
|
"dat": copiedArray.buffer
|
|
});
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @param {string} channel
|
|
* @param {!ArrayBuffer} arr
|
|
*/
|
|
sendIPCPacketFunc = function(channel, arr) {
|
|
if(workerObj) {
|
|
workerObj.postMessage({
|
|
"ch": channel,
|
|
"dat": arr
|
|
});
|
|
}
|
|
};
|
|
|
|
spImports["getAvailablePackets"] = clientMessageQueue.getLength.bind(clientMessageQueue);
|
|
|
|
spImports["getNextPacket"] = clientMessageQueue.shift.bind(clientMessageQueue);
|
|
|
|
spImports["killWorker"] = function() {
|
|
if(workerObj) {
|
|
workerObj.terminate();
|
|
workerObj = null;
|
|
}
|
|
};
|
|
|
|
/** @type {HTMLElement} */
|
|
var integratedServerCrashPanel = null;
|
|
|
|
/**
|
|
* @param {string} report
|
|
* @param {number} x
|
|
* @param {number} y
|
|
* @param {number} w
|
|
* @param {number} h
|
|
*/
|
|
spImports["showCrashReportOverlay"] = function(report, x, y, w, h) {
|
|
if(!integratedServerCrashPanel) {
|
|
integratedServerCrashPanel = /** @type {HTMLElement} */ (document.createElement("div"));
|
|
integratedServerCrashPanel.setAttribute("style", "z-index:99;position:absolute;background-color:black;color:white;overflow-x:hidden;overflow-y:scroll;overflow-wrap:break-word;white-space:pre-wrap;font:18px sans-serif;padding:20px;display:none;");
|
|
integratedServerCrashPanel.classList.add("_eaglercraftX_integratedserver_crash_element");
|
|
parentElement.appendChild(integratedServerCrashPanel);
|
|
}
|
|
integratedServerCrashPanel.innerText = "";
|
|
integratedServerCrashPanel.innerText = "CURRENT DATE: " + (new Date()).toLocaleString() + "\n\n" + report;
|
|
const s = window.devicePixelRatio;
|
|
integratedServerCrashPanel.style.top = "" + (y / s) + "px";
|
|
integratedServerCrashPanel.style.left = "" + (x / s) + "px";
|
|
integratedServerCrashPanel.style.width = "" + ((w / s) - 20) + "px";
|
|
integratedServerCrashPanel.style.height = "" + ((h / s) - 20) + "px";
|
|
integratedServerCrashPanel.style.display = "block";
|
|
};
|
|
|
|
spImports["hideCrashReportOverlay"] = function() {
|
|
if(integratedServerCrashPanel) {
|
|
integratedServerCrashPanel.style.display = "none";
|
|
}
|
|
};
|
|
|
|
}
|
|
|
|
function initializeNoClientPlatfSP(spImports) {
|
|
setUnsupportedFunc(spImports, clientPlatfSPName, "startIntegratedServer");
|
|
setUnsupportedFunc(spImports, clientPlatfSPName, "sendPacket");
|
|
setUnsupportedFunc(spImports, clientPlatfSPName, "getAvailablePackets");
|
|
setUnsupportedFunc(spImports, clientPlatfSPName, "getNextPacket");
|
|
setUnsupportedFunc(spImports, clientPlatfSPName, "killWorker");
|
|
setUnsupportedFunc(spImports, clientPlatfSPName, "showCrashReportOverlay");
|
|
setUnsupportedFunc(spImports, clientPlatfSPName, "hideCrashReportOverlay");
|
|
}
|