From dbba6ca4b9f0270555fc94091e6207f0ea6cd6b8 Mon Sep 17 00:00:00 2001 From: ZXMushroom63 Date: Wed, 4 Dec 2024 14:29:07 +0800 Subject: [PATCH 01/20] new readme --- README.md | 7 ++++++- injector.minify.js | 5 +++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 95aaf4e..9a2cb36 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,10 @@ # EaglerForgeInjector -A modding API injector for vanilla eaglercraft builds. +An advanced modding API injector for vanilla eaglercraft builds. +Current features: +- Method hooking/monkey patching +- Reflection +- Custom classes +- Modify the dedicated server ### How to use: #### Online diff --git a/injector.minify.js b/injector.minify.js index 8dc955c..d0a7668 100644 --- a/injector.minify.js +++ b/injector.minify.js @@ -36,18 +36,19 @@ async function shronk(input) { const parser = new DOMParser(); const doc = parser.parseFromString(inputHtml, 'text/html'); const scriptTags = doc.querySelectorAll('script'); - + await wait(100); //trying to get chrome to gc for (let i = 0; i < scriptTags.length; i++) { const scriptTag = scriptTags[i]; const code = scriptTag.textContent; _status("[ASYNC_PLUGIN_1] Transpiling script #" + (i + 1) + " of length " + Math.round(code.length / 1000) + "k..."); - await wait(50); + await wait(150); const output = Babel.transform(code, { plugins: [] }); scriptTag.textContent = output.code; + await wait(10); } _status("[ASYNC_PLUGIN_1] Job complete!"); From 01fa9fee08f97f3c66dccdeb177a08a8cd3eb76b Mon Sep 17 00:00:00 2001 From: ZXMushroom63 Date: Thu, 5 Dec 2024 13:18:57 +0800 Subject: [PATCH 02/20] add efi version to title --- injector.js | 1 + postinit.js | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/injector.js b/injector.js index 919ae40..2a9c590 100644 --- a/injector.js +++ b/injector.js @@ -317,6 +317,7 @@ var main;(function(){` \ - + diff --git a/modgui.js b/modgui.js index 5ef4d75..3eb1d96 100644 --- a/modgui.js +++ b/modgui.js @@ -24,7 +24,7 @@ globalThis.modapi_guikit = "(" + (() => { - +
@@ -162,15 +162,18 @@ globalThis.modapi_guikit = "(" + (() => { font-size: 1.25rem; box-shadow: 0 -4px 6px rgba(0, 0, 0, 0.1); } + #modapi_gui_modTable { + min-width: 40vw; + } `; - async function fileToDataURI(file) { + async function fileToText(file) { return new Promise((res, rej) => { var fr = new FileReader(); fr.addEventListener("error", (e) => { rej(e); }); fr.addEventListener("load", (e) => { res(fr.result); }); - fr.readAsDataURL(file); + fr.readAsText(file); }); } window.modapi_displayModGui = async function (cb) { @@ -191,7 +194,7 @@ globalThis.modapi_guikit = "(" + (() => { document.querySelector("#modapi_gui_container")._cb = cb; var modsList = await getMods(); - var tbody = document.querySelector("#modapi_gui_container .modTable tbody"); + var tbody = document.querySelector("#modapi_gui_container #modapi_gui_modTable tbody"); tbody.innerHTML = ""; modsList.forEach((modtxt, i) => { if (!modtxt) { return } @@ -245,7 +248,6 @@ globalThis.modapi_guikit = "(" + (() => { var button = document.createElement("button"); button.innerText = "Delete"; button.style.height = "3rem"; - button.style.marginTop = "calc(50% - 1.5rem)"; button.addEventListener("click", async () => { await removeMod(i); window.modapi_displayModGui(); @@ -254,7 +256,7 @@ globalThis.modapi_guikit = "(" + (() => { controls.appendChild(button); tr.appendChild(mod); tr.appendChild(spacer); - tr.appendChild(button); + tr.appendChild(controls); tbody.appendChild(tr); }); var once = false; @@ -279,7 +281,7 @@ globalThis.modapi_guikit = "(" + (() => { if (!mod || mod.length === 0) { return; } - await addMod("web@" + mod); + await addMod(mod); window.modapi_displayModGui(); } window.modapi_uploadmod = async () => { @@ -292,7 +294,7 @@ globalThis.modapi_guikit = "(" + (() => { return; } for (let i = 0; i < f.files.length; i++) { - await addMod("web@" + (await fileToDataURI(f.files[i])).replaceAll(";base64", ";fs=" + f.files[i].name + ";base64")); + await addFileMod(f.files[i].name, (await fileToText(f.files[i]))); } window.modapi_displayModGui(); }); diff --git a/modloader.injector.js b/modloader.injector.js deleted file mode 100644 index 66c62d7..0000000 --- a/modloader.injector.js +++ /dev/null @@ -1,212 +0,0 @@ -globalThis.modapi_modloader = `function promisifyIDBRequest(request) { - return new Promise((resolve, reject) => { - request.onsuccess = () => resolve(request.result); - request.onerror = () => reject(request.error); - }); -} - -async function getDatabase() { - const dbRequest = indexedDB.open("EF_MODS"); - const db = await promisifyIDBRequest(dbRequest); - - if (!db.objectStoreNames.contains("filesystem")) { - db.close(); - const version = db.version + 1; - const upgradeRequest = indexedDB.open("EF_MODS", version); - upgradeRequest.onupgradeneeded = (event) => { - const upgradedDb = event.target.result; - upgradedDb.createObjectStore("filesystem"); - }; - return promisifyIDBRequest(upgradeRequest); - } - - return db; -} - -async function getMods() { - const db = await getDatabase(); - const transaction = db.transaction(["filesystem"], "readonly"); - const objectStore = transaction.objectStore("filesystem"); - const object = await promisifyIDBRequest(objectStore.get("mods.txt")); - return object ? (await object.text()).split("|") : []; -} - -async function saveMods(mods) { - const db = await getDatabase(); - const transaction = db.transaction(["filesystem"], "readwrite"); - const objectStore = transaction.objectStore("filesystem"); - const encoder = new TextEncoder(); - const modsData = encoder.encode(mods.join("|")); - const modsBlob = new Blob([modsData], { type: "text/plain" }); - await promisifyIDBRequest(objectStore.put(modsBlob, "mods.txt")); -} - -async function addMod(mod) { - const mods = await getMods(); - mods.push(mod); - await saveMods(mods); -} - -async function removeMod(index) { - const mods = await getMods(); - if (index >= 0 && index < mods.length) { - mods.splice(index, 1); - await saveMods(mods); - } -} - -async function resetMods() { - await saveMods([]); - console.log("Mods reset"); -} - -window.modLoader = async function modLoader(modsArr = []) { - if (!window.eaglerMLoaderMainRun) { - var searchParams = new URLSearchParams(location.search); - searchParams.getAll("mod").forEach((modToAdd) => { - console.log( - "[EaglerML] Adding mod to loadlist from search params: " + modToAdd - ); - modsArr.push(modToAdd); - }); - searchParams.getAll("plugin").forEach((modToAdd) => { - console.log( - "[EaglerML] Adding mod to loadlist from search params: " + modToAdd - ); - modsArr.push(modToAdd); - }); - if ( - !!eaglercraftXOpts && - !!eaglercraftXOpts.Mods && - Array.isArray(eaglercraftXOpts.Mods) - ) { - eaglercraftXOpts.Mods.forEach((modToAdd) => { - console.log( - "[EaglerML] Adding mod to loadlist from eaglercraftXOpts: " + - modToAdd - ); - modsArr.push(modToAdd); - }); - } - - console.log("[EaglerML] Searching in iDB"); - try { - var idbMods = await getMods(); - modsArr = modsArr.concat(idbMods - .filter(x => { return x && x.length > 0 }) - .flatMap(x => { if (x.startsWith("web@")) { return x.replace("web@", "") } return x }) - ); - } catch (error) { - console.error(error); - } - - window.eaglerMLoaderMainRun = true; - } - if (window.noLoadMods === true) { - modsArr.splice(0, modsArr.length); - } - function checkModsLoaded(totalLoaded, identifier) { - console.log( - "[EaglerML] Checking if mods are finished :: " + - totalLoaded + - "/" + - modsArr.length - ); - if (totalLoaded >= modsArr.length) { - clearInterval(identifier); - window.ModGracePeriod = false; - if ( - window.eaglerMLoaderMainRun && - ModAPI && - ModAPI.events && - ModAPI.events.callEvent - ) { - ModAPI.events.callEvent("load", {}); - } - console.log( - "[EaglerML] Checking if mods are finished :: All mods loaded! Grace period off." - ); - } - } - function methodB(currentMod) { - try { - console.log("[EaglerML] Loading " + currentMod + " via method B."); - var script = document.createElement("script"); - script.setAttribute("data-hash", ModAPI.util.hashCode("web@"+currentMod)); - script.src = currentMod; - script.setAttribute("data-isMod", "true"); - script.onerror = () => { - console.log( - "[EaglerML] Failed to load " + currentMod + " via method B!" - ); - script.remove(); - totalLoaded++; - }; - script.onload = () => { - console.log( - "[EaglerML] Successfully loaded " + currentMod + " via method B." - ); - totalLoaded++; - }; - document.body.appendChild(script); - } catch (error) { - console.log( - "[EaglerML] Oh no! The mod " + currentMod + " failed to load!" - ); - totalLoaded++; - } - } - window.ModGracePeriod = true; - var totalLoaded = 0; - var loaderCheckInterval = null; - modsArr.forEach((c) => { - let currentMod = c; - console.log("[EaglerML] Starting " + currentMod); - try { - var req = new XMLHttpRequest(); - req.open("GET", currentMod); - req.onload = function xhrLoadHandler() { - console.log("[EaglerML] Loading " + currentMod + " via method A."); - var script = document.createElement("script"); - script.setAttribute("data-hash", ModAPI.util.hashCode("web@"+currentMod)); - try { - script.src = - "data:text/javascript," + encodeURIComponent(req.responseText); - } catch (error) { - methodB(currentMod); - return; - } - script.setAttribute("data-isMod", "true"); - script.onerror = () => { - console.log( - "[EaglerML] Failed to load " + currentMod + " via method A!" - ); - script.remove(); - totalLoaded++; - }; - script.onload = () => { - console.log( - "[EaglerML] Successfully loaded " + currentMod + " via method A." - ); - totalLoaded++; - }; - document.body.appendChild(script); - }; - req.onerror = function xhrErrorHandler() { - methodB(currentMod); - }; - req.send(); - } catch (error) { - methodB(currentMod); - } - }); - loaderCheckInterval = setInterval(() => { - checkModsLoaded(totalLoaded, loaderCheckInterval); - }, 500); - console.log( - "[EaglerML] Starting to load " + modsArr.length + " mods..." - ); - window.returnTotalLoadedMods = function returnTotalLoadedMods() { - return totalLoaded; - }; -};`; \ No newline at end of file diff --git a/modloader.js b/modloader.js index 02cda35..10b9873 100644 --- a/modloader.js +++ b/modloader.js @@ -1,177 +1,219 @@ -function promisifyIDBRequest(request) { - return new Promise((resolve, reject) => { - request.onsuccess = () => resolve(request.result); - request.onerror = () => reject(request.error); - }); -} - -async function getDatabase() { - const dbRequest = indexedDB.open("EF_MODS"); - const db = await promisifyIDBRequest(dbRequest); - - if (!db.objectStoreNames.contains("filesystem")) { - db.close(); - const version = db.version + 1; - const upgradeRequest = indexedDB.open("EF_MODS", version); - upgradeRequest.onupgradeneeded = (event) => { - const upgradedDb = event.target.result; - upgradedDb.createObjectStore("filesystem"); - }; - return promisifyIDBRequest(upgradeRequest); +globalThis.modapi_modloader = "(" + (() => { + globalThis.promisifyIDBRequest = function promisifyIDBRequest(request) { + return new Promise((resolve, reject) => { + request.onsuccess = () => resolve(request.result); + request.onerror = () => reject(request.error); + }); } - return db; -} + globalThis.getDatabase = async function getDatabase() { + const dbRequest = indexedDB.open("EF_MODS"); + const db = await promisifyIDBRequest(dbRequest); -async function getMods() { - const db = await getDatabase(); - const transaction = db.transaction(["filesystem"], "readonly"); - const objectStore = transaction.objectStore("filesystem"); - const object = await promisifyIDBRequest(objectStore.get("mods.txt")); - return object ? (await object.text()).split("|") : []; -} + if (!db.objectStoreNames.contains("filesystem")) { + db.close(); + const version = db.version + 1; + const upgradeRequest = indexedDB.open("EF_MODS", version); + upgradeRequest.onupgradeneeded = (event) => { + const upgradedDb = event.target.result; + upgradedDb.createObjectStore("filesystem"); + }; + return promisifyIDBRequest(upgradeRequest); + } -async function saveMods(mods) { - const db = await getDatabase(); - const transaction = db.transaction(["filesystem"], "readwrite"); - const objectStore = transaction.objectStore("filesystem"); - const encoder = new TextEncoder(); - const modsData = encoder.encode(mods.join("|")); - const modsBlob = new Blob([modsData], { type: "text/plain" }); - await promisifyIDBRequest(objectStore.put(modsBlob, "mods.txt")); -} + return db; + } -async function addMod(mod) { - const mods = await getMods(); - mods.push(mod); - await saveMods(mods); -} + globalThis.getMods = async function getMods() { + const db = await getDatabase(); + const transaction = db.transaction(["filesystem"], "readonly"); + const objectStore = transaction.objectStore("filesystem"); + const object = await promisifyIDBRequest(objectStore.get("mods.txt")); + var out = object ? (await object.text()).split("|") : []; + db.close(); + return out; + } -async function removeMod(index) { - const mods = await getMods(); - if (index >= 0 && index < mods.length) { - mods.splice(index, 1); + globalThis.getMod = async function getMod(mod) { + const db = await getDatabase(); + const transaction = db.transaction(["filesystem"], "readonly"); + const objectStore = transaction.objectStore("filesystem"); + const object = await promisifyIDBRequest(objectStore.get("mods/" + mod)); + var out = object ? (await object.text()) : ""; + db.close(); + return out; + } + + globalThis.saveMods = async function saveMods(mods) { + const db = await getDatabase(); + const transaction = db.transaction(["filesystem"], "readwrite"); + const objectStore = transaction.objectStore("filesystem"); + const encoder = new TextEncoder(); + const modsData = encoder.encode(mods.join("|")); + const modsBlob = new Blob([modsData], { type: "text/plain" }); + await promisifyIDBRequest(objectStore.put(modsBlob, "mods.txt")); + db.close(); + } + + globalThis.addMod = async function addMod(mod) { + const mods = await getMods(); + mods.push("web@" + mod); await saveMods(mods); } -} -async function resetMods() { - await saveMods([]); - console.log("Mods reset"); -} + globalThis.addFileMod = async function addFileMod(mod, textContents) { + const mods = await getMods(); + mods.push(mod); + await saveMods(mods); -window.modLoader = async function modLoader(modsArr = []) { - if (!window.eaglerMLoaderMainRun) { - var searchParams = new URLSearchParams(location.search); - searchParams.getAll("mod").forEach((modToAdd) => { - console.log( - "[EaglerML] Adding mod to loadlist from search params: " + modToAdd - ); - modsArr.push(modToAdd); - }); - searchParams.getAll("plugin").forEach((modToAdd) => { - console.log( - "[EaglerML] Adding mod to loadlist from search params: " + modToAdd - ); - modsArr.push(modToAdd); - }); - if ( - !!eaglercraftXOpts && - !!eaglercraftXOpts.Mods && - Array.isArray(eaglercraftXOpts.Mods) - ) { - eaglercraftXOpts.Mods.forEach((modToAdd) => { - console.log( - "[EaglerML] Adding mod to loadlist from eaglercraftXOpts: " + - modToAdd - ); - modsArr.push(modToAdd); - }); - } - - console.log("[EaglerML] Searching in iDB"); - try { - var idbMods = await getMods(); - modsArr = modsArr.concat(idbMods - .filter(x => { return x && x.length > 0 }) - .flatMap(x => { if (x.startsWith("web@")) { return x.replace("web@", "") } return x }) - ); - } catch (error) { - console.error(error); - } - - window.eaglerMLoaderMainRun = true; + const db = await getDatabase(); + const transaction = db.transaction(["filesystem"], "readwrite"); + const objectStore = transaction.objectStore("filesystem"); + const encoder = new TextEncoder(); + const modsData = encoder.encode(textContents); + const modsBlob = new Blob([modsData], { type: "text/plain" }); + await promisifyIDBRequest(objectStore.put(modsBlob, "mods/" + mod)); + db.close(); } - if (window.noLoadMods === true) { - modsArr.splice(0, modsArr.length); - } - function checkModsLoaded(totalLoaded, identifier) { - console.log( - "[EaglerML] Checking if mods are finished :: " + - totalLoaded + - "/" + - modsArr.length - ); - if (totalLoaded >= modsArr.length) { - clearInterval(identifier); - window.ModGracePeriod = false; - if ( - window.eaglerMLoaderMainRun && - ModAPI && - ModAPI.events && - ModAPI.events.callEvent - ) { - ModAPI.events.callEvent("load", {}); + + globalThis.removeMod = async function removeMod(index) { + const mods = await getMods(); + if (index >= 0 && index < mods.length) { + var deleted = mods.splice(index, 1)[0]; + await saveMods(mods); + if (!deleted.startsWith("web@")) { + const db = await getDatabase(); + const transaction = db.transaction(["filesystem"], "readwrite"); + const objectStore = transaction.objectStore("filesystem"); + await promisifyIDBRequest(objectStore.delete("mods/" + deleted)); + db.close(); } - console.log( - "[EaglerML] Checking if mods are finished :: All mods loaded! Grace period off." - ); } } - function methodB(currentMod) { - try { - console.log("[EaglerML] Loading " + currentMod + " via method B."); - var script = document.createElement("script"); - script.setAttribute("data-hash", ModAPI.util.hashCode("web@"+currentMod)); - script.src = currentMod; - script.setAttribute("data-isMod", "true"); - script.onerror = () => { - console.log( - "[EaglerML] Failed to load " + currentMod + " via method B!" - ); - script.remove(); - totalLoaded++; - }; - script.onload = () => { - console.log( - "[EaglerML] Successfully loaded " + currentMod + " via method B." - ); - totalLoaded++; - }; - document.body.appendChild(script); - } catch (error) { - console.log( - "[EaglerML] Oh no! The mod " + currentMod + " failed to load!" - ); - totalLoaded++; - } + + globalThis.resetMods = async function resetMods() { + console.log("Resetting mods..."); + const db = await getDatabase(); + const transaction = db.transaction(["filesystem"], "readwrite"); + const objectStore = transaction.objectStore("filesystem"); + await promisifyIDBRequest(objectStore.clear()); + console.log("Mods reset"); + db.close(); } - window.ModGracePeriod = true; - var totalLoaded = 0; - var loaderCheckInterval = null; - modsArr.forEach((c) => { - let currentMod = c; - console.log("[EaglerML] Starting " + currentMod); - try { - var req = new XMLHttpRequest(); - req.open("GET", currentMod); - req.onload = function xhrLoadHandler() { + + globalThis.modLoader = async function modLoader(modsArr = []) { + if (!window.eaglerMLoaderMainRun) { + var searchParams = new URLSearchParams(location.search); + searchParams.getAll("mod").forEach((modToAdd) => { + console.log( + "[EaglerML] Adding mod to loadlist from search params: " + modToAdd + ); + modsArr.push("web@" + modToAdd); + }); + searchParams.getAll("plugin").forEach((modToAdd) => { + console.log( + "[EaglerML] Adding mod to loadlist from search params: " + modToAdd + ); + modsArr.push("web@" + modToAdd); + }); + if ( + !!eaglercraftXOpts && + !!eaglercraftXOpts.Mods && + Array.isArray(eaglercraftXOpts.Mods) + ) { + eaglercraftXOpts.Mods.forEach((modToAdd) => { + console.log( + "[EaglerML] Adding mod to loadlist from eaglercraftXOpts: " + + modToAdd + ); + modsArr.push(modToAdd); + }); + } + + console.log("[EaglerML] Searching in iDB"); + try { + var idbMods = await getMods(); + modsArr = modsArr.concat(idbMods + .filter(x => { return x && x.length > 0 }) + ); + } catch (error) { + console.error(error); + } + + window.eaglerMLoaderMainRun = true; + } + if (window.noLoadMods === true) { + modsArr.splice(0, modsArr.length); + } + function checkModsLoaded(totalLoaded, identifier) { + console.log( + "[EaglerML] Checking if mods are finished :: " + + totalLoaded + + "/" + + modsArr.length + ); + if (totalLoaded >= modsArr.length) { + clearInterval(identifier); + window.ModGracePeriod = false; + if ( + window.eaglerMLoaderMainRun && + ModAPI && + ModAPI.events && + ModAPI.events.callEvent + ) { + ModAPI.events.callEvent("load", {}); + } + console.log( + "[EaglerML] Checking if mods are finished :: All mods loaded! Grace period off." + ); + } + } + function methodB(currentMod) { + try { + console.log("[EaglerML] Loading " + currentMod + " via method B."); + var script = document.createElement("script"); + script.setAttribute("data-hash", ModAPI.util.hashCode("web@" + currentMod)); + script.src = currentMod; + script.setAttribute("data-isMod", "true"); + script.onerror = () => { + console.log( + "[EaglerML] Failed to load " + currentMod + " via method B!" + ); + script.remove(); + totalLoaded++; + }; + script.onload = () => { + console.log( + "[EaglerML] Successfully loaded " + currentMod + " via method B." + ); + totalLoaded++; + }; + document.body.appendChild(script); + } catch (error) { + console.log( + "[EaglerML] Oh no! The mod " + currentMod + " failed to load!" + ); + totalLoaded++; + } + } + window.ModGracePeriod = true; + var totalLoaded = 0; + var loaderCheckInterval = null; + for (let i = 0; i < modsArr.length; i++) { + let currentMod = modsArr[i]; + var isIDBMod = !currentMod.startsWith("web@"); + if (!isIDBMod) { + currentMod = currentMod.replace("web@", ""); + } + console.log("[EaglerML] Starting " + currentMod); + try { + var responseText = isIDBMod ? await getMod(currentMod) : await (await fetch(currentMod)).text(); console.log("[EaglerML] Loading " + currentMod + " via method A."); var script = document.createElement("script"); - script.setAttribute("data-hash", ModAPI.util.hashCode("web@"+currentMod)); + script.setAttribute("data-hash", ModAPI.util.hashCode((isIDBMod ? "" : "web@") + currentMod)); try { script.src = - "data:text/javascript," + encodeURIComponent(req.responseText); + "data:text/javascript," + encodeURIComponent(responseText); } catch (error) { methodB(currentMod); return; @@ -191,22 +233,18 @@ window.modLoader = async function modLoader(modsArr = []) { totalLoaded++; }; document.body.appendChild(script); - }; - req.onerror = function xhrErrorHandler() { + } catch (error) { methodB(currentMod); - }; - req.send(); - } catch (error) { - methodB(currentMod); + } } - }); - loaderCheckInterval = setInterval(() => { - checkModsLoaded(totalLoaded, loaderCheckInterval); - }, 500); - console.log( - "[EaglerML] Starting to load " + modsArr.length + " mods..." - ); - window.returnTotalLoadedMods = function returnTotalLoadedMods() { - return totalLoaded; + loaderCheckInterval = setInterval(() => { + checkModsLoaded(totalLoaded, loaderCheckInterval); + }, 500); + console.log( + "[EaglerML] Starting to load " + modsArr.length + " mods..." + ); + window.returnTotalLoadedMods = function returnTotalLoadedMods() { + return totalLoaded; + }; }; -}; \ No newline at end of file +}).toString() + ")();" \ No newline at end of file From f600e3859a25c7b0b539fca1a038b0ade49f2ae8 Mon Sep 17 00:00:00 2001 From: ZXMushroom63 Date: Mon, 9 Dec 2024 10:11:07 +0800 Subject: [PATCH 15/20] add sorting to modlaoder --- modloader.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modloader.js b/modloader.js index 10b9873..8f43001 100644 --- a/modloader.js +++ b/modloader.js @@ -29,7 +29,7 @@ globalThis.modapi_modloader = "(" + (() => { const transaction = db.transaction(["filesystem"], "readonly"); const objectStore = transaction.objectStore("filesystem"); const object = await promisifyIDBRequest(objectStore.get("mods.txt")); - var out = object ? (await object.text()).split("|") : []; + var out = object ? (await object.text()).split("|").toSorted() : []; db.close(); return out; } @@ -49,7 +49,7 @@ globalThis.modapi_modloader = "(" + (() => { const transaction = db.transaction(["filesystem"], "readwrite"); const objectStore = transaction.objectStore("filesystem"); const encoder = new TextEncoder(); - const modsData = encoder.encode(mods.join("|")); + const modsData = encoder.encode(mods.toSorted().join("|")); const modsBlob = new Blob([modsData], { type: "text/plain" }); await promisifyIDBRequest(objectStore.put(modsBlob, "mods.txt")); db.close(); @@ -199,6 +199,7 @@ globalThis.modapi_modloader = "(" + (() => { window.ModGracePeriod = true; var totalLoaded = 0; var loaderCheckInterval = null; + modsArr.sort(); for (let i = 0; i < modsArr.length; i++) { let currentMod = modsArr[i]; var isIDBMod = !currentMod.startsWith("web@"); From 04325e6f4e8b0bef18c3c7ad127dae52da00ed00 Mon Sep 17 00:00:00 2001 From: ZXMushroom63 Date: Mon, 9 Dec 2024 11:25:00 +0800 Subject: [PATCH 16/20] make unlucky blocks less laggy --- examplemods/unlucky_blocks.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examplemods/unlucky_blocks.js b/examplemods/unlucky_blocks.js index cc2f459..97dd51b 100644 --- a/examplemods/unlucky_blocks.js +++ b/examplemods/unlucky_blocks.js @@ -38,7 +38,7 @@ var blockpos = ModAPI.util.wrap($blockpos); if (Math.random() < 1) { //was gonna add random events but couldn't be bothered. Enjoy exploding! world.newExplosion(null, blockpos.getX() + 0.5, blockpos.getY() + 0.5, - blockpos.getZ() + 0.5, 9, 1, 1); + blockpos.getZ() + 0.5, 9, 1, 0); } return breakBlockMethod(this, $world, $blockpos, $blockstate); } From b8fcdd3a6e2f8332a17b1c6d39d5258dd6ca26ad Mon Sep 17 00:00:00 2001 From: ZXMushroom63 Date: Mon, 9 Dec 2024 11:26:13 +0800 Subject: [PATCH 17/20] bump version --- postinit.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/postinit.js b/postinit.js index 4e44780..342ae64 100644 --- a/postinit.js +++ b/postinit.js @@ -1,4 +1,4 @@ -globalThis.ModAPIVersion = "v2.3.2"; +globalThis.ModAPIVersion = "v2.3.3"; globalThis.modapi_postinit = "(" + (() => { //EaglerForge post initialization code. //This script cannot contain backticks, escape characters, or backslashes in order to inject into the dedicated server code. From 8aa7937382eabc94ab8c1d1700150a7955ceb34a Mon Sep 17 00:00:00 2001 From: ZXMushroom63 Date: Mon, 9 Dec 2024 15:42:14 +0800 Subject: [PATCH 18/20] fix bug, but new regression --- examplemods/guns.js | 2 +- examplemods/useless_item_example_mod.js | 2 +- postinit.js | 19 +++++++++++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/examplemods/guns.js b/examplemods/guns.js index 469d479..8cb5e99 100644 --- a/examplemods/guns.js +++ b/examplemods/guns.js @@ -68,7 +68,7 @@ var pistol_item = (new nmi_ItemPistol()).$setUnlocalizedName( ModAPI.util.str("pistol") ); - itemClass.staticMethods.registerItem0.method(ModAPI.keygen.item("pistol"), ModAPI.util.str("pistol"), pistol_item); + itemClass.staticMethods.registerItem.method(ModAPI.keygen.item("pistol"), ModAPI.util.str("pistol"), pistol_item); ModAPI.items["pistol"] = pistol_item; return pistol_item; diff --git a/examplemods/useless_item_example_mod.js b/examplemods/useless_item_example_mod.js index 3fb0dcc..16530c0 100644 --- a/examplemods/useless_item_example_mod.js +++ b/examplemods/useless_item_example_mod.js @@ -24,7 +24,7 @@ var example_item = (new nmi_ItemExample()).$setUnlocalizedName( ModAPI.util.str("exampleitem") ); - itemClass.staticMethods.registerItem0.method(ModAPI.keygen.item("exampleitem"), ModAPI.util.str("exampleitem"), example_item); + itemClass.staticMethods.registerItem.method(ModAPI.keygen.item("exampleitem"), ModAPI.util.str("exampleitem"), example_item); ModAPI.items["exampleitem"] = example_item; return example_item; diff --git a/postinit.js b/postinit.js index 342ae64..17cd42f 100644 --- a/postinit.js +++ b/postinit.js @@ -890,8 +890,10 @@ globalThis.modapi_postinit = "(" + (() => { } ModAPI.events.newEvent("bootstrap", "server"); + ModAPI.events.newEvent("prebootstrap", "server"); const originalBootstrap = ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.minecraft.init.Bootstrap", "register")]; ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.minecraft.init.Bootstrap", "register")] = function (...args) { + ModAPI.events.callEvent("prebootstrap", {}); var x = originalBootstrap.apply(this, args); ModAPI.util.bootstrap(); ModAPI.events.callEvent("bootstrap", {}); @@ -899,6 +901,23 @@ globalThis.modapi_postinit = "(" + (() => { return x; } + + ModAPI.events.newEvent("registeritems", "server"); + const originalItemRegister = ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.minecraft.item.Item", "registerItems")]; + ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.minecraft.item.Item", "registerItems")] = function (...args) { + var x = originalItemRegister.apply(this, args); + ModAPI.events.callEvent("registeritems", {}); + return x; + } + + ModAPI.events.newEvent("registerblocks", "server"); + const originalBlockRegister = ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.minecraft.block.Block", "registerBlocks")]; + ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.minecraft.block.Block")] = function (...args) { + var x = originalBlockRegister.apply(this, args); + ModAPI.events.callEvent("registerblocks", {}); + return x; + } + const originalOptionsInit = ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.minecraft.client.gui.GuiOptions", "initGui")]; ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.minecraft.client.gui.GuiOptions", "initGui")] = function (...args) { var x = originalOptionsInit.apply(this, args); From 8c1ae93040432015bb9dd8ac66c5950d95ff9173 Mon Sep 17 00:00:00 2001 From: ZXMushroom63 Date: Mon, 9 Dec 2024 16:02:04 +0800 Subject: [PATCH 19/20] almost done with postinit --- postinit.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/postinit.js b/postinit.js index 17cd42f..c7c8479 100644 --- a/postinit.js +++ b/postinit.js @@ -891,13 +891,17 @@ globalThis.modapi_postinit = "(" + (() => { ModAPI.events.newEvent("bootstrap", "server"); ModAPI.events.newEvent("prebootstrap", "server"); + const bootstrapClass = ModAPI.reflect.getClassById("net.minecraft.init.Bootstrap"); const originalBootstrap = ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.minecraft.init.Bootstrap", "register")]; ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.minecraft.init.Bootstrap", "register")] = function (...args) { + if (bootstrapClass.staticVariables.alreadyRegistered) { + return; + } ModAPI.events.callEvent("prebootstrap", {}); var x = originalBootstrap.apply(this, args); ModAPI.util.bootstrap(); - ModAPI.events.callEvent("bootstrap", {}); console.log("[ModAPI] Hooked into bootstrap. .blocks, .items, .materials and .enchantments are now accessible."); + ModAPI.events.callEvent("bootstrap", {}); return x; } From a519eb7afa730127d2fd4aa329684e6181826a0b Mon Sep 17 00:00:00 2001 From: ZXMushroom63 Date: Mon, 9 Dec 2024 16:59:45 +0800 Subject: [PATCH 20/20] Fix gun bug, add more static variables and add clinit methods --- examplemods/guns.js | 7 ++++++- injector.js | 27 ++++++++++----------------- postinit.js | 19 ------------------- 3 files changed, 16 insertions(+), 37 deletions(-) diff --git a/examplemods/guns.js b/examplemods/guns.js index 8cb5e99..de22609 100644 --- a/examplemods/guns.js +++ b/examplemods/guns.js @@ -6,6 +6,7 @@ ModAPI.meta.description("Requires AsyncSink."); function PistolItem() { + var DamageSourceClass = ModAPI.reflect.getClassByName("DamageSource"); var creativeMiscTab = ModAPI.reflect.getClassById("net.minecraft.creativetab.CreativeTabs").staticVariables.tabMisc; var itemClass = ModAPI.reflect.getClassById("net.minecraft.item.Item"); var itemSuper = ModAPI.reflect.getSuper(itemClass, (x) => x.length === 1); @@ -53,7 +54,11 @@ } ModAPI.reflect.prototypeStack(itemClass, nmi_ItemPistol); nmi_ItemPistol.prototype.$onItemRightClick = function ($itemstack, $world, $player) { - var cactus = ModAPI.reflect.getClassByName("DamageSource").staticVariables.cactus; + DamageSourceClass.staticMethods.$callClinit.method(); + //Noticed that the gun only worked after an entity in the world takes damage XD + //TeaVM is very optimised. Using $callClinit tells it to hurry up pretty much lol + + var cactus = DamageSourceClassstaticVariables.cactus; var world = ModAPI.util.wrap($world); var entityplayer = ModAPI.util.wrap($player); var shotentity = entityRayCast(entityplayer, world, 12.0) diff --git a/injector.js b/injector.js index 2a9c590..bb3d8a5 100644 --- a/injector.js +++ b/injector.js @@ -18,24 +18,17 @@ function entriesToStaticVariableProxy(entries, prefix) { var getComponents = ""; entries.forEach((entry) => { getComponents += ` - case \`${entry.name}\`: - return ${entry.variable}; - break;`; + case \`${entry.name}\`: return ${entry.variable};`; }); getComponents += ` - default: - return Reflect.get(a,b,c);` + default: return Reflect.get(a,b,c);` var setComponents = ""; entries.forEach((entry) => { setComponents += ` - case \`${entry.name}\`: - ${entry.variable} = c; - break;`; + case \`${entry.name}\`: ${entry.variable} = c; break;`; }); - setComponents += ` - default: - a[b]=c;` + setComponents += ` default: a[b]=c;` /*/ ModAPI.hooks._rippedStaticIndexer[\`${prefix.replace( @@ -196,8 +189,7 @@ var main;(function(){` (match) => { if ( match.includes("__init_") || - match.includes("__clinit_") || - match.includes("_$callClinit") + match.includes("__clinit_") ) { return match; } @@ -212,13 +204,14 @@ var main;(function(){` ModAPI.hooks.methods[\`${fullName}\`]=` + match.replace(fullName + "(", "(") ); - return match; } ); var staticVariables = [ - ...patchedFile.matchAll(/var \S+?_\S+?_\S+? = null;/gm), + ...patchedFile.matchAll(/var \S+?_\S+?_\S+? = /gm), ].flatMap((x) => { return x[0]; + }).filter(x => { + return (!x.includes("$_clinit_$")) && (!x.includes("$lambda$")) }); patchedFile = patchedFile.replaceAll( /var \S+?_\S+? = \$rt_classWithoutFields\(\S*?\);/gm, @@ -232,7 +225,7 @@ var main;(function(){` if (entry.startsWith(prefix)) { var variableName = entry .replace("var ", "") - .replace(" = null;", ""); + .replace(" = ", ""); var segments = variableName.split("_"); segments.splice(0, 2); var name = segments.join("_"); @@ -262,7 +255,7 @@ var main;(function(){` if (entry.startsWith(prefix)) { var variableName = entry .replace("var ", "") - .replace(" = null;", ""); + .replace(" = ", ""); var segments = variableName.split("_"); segments.splice(0, 2); var name = segments.join("_"); diff --git a/postinit.js b/postinit.js index c7c8479..857026d 100644 --- a/postinit.js +++ b/postinit.js @@ -890,14 +890,12 @@ globalThis.modapi_postinit = "(" + (() => { } ModAPI.events.newEvent("bootstrap", "server"); - ModAPI.events.newEvent("prebootstrap", "server"); const bootstrapClass = ModAPI.reflect.getClassById("net.minecraft.init.Bootstrap"); const originalBootstrap = ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.minecraft.init.Bootstrap", "register")]; ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.minecraft.init.Bootstrap", "register")] = function (...args) { if (bootstrapClass.staticVariables.alreadyRegistered) { return; } - ModAPI.events.callEvent("prebootstrap", {}); var x = originalBootstrap.apply(this, args); ModAPI.util.bootstrap(); console.log("[ModAPI] Hooked into bootstrap. .blocks, .items, .materials and .enchantments are now accessible."); @@ -905,23 +903,6 @@ globalThis.modapi_postinit = "(" + (() => { return x; } - - ModAPI.events.newEvent("registeritems", "server"); - const originalItemRegister = ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.minecraft.item.Item", "registerItems")]; - ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.minecraft.item.Item", "registerItems")] = function (...args) { - var x = originalItemRegister.apply(this, args); - ModAPI.events.callEvent("registeritems", {}); - return x; - } - - ModAPI.events.newEvent("registerblocks", "server"); - const originalBlockRegister = ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.minecraft.block.Block", "registerBlocks")]; - ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.minecraft.block.Block")] = function (...args) { - var x = originalBlockRegister.apply(this, args); - ModAPI.events.callEvent("registerblocks", {}); - return x; - } - const originalOptionsInit = ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.minecraft.client.gui.GuiOptions", "initGui")]; ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.minecraft.client.gui.GuiOptions", "initGui")] = function (...args) { var x = originalOptionsInit.apply(this, args);