Update #51 - Protocol and FPS improvements, better workspace

This commit is contained in:
lax1dude
2025-05-18 15:01:06 -07:00
parent 71c61e33fd
commit 325a6826bf
1191 changed files with 9266 additions and 187695 deletions

View File

@ -78,3 +78,11 @@ eagruntimeImpl.WASMGCBufferAllocator["getIntBufferView"] = function(addr, length
eagruntimeImpl.WASMGCBufferAllocator["getFloatBufferView"] = function(addr, length) {
return new Float32Array(heapArrayBuffer, addr, length);
}
/**
* @param {function(Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array)} cb
*/
eagruntimeImpl.WASMGCBufferAllocator["setHeapViewCallback"] = function(cb) {
heapResizeHandler = cb;
callHeapViewCallback();
}

View File

@ -86,6 +86,8 @@ var heapI32Array = null;
var heapU32Array = null;
/** @type {Float32Array} */
var heapF32Array = null;
/** @type {function(Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array)|null} */
var heapResizeHandler = null;
/** @type {boolean} */
var isLikelyMobileBrowser = false;
/** @type {function(string, !ArrayBuffer)|null} */
@ -460,6 +462,13 @@ function handleMemoryResized(mem) {
heapU32Array = new Uint32Array(heapArrayBuffer);
heapI32Array = new Int32Array(heapArrayBuffer);
heapF32Array = new Float32Array(heapArrayBuffer);
callHeapViewCallback();
}
function callHeapViewCallback() {
if (heapResizeHandler) {
heapResizeHandler(heapI8Array, heapU8Array, heapI16Array, heapU16Array, heapI32Array, heapU32Array, heapF32Array);
}
}
const EVENT_TYPE_INPUT = 0;
@ -753,6 +762,44 @@ function showIncompatibleScreen(msg) {
}
}
/**
* @param {string} msg
*/
function showContextLostScreen(msg) {
if(!isCrashed) {
isCrashed = true;
var parentEl = parentElement || rootElement;
if(!parentEl) {
alert("WebGL context lost!");
eagError("WebGL context lost!");
return;
}
const img = document.createElement("img");
const div = document.createElement("div");
img.setAttribute("style", "z-index:100;position:absolute;top:10px;left:calc(50% - 151px);");
img.src = crashURL;
div.setAttribute("style", "z-index:100;position:absolute;top:135px;left:10%;right:10%;bottom:50px;background-color:white;border:1px solid #cccccc;overflow-x:hidden;overflow-y:scroll;font:18px sans-serif;padding:40px;");
div.classList.add("_eaglercraftX_context_lost_element");
parentEl.appendChild(img);
parentEl.appendChild(div);
div.innerHTML = "<h2><svg style=\"vertical-align:middle;margin:0px 16px 8px 8px;\" xmlns=\"http://www.w3.org/2000/svg\" width=\"48\" height=\"48\" viewBox=\"0 0 48 48\" fill=\"none\"><path stroke=\"#000000\" stroke-width=\"3\" stroke-linecap=\"square\" d=\"M1.5 8.5v34h45v-28m-3-3h-10v-3m-3-3h-10m15 6h-18v-3m-3-3h-10\"/><path stroke=\"#000000\" stroke-width=\"2\" stroke-linecap=\"square\" d=\"M12 21h0m0 4h0m4 0h0m0-4h0m-2 2h0m20-2h0m0 4h0m4 0h0m0-4h0m-2 2h0\"/><path stroke=\"#000000\" stroke-width=\"2\" stroke-linecap=\"square\" d=\"M20 30h0 m2 2h0 m2 2h0 m2 2h0 m2 -2h0 m2 -2h0 m2 -2h0\"/></svg> + WebGL context lost!</h2>"
+ "<div style=\"margin-left:40px;\">"
+ "<p style=\"font-size:1.2em;\">Your browser has forcibly released all of the resources "
+ "allocated by the game's 3D rendering context. EaglercraftX cannot continue, please refresh "
+ "the page to restart the game.</p>"
+ "<p style=\"font-size:1.2em;\">This is not a bug, it is usually caused by the browser "
+ "deciding it no longer has sufficient resources to continue rendering this page. If it "
+ "happens again, try closing your other browser tabs and windows.</p>"
+ "<p style=\"overflow-wrap:break-word;white-space:pre-wrap;font:0.75em monospace;margin-top:1.5em;\" id=\"_eaglercraftX_contextLostTrace\"></p>"
+ "</div>";
div.querySelector("#_eaglercraftX_contextLostTrace").appendChild(document.createTextNode(msg));
}
}
/** @type {string|null} */
var webGLCrashStringCache = 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"] = ctx.readPixels.bind(ctx);
glImports["glReadPixels"] = glImports["glReadPixels0"] = 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"] = ctx.bufferData.bind(ctx);
glImports["glBufferSubData"] = ctx.bufferSubData.bind(ctx);
glImports["glBufferData"] = glImports["glBufferData0"] = ctx.bufferData.bind(ctx);
glImports["glBufferSubData"] = glImports["glBufferSubData0"] = 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"] = glesVersIn >= 300 ? ctx.texImage3D.bind(ctx) : unsupportedFunc(platfOpenGLName, "glTexImage3D");
glImports["glTexImage2D"] = ctx.texImage2D.bind(ctx);
glImports["glTexSubImage2D"] = ctx.texSubImage2D.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["glCopyTexSubImage2D"] = ctx.copyTexSubImage2D.bind(ctx);
glImports["glTexStorage2D"] = glesVersIn >= 300 ? ctx.texStorage2D.bind(ctx) : unsupportedFunc(platfOpenGLName, "glTexStorage2D");
glImports["glPixelStorei"] = ctx.pixelStorei.bind(ctx);
@ -299,6 +299,7 @@ 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");
@ -317,7 +318,9 @@ 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");
@ -326,8 +329,11 @@ 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");

View File

@ -156,6 +156,13 @@ eagruntimeImpl.platformRuntime["writeCrashReport"] = function(crashDump) {
displayCrashReport(crashDump, false);
};
/**
* @param {string} crashDump
*/
eagruntimeImpl.platformRuntime["showContextLostScreen"] = function(crashDump) {
showContextLostScreen(crashDump);
};
eagruntimeImpl.platformRuntime["steadyTimeMillis"] = performance.now.bind(performance);
/**

View File

@ -42,11 +42,13 @@ let setGlobalName = function(name, value) {
/**
* @param {Object} imports
* @param {Object} userExports
*/
function defaults(imports) {
function defaults(imports, userExports) {
let context = {
/** @type {Object} */
exports: null,
userExports: userExports,
/** @type {function(number)|null} */
stackDeobfuscator: null,
/** @type {function(function())|null} */
@ -90,6 +92,21 @@ class JavaError extends Error {
}
}
/**
* @param {Object} imports
*/
function stringImports(imports) {
imports["wasm:js-string"] = {
"fromCharCode": code => String.fromCharCode(code),
"fromCharCodeArray": () => { throw new Error("Not supported"); },
"intoCharCodeArray": () => { throw new Error("Not supported"); },
"concat": (first, second) => first + second,
"charCodeAt": (string, index) => string.charCodeAt(index),
"length": s => s.length,
"substring": (s, start, end) => s.substring(start, end)
};
}
/**
* @param {Object} imports
*/
@ -182,7 +199,10 @@ function coreImports(imports, context) {
}
return new WeakRef(value);
},
"deref": weakRef => weakRef.deref(),
"deref": weakRef => {
let result = weakRef.deref();
return result !== void 0 ? result : null;
},
"createStringWeakRef": (value, heldValue) => {
stringFinalizationRegistry.register(value, heldValue)
return new WeakRef(value);
@ -224,7 +244,11 @@ function coreImports(imports, context) {
},
"decorateException": (javaException) => {
new JavaError(context, javaException);
}
},
"linearMemory": () => {
return context.exports["teavm.memory"].buffer;
},
"notifyHeapResized": () => {}
};
}
@ -349,11 +373,8 @@ function jsoImports(imports, context) {
)(c);
}
imports["teavmJso"] = {
"emptyString": () => "",
"stringFromCharCode": code => String.fromCharCode(code),
"concatStrings": (a, b) => a + b,
"stringLength": s => s.length,
"charAt": (s, index) => s.charCodeAt(index),
"stringBuiltinsSupported": () => hasStringBuiltins(),
"isUndefined": o => typeof o === "undefined",
"emptyArray": () => [],
"appendToArray": (array, e) => array.push(e),
"unwrapBoolean": value => value ? 1 : 0,
@ -591,11 +612,16 @@ function jsoImports(imports, context) {
rethrowJsAsJava(e);
}
},
"concatArray": (a, b) => a.concat(b),
"getJavaException": e => e[javaExceptionSymbol]
"concatArray": (a, b) => [...a, ...b],
"getJavaException": e => e[javaExceptionSymbol],
"getJSException": e => {
let getJsException = context.exports["teavm.getJsException"];
return getJsException(e);
},
"jsExports": () => context.userExports
};
for (let name of ["wrapByte", "wrapShort", "wrapChar", "wrapInt", "wrapFloat", "wrapDouble", "unwrapByte",
"unwrapShort", "unwrapChar", "unwrapInt", "unwrapFloat", "unwrapDouble"]) {
for (let name of ["wrapByte", "wrapShort", "wrapChar", "wrapInt", "wrapLong", "wrapFloat", "wrapDouble",
"unwrapByte", "unwrapShort", "unwrapChar", "unwrapInt", "unwrapLong", "unwrapFloat", "unwrapDouble"]) {
imports["teavmJso"][name] = identity;
}
function wrapCallFromJavaToJs(call) {
@ -705,14 +731,17 @@ async function load(path, options) {
}
let deobfuscatorOptions = options.stackDeobfuscator || {};
/** @suppress {checkTypes} */
let [deobfuscatorFactory, module, debugInfo] = await Promise.all([
deobfuscatorOptions.enabled ? getDeobfuscator(deobfuscatorOptions) : Promise.resolve(null),
(path instanceof WebAssembly.Module) ? Promise.resolve(path) : WebAssembly.compileStreaming(fetch(path)),
(path instanceof WebAssembly.Module) ? Promise.resolve(path) : WebAssembly.compileStreaming(fetch(path), { "builtins": ["js-string"] }),
fetchExternalDebugInfo(deobfuscatorOptions.infoLocation, deobfuscatorOptions)
]);
const importObj = {};
const defaultsResult = defaults(importObj);
let userExports = {};
const defaultsResult = defaults(importObj, userExports);
if (typeof options.installImports !== "undefined") {
options.installImports(importObj);
}
@ -724,7 +753,6 @@ async function load(path, options) {
let instance = /** @type {!WebAssembly.Instance} */ (await WebAssembly.instantiate(module, importObj));
let userExports = {};
defaultsResult.supplyExports(instance.exports);
if (deobfuscatorFactory) {
@ -758,6 +786,25 @@ async function load(path, options) {
return teavm;
}
let stringBuiltinsCache = null;
function hasStringBuiltins() {
if (stringBuiltinsCache === null) {
/*
(module
(type (func))
(import "wasm:js-string" "cast" (func (type 0)))
)
*/
let bytes = new Int8Array([0, 97, 115, 109, 1, 0, 0, 0, 1, 4, 1, 96, 0, 0, 2, 23, 1, 14, 119, 97,
115, 109, 58, 106, 115, 45, 115, 116, 114, 105, 110, 103, 4, 99, 97, 115, 116, 0, 0, 3, 1, 0,
5, 4, 1, 1, 0, 0, 10, -127, -128, -128, 0, 0]);
/** @suppress {checkTypes} */
stringBuiltinsCache = !WebAssembly.validate(bytes, { "builtins": ["js-string"]});
}
return stringBuiltinsCache;
}
/**
* @param {Object} options
* @return {!Promise<?{module:!WebAssembly.Module,instance:!WebAssembly.Instance}>}
@ -765,9 +812,10 @@ async function load(path, options) {
async function getDeobfuscator(options) {
try {
const importObj = {};
const defaultsResult = defaults(importObj);
const defaultsResult = defaults(importObj, {});
/** @suppress {checkTypes} */
const module = (options.path instanceof WebAssembly.Module) ?
options.path : await WebAssembly.compileStreaming(fetch(options.path));
options.path : await WebAssembly.compileStreaming(fetch(options.path), { "builtins": ["js-string"] });
const instance = new WebAssembly.Instance(module, importObj);
defaultsResult.supplyExports(instance.exports)
return { module, instance };
@ -796,7 +844,7 @@ function createDeobfuscator(module, externalData, deobfuscatorFactory) {
console.warn("Could not load create deobfuscator", e);
}
}
if (deobfuscator == null && module !== null) {
if (deobfuscator === null && module !== null) {
try {
deobfuscator = deobfuscatorFactory.exports["createForModule"].value(module);
} catch (e) {