Update #53 - Improved FPS, reduced WebGL context loss crashes

This commit is contained in:
lax1dude
2025-07-06 12:31:55 -07:00
parent f3281c037f
commit 332a7bb11f
53 changed files with 568 additions and 383 deletions

View File

@ -100,8 +100,13 @@ function initializeClientPlatfSP(spImports) {
});
}));
const classesTEADBGCopy = new Int8Array(classesTEADBG.length);
classesTEADBGCopy.set(classesTEADBG, 0);
const transferList = [];
var classesTEADBGCopy = null;
if(classesTEADBG) {
classesTEADBGCopy = classesTEADBG.buffer.slice(classesTEADBG.byteOffset, classesTEADBG.byteOffset + classesTEADBG.byteLength);
transferList.push(classesTEADBGCopy);
}
var eagRuntimeJS;
try {
@ -116,13 +121,15 @@ function initializeClientPlatfSP(spImports) {
return false;
}
transferList.push(eagRuntimeJS);
workerObj.postMessage({
"eaglercraftXOpts": eaglercraftXOpts,
"eagruntimeJS": eagRuntimeJS,
"classesWASM": classesWASMModule,
"classesDeobfWASM": classesDeobfWASMModule,
"classesTEADBG": classesTEADBGCopy.buffer
});
"classesTEADBG": classesTEADBGCopy
}, transferList);
return true;
};
@ -131,16 +138,16 @@ function initializeClientPlatfSP(spImports) {
/**
* @param {string} channel
* @param {Uint8Array} arr
* @param {number} addr
* @param {number} length
*/
spImports["sendPacket"] = function(channel, arr) {
spImports["sendPacket"] = function(channel, addr, length) {
if(workerObj) {
const copiedArray = new Uint8Array(arr.length);
copiedArray.set(arr, 0);
const copiedArray = heapArrayBuffer.slice(addr, addr + length);
workerObj.postMessage({
"ch": channel,
"dat": copiedArray.buffer
}, [copiedArray.buffer]);
"dat": copiedArray
}, [copiedArray]);
}
};

View File

@ -45,7 +45,7 @@ async function entryPoint() {
const teavm = await wasmGC.load(classesWASM, {
stackDeobfuscator: {
enabled: true,
enabled: !!(classesDeobfWASM && classesTEADBGURL),
path: classesDeobfWASM,
infoLocation: "external",
externalInfoPath: classesTEADBGURL

View File

@ -106,6 +106,8 @@ var keepAliveCallback = null;
var showDebugConsole = null;
/** @type {function()|null} */
var resetSettings = null;
/** @type {function()|null} */
var handleVisibilityChange = null;
const runtimeOpts = {
localStorageNamespace: "_eaglercraftX",

View File

@ -16,6 +16,9 @@
const platfAudioName = "platformAudio";
/** @type {HTMLAudioElement|null} */
var silenceElement = null;
function setCurrentAudioContext(audioContext, audioImports) {
/**
@ -26,25 +29,41 @@ function setCurrentAudioContext(audioContext, audioImports) {
};
/**
* @param {Uint8Array} fileData
* @param {number} addr
* @param {number} length
*/
audioImports["initKeepAliveHack"] = function(fileData) {
const copiedData = new Uint8Array(fileData.length);
copiedData.set(fileData, 0);
audioImports["initKeepAliveHack"] = function(addr, length) {
const copiedData = heapArrayBuffer.slice(addr, addr + length);
const copiedDataURI = URL.createObjectURL(new Blob([copiedData], {type: "audio/wav"}));
const audioElement = /** @type {HTMLAudioElement} */ (document.createElement("audio"));
audioElement.classList.add("_eaglercraftX_keepalive_hack");
audioElement.setAttribute("style", "display:none;");
audioElement.autoplay = true;
audioElement.autoplay = false;
audioElement.loop = true;
audioElement.addEventListener("seeked", function() {
// NOP, wakes up the browser's event loop
});
audioElement.addEventListener("canplay", function() {
if (silenceElement && document.visibilityState === "hidden") {
silenceElement.play();
}
});
const sourceElement = /** @type {HTMLSourceElement} */ (document.createElement("source"));
sourceElement.type = "audio/wav";
sourceElement.src = copiedDataURI;
audioElement.appendChild(sourceElement);
audioElement.addEventListener("seeked", function() {
// NOP, wakes up the browser's event loop
});
parentElement.appendChild(audioElement);
silenceElement = audioElement;
};
handleVisibilityChange = function() {
if (silenceElement) {
if (document.visibilityState === "hidden") {
silenceElement.play();
} else {
silenceElement.pause();
}
}
};
/**

View File

@ -144,13 +144,24 @@ function eaglerReadImpl(database, pathName) {
eagruntimeImpl.platformFilesystem["eaglerRead"] = new WebAssembly.Suspending(eaglerReadImpl);
/**
* @param {IDBDatabase} database
* @param {string} pathName
* @param {number} addr
* @param {number} length
* @return {Promise}
*/
function eaglerWriteImpl(database, pathName, addr, length) {
return eaglerWriteImpl0(database, pathName, heapArrayBuffer.slice(addr, addr + length));
}
/**
* @param {IDBDatabase} database
* @param {string} pathName
* @param {ArrayBuffer} arr
* @return {Promise}
*/
function eaglerWriteImpl(database, pathName, arr) {
function eaglerWriteImpl0(database, pathName, arr) {
return new Promise(function(resolve) {
const tx = database.transaction("filesystem", "readwrite");
const r = tx.objectStore("filesystem").put(writeDBRow(pathName, arr));
@ -193,7 +204,7 @@ eagruntimeImpl.platformFilesystem["eaglerExists"] = new WebAssembly.Suspending(e
*/
async function eaglerMoveImpl(database, pathNameOld, pathNameNew) {
const oldData = await eaglerReadImpl(database, pathNameOld);
if(!oldData || !(await eaglerWriteImpl(database, pathNameNew, oldData))) {
if(!oldData || !(await eaglerWriteImpl0(database, pathNameNew, oldData))) {
return false;
}
return await eaglerDeleteImpl(database, pathNameOld);
@ -209,7 +220,7 @@ eagruntimeImpl.platformFilesystem["eaglerMove"] = new WebAssembly.Suspending(eag
*/
async function eaglerCopyImpl(database, pathNameOld, pathNameNew) {
const oldData = await eaglerReadImpl(database, pathNameOld);
return oldData && (await eaglerWriteImpl(database, pathNameNew, oldData));
return oldData && (await eaglerWriteImpl0(database, pathNameNew, oldData));
}
eagruntimeImpl.platformFilesystem["eaglerCopy"] = new WebAssembly.Suspending(eaglerCopyImpl);

View File

@ -118,7 +118,8 @@ async function initPlatformInput(inputImports) {
blur: null,
pointerlock: null,
pointerlockerr: null,
fullscreenChange: null
fullscreenChange: null,
visibilitychange: null
};
touchKeyboardOpenZone = document.createElement("div");
@ -351,6 +352,11 @@ async function initPlatformInput(inputImports) {
pushEvent(EVENT_TYPE_INPUT, EVENT_INPUT_FOCUS, null);
});
document.addEventListener("visibilitychange", currentEventListeners.visibilitychange = function(/** Event */ evt) {
if (handleVisibilityChange)
handleVisibilityChange();
});
/**
* @param {number} evtType
* @param {KeyboardEvent} evt
@ -1138,6 +1144,10 @@ async function initPlatformInput(inputImports) {
window.removeEventListener("blur", /** @type {function(Event)} */ (currentEventListeners.blur));
currentEventListeners.blur = null;
}
if(currentEventListeners.visibilitychange) {
document.removeEventListener("visibilitychange", currentEventListeners.visibilitychange);
currentEventListeners.visibilitychange = null;
}
if(currentEventListeners.pointerlock) {
document.removeEventListener("pointerlockchange", /** @type {function(Event)} */ (currentEventListeners.pointerlock));
currentEventListeners.pointerlock = null;

View File

@ -99,7 +99,7 @@ function setCurrentGLContext(ctx, glesVersIn, allowExts, glImports) {
glImports["glColorMask"] = ctx.colorMask.bind(ctx);
glImports["glDrawBuffers"] = glesVersIn >= 300 ? ctx.drawBuffers.bind(ctx) : unsupportedFunc(platfOpenGLName, "glDrawBuffers");
glImports["glReadBuffer"] = glesVersIn >= 300 ? ctx.readBuffer.bind(ctx) : unsupportedFunc(platfOpenGLName, "glReadBuffer");
glImports["glReadPixels"] = glImports["glReadPixels0"] = ctx.readPixels.bind(ctx);
glImports["glReadPixels"] = ctx.readPixels.bind(ctx);
glImports["glPolygonOffset"] = ctx.polygonOffset.bind(ctx);
glImports["glLineWidth"] = ctx.lineWidth.bind(ctx);
glImports["glGenBuffers"] = ctx.createBuffer.bind(ctx);
@ -117,8 +117,8 @@ function setCurrentGLContext(ctx, glesVersIn, allowExts, glImports) {
glImports["glDeleteRenderbuffer"] = ctx.deleteRenderbuffer.bind(ctx);
glImports["glDeleteQueries"] = glesVersIn >= 300 ? ctx.deleteQuery.bind(ctx) : unsupportedFunc(platfOpenGLName, "glDeleteQueries");
glImports["glBindBuffer"] = ctx.bindBuffer.bind(ctx);
glImports["glBufferData"] = glImports["glBufferData0"] = ctx.bufferData.bind(ctx);
glImports["glBufferSubData"] = glImports["glBufferSubData0"] = ctx.bufferSubData.bind(ctx);
glImports["glBufferData"] = ctx.bufferData.bind(ctx);
glImports["glBufferSubData"] = ctx.bufferSubData.bind(ctx);
glImports["glEnableVertexAttribArray"] = ctx.enableVertexAttribArray.bind(ctx);
glImports["glDisableVertexAttribArray"] = ctx.disableVertexAttribArray.bind(ctx);
glImports["glVertexAttribPointer"] = ctx.vertexAttribPointer.bind(ctx);
@ -126,9 +126,9 @@ function setCurrentGLContext(ctx, glesVersIn, allowExts, glImports) {
glImports["glBindTexture"] = ctx.bindTexture.bind(ctx);
glImports["glTexParameterf"] = ctx.texParameterf.bind(ctx);
glImports["glTexParameteri"] = ctx.texParameteri.bind(ctx);
glImports["glTexImage3D"] = glImports["glTexImage3D0"] = glesVersIn >= 300 ? ctx.texImage3D.bind(ctx) : unsupportedFunc(platfOpenGLName, "glTexImage3D");
glImports["glTexImage2D"] = glImports["glTexImage2D0"] = ctx.texImage2D.bind(ctx);
glImports["glTexSubImage2D"] = glImports["glTexSubImage2D0"] = ctx.texSubImage2D.bind(ctx);
glImports["glTexImage3D"] = glesVersIn >= 300 ? ctx.texImage3D.bind(ctx) : unsupportedFunc(platfOpenGLName, "glTexImage3D");
glImports["glTexImage2D"] = ctx.texImage2D.bind(ctx);
glImports["glTexSubImage2D"] = ctx.texSubImage2D.bind(ctx);
glImports["glCopyTexSubImage2D"] = ctx.copyTexSubImage2D.bind(ctx);
glImports["glTexStorage2D"] = glesVersIn >= 300 ? ctx.texStorage2D.bind(ctx) : unsupportedFunc(platfOpenGLName, "glTexStorage2D");
glImports["glPixelStorei"] = ctx.pixelStorei.bind(ctx);
@ -145,6 +145,7 @@ function setCurrentGLContext(ctx, glesVersIn, allowExts, glImports) {
glImports["glGetProgramInfoLog"] = ctx.getProgramInfoLog.bind(ctx);
glImports["glDrawArrays"] = ctx.drawArrays.bind(ctx);
glImports["glDrawElements"] = ctx.drawElements.bind(ctx);
glImports["glDrawRangeElements"] = glesVersIn >= 300 ? ctx.drawRangeElements.bind(ctx) : unsupportedFunc(platfOpenGLName, "glDrawRangeElements");
glImports["glBindAttribLocation"] = ctx.bindAttribLocation.bind(ctx);
glImports["glGetAttribLocation"] = ctx.getAttribLocation.bind(ctx);
glImports["glGetUniformLocation"] = ctx.getUniformLocation.bind(ctx);
@ -299,7 +300,6 @@ function setNoGLContext(glImports) {
setUnsupportedFunc(glImports, platfOpenGLName, "glDrawBuffers");
setUnsupportedFunc(glImports, platfOpenGLName, "glReadBuffer");
setUnsupportedFunc(glImports, platfOpenGLName, "glReadPixels");
setUnsupportedFunc(glImports, platfOpenGLName, "glReadPixels0");
setUnsupportedFunc(glImports, platfOpenGLName, "glPolygonOffset");
setUnsupportedFunc(glImports, platfOpenGLName, "glLineWidth");
setUnsupportedFunc(glImports, platfOpenGLName, "glGenBuffers");
@ -318,9 +318,7 @@ function setNoGLContext(glImports) {
setUnsupportedFunc(glImports, platfOpenGLName, "glDeleteQueries");
setUnsupportedFunc(glImports, platfOpenGLName, "glBindBuffer");
setUnsupportedFunc(glImports, platfOpenGLName, "glBufferData");
setUnsupportedFunc(glImports, platfOpenGLName, "glBufferData0");
setUnsupportedFunc(glImports, platfOpenGLName, "glBufferSubData");
setUnsupportedFunc(glImports, platfOpenGLName, "glBufferSubData0");
setUnsupportedFunc(glImports, platfOpenGLName, "glEnableVertexAttribArray");
setUnsupportedFunc(glImports, platfOpenGLName, "glDisableVertexAttribArray");
setUnsupportedFunc(glImports, platfOpenGLName, "glVertexAttribPointer");
@ -329,11 +327,8 @@ function setNoGLContext(glImports) {
setUnsupportedFunc(glImports, platfOpenGLName, "glTexParameterf");
setUnsupportedFunc(glImports, platfOpenGLName, "glTexParameteri");
setUnsupportedFunc(glImports, platfOpenGLName, "glTexImage3D");
setUnsupportedFunc(glImports, platfOpenGLName, "glTexImage3D0");
setUnsupportedFunc(glImports, platfOpenGLName, "glTexImage2D");
setUnsupportedFunc(glImports, platfOpenGLName, "glTexImage2D0");
setUnsupportedFunc(glImports, platfOpenGLName, "glTexSubImage2D");
setUnsupportedFunc(glImports, platfOpenGLName, "glTexSubImage2D0");
setUnsupportedFunc(glImports, platfOpenGLName, "glCopyTexSubImage2D");
setUnsupportedFunc(glImports, platfOpenGLName, "glTexStorage2D");
setUnsupportedFunc(glImports, platfOpenGLName, "glPixelStorei");
@ -350,6 +345,7 @@ function setNoGLContext(glImports) {
setUnsupportedFunc(glImports, platfOpenGLName, "glGetProgramInfoLog");
setUnsupportedFunc(glImports, platfOpenGLName, "glDrawArrays");
setUnsupportedFunc(glImports, platfOpenGLName, "glDrawElements");
setUnsupportedFunc(glImports, platfOpenGLName, "glDrawRangeElements");
setUnsupportedFunc(glImports, platfOpenGLName, "glBindAttribLocation");
setUnsupportedFunc(glImports, platfOpenGLName, "glGetAttribLocation");
setUnsupportedFunc(glImports, platfOpenGLName, "glGetUniformLocation");

View File

@ -121,19 +121,18 @@ function initializePlatfWebView(webViewImports) {
/**
* @param {string} ch
* @param {Uint8Array} bin
* @param {number} addr
* @param {number} length
*/
webViewImports["sendBinaryMessage"] = function(ch, bin) {
webViewImports["sendBinaryMessage"] = function(ch, addr, length) {
try {
var w;
if(currentIFrame != null && (w = currentIFrame.contentWindow) != null) {
const copiedArray = new Uint8Array(bin.length);
copiedArray.set(bin, 0);
w.postMessage({
"ver": 1,
"channel": ch,
"type": "binary",
"data": copiedArray.buffer
"data": heapArrayBuffer.slice(addr, addr + length)
}, "*");
}else {
eagError("Server tried to send the WebView a message, but the message channel is not open!");

View File

@ -57,15 +57,15 @@ function initializeServerPlatfSP(spImports) {
/**
* @param {string} channel
* @param {Uint8Array} arr
* @param {number} addr
* @param {number} length
*/
spImports["sendPacket"] = function(channel, arr) {
const copiedArray = new Uint8Array(arr.length);
copiedArray.set(arr, 0);
spImports["sendPacket"] = function(channel, addr, length) {
const copiedArray = heapArrayBuffer.slice(addr, addr + length);
postMessage({
"ch": channel,
"dat": copiedArray.buffer
}, [copiedArray.buffer]);
"dat": copiedArray
}, [copiedArray]);
};
spImports["getAvailablePackets"] = serverMessageQueue.getLength.bind(serverMessageQueue);