diff --git a/modgui.injector.js b/modgui.injector.js index d2d64e2..fda999f 100644 --- a/modgui.injector.js +++ b/modgui.injector.js @@ -1,15 +1,15 @@ globalThis.modapi_guikit = `// ModAPI GUI made by TheIdiotPlays // https://github.com/TheIdiotPlays -(()=>{ - var splashes = [ - "Now with A.I.D.S (automatically injected dedicated server)", - "Only causes death 90% of the time!", - "HTML is better.", - "https://github.com/EaglerForge", - "hey you should check out https://github.com/ZXMushroom63/scratch-gui", - "99% of people stop gambling before they win big." - ]; - var gui = \`
+(() => { + var splashes = [ + "Now with A.I.D.S (automatically injected dedicated server)", + "Only causes death 90% of the time!", + "HTML is better.", + "https://github.com/EaglerForge", + "hey you should check out https://github.com/ZXMushroom63/scratch-gui", + "99% of people stop gambling before they win big." + ]; + var gui = \`

EaglerForge Mod Manager

@@ -158,38 +158,85 @@ globalThis.modapi_guikit = `// ModAPI GUI made by TheIdiotPlays }

\`; - window.modapi_displayModGui = async function () { - if (!getMods) { - return; - } - if (document.querySelector("#modapi_gui_container")) { - document.querySelector("#modapi_gui_container").remove(); - } - var element = document.createElement("div"); - - element.innerHTML = gui.replace("{splash_msg}", splashes[Math.floor(Math.random() * splashes.length)]); - - document.body.appendChild(element); - - var modsList = await getMods(); - var tbody = document.querySelector("#modapi_gui_container .modTable tbody"); - tbody.innerHTML = ""; - modsList.forEach((modtxt, i) => { - var tr = document.createElement("tr"); - var mod = document.createElement("td"); - mod.innerText = modtxt; - var spacer = document.createElement("td"); - spacer.appendChild("nothing"); - var controls = document.createElement("td"); - - var button = document.createElement("button"); - button.classList.add("button"); - controls.appendChild(button); - tr.appendChild(mod); - tr.appendChild(spacer); - tr.appendChild(button); - tbody.appendChild(tr); - }); - + async function fileToDataURI(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); + }); + } + window.modapi_displayModGui = async function () { + if (!getMods) { + return; } + if (document.querySelector("#modapi_gui_container")) { + document.querySelector("#modapi_gui_container").remove(); + } + var element = document.createElement("div"); + + element.innerHTML = gui.replace("{splash_msg}", splashes[Math.floor(Math.random() * splashes.length)]); + + document.body.appendChild(element); + + var modsList = await getMods(); + var tbody = document.querySelector("#modapi_gui_container .modTable tbody"); + tbody.innerHTML = ""; + modsList.forEach((modtxt, i) => { + if (!modtxt) { return } + var tr = document.createElement("tr"); + var mod = document.createElement("td"); + if (modtxt.length > 125) { + try { + mod.innerText = modtxt.match(/data:text\\/\\S+?;fs=\\S+;/m)[0] + } catch (error) { + mod.innerText = "Unknown Mod."; + } + } else { mod.innerText = modtxt; } + var spacer = document.createElement("td"); + spacer.classList.add("nothing"); + var controls = document.createElement("td"); + + var button = document.createElement("button"); + button.innerText = "Delete"; + button.addEventListener("click", async () => { + await removeMod(i); + window.modapi_displayModGui(); + }); + button.classList.add("button"); + controls.appendChild(button); + tr.appendChild(mod); + tr.appendChild(spacer); + tr.appendChild(button); + tbody.appendChild(tr); + }); + } + window.modapi_clearmods = async () => { + await resetMods(); + window.modapi_displayModGui(); + } + window.modapi_addmod = async () => { + var mod = window.prompt("Paste in the URL of the mod you wish to add: "); + if (!mod || mod.length === 0) { + return; + } + await addMod("web@" + mod); + window.modapi_displayModGui(); + } + window.modapi_uploadmod = async () => { + var f = document.createElement("input"); + f.type = "file"; + f.accept = "text/javascript"; + f.multiple = true; + f.addEventListener("input", async () => { + if (f.files.length < 1) { + 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")); + } + window.modapi_displayModGui(); + }); + f.click(); + } })();`; \ No newline at end of file diff --git a/modgui.js b/modgui.js index 2e5c7b9..b3df844 100644 --- a/modgui.js +++ b/modgui.js @@ -1,15 +1,15 @@ // ModAPI GUI made by TheIdiotPlays // https://github.com/TheIdiotPlays -(()=>{ - var splashes = [ - "Now with A.I.D.S (automatically injected dedicated server)", - "Only causes death 90% of the time!", - "HTML is better.", - "https://github.com/EaglerForge", - "hey you should check out https://github.com/ZXMushroom63/scratch-gui", - "99% of people stop gambling before they win big." - ]; - var gui = `
+(() => { + var splashes = [ + "Now with A.I.D.S (automatically injected dedicated server)", + "Only causes death 90% of the time!", + "HTML is better.", + "https://github.com/EaglerForge", + "hey you should check out https://github.com/ZXMushroom63/scratch-gui", + "99% of people stop gambling before they win big." + ]; + var gui = `

EaglerForge Mod Manager

@@ -158,38 +158,85 @@ }

`; - window.modapi_displayModGui = async function () { - if (!getMods) { - return; - } - if (document.querySelector("#modapi_gui_container")) { - document.querySelector("#modapi_gui_container").remove(); - } - var element = document.createElement("div"); - - element.innerHTML = gui.replace("{splash_msg}", splashes[Math.floor(Math.random() * splashes.length)]); - - document.body.appendChild(element); - - var modsList = await getMods(); - var tbody = document.querySelector("#modapi_gui_container .modTable tbody"); - tbody.innerHTML = ""; - modsList.forEach((modtxt, i) => { - var tr = document.createElement("tr"); - var mod = document.createElement("td"); - mod.innerText = modtxt; - var spacer = document.createElement("td"); - spacer.appendChild("nothing"); - var controls = document.createElement("td"); - - var button = document.createElement("button"); - button.classList.add("button"); - controls.appendChild(button); - tr.appendChild(mod); - tr.appendChild(spacer); - tr.appendChild(button); - tbody.appendChild(tr); - }); - + async function fileToDataURI(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); + }); + } + window.modapi_displayModGui = async function () { + if (!getMods) { + return; } + if (document.querySelector("#modapi_gui_container")) { + document.querySelector("#modapi_gui_container").remove(); + } + var element = document.createElement("div"); + + element.innerHTML = gui.replace("{splash_msg}", splashes[Math.floor(Math.random() * splashes.length)]); + + document.body.appendChild(element); + + var modsList = await getMods(); + var tbody = document.querySelector("#modapi_gui_container .modTable tbody"); + tbody.innerHTML = ""; + modsList.forEach((modtxt, i) => { + if (!modtxt) { return } + var tr = document.createElement("tr"); + var mod = document.createElement("td"); + if (modtxt.length > 125) { + try { + mod.innerText = modtxt.match(/data:text\/\S+?;fs=\S+;/m)[0] + } catch (error) { + mod.innerText = "Unknown Mod."; + } + } else { mod.innerText = modtxt; } + var spacer = document.createElement("td"); + spacer.classList.add("nothing"); + var controls = document.createElement("td"); + + var button = document.createElement("button"); + button.innerText = "Delete"; + button.addEventListener("click", async () => { + await removeMod(i); + window.modapi_displayModGui(); + }); + button.classList.add("button"); + controls.appendChild(button); + tr.appendChild(mod); + tr.appendChild(spacer); + tr.appendChild(button); + tbody.appendChild(tr); + }); + } + window.modapi_clearmods = async () => { + await resetMods(); + window.modapi_displayModGui(); + } + window.modapi_addmod = async () => { + var mod = window.prompt("Paste in the URL of the mod you wish to add: "); + if (!mod || mod.length === 0) { + return; + } + await addMod("web@" + mod); + window.modapi_displayModGui(); + } + window.modapi_uploadmod = async () => { + var f = document.createElement("input"); + f.type = "file"; + f.accept = "text/javascript"; + f.multiple = true; + f.addEventListener("input", async () => { + if (f.files.length < 1) { + 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")); + } + window.modapi_displayModGui(); + }); + f.click(); + } })(); \ No newline at end of file diff --git a/modloader.injector.js b/modloader.injector.js index 325866b..3106c34 100644 --- a/modloader.injector.js +++ b/modloader.injector.js @@ -28,8 +28,7 @@ async function getMods() { const transaction = db.transaction(["filesystem"], "readonly"); const objectStore = transaction.objectStore("filesystem"); const object = await promisifyIDBRequest(objectStore.get("mods.txt")); - const decoder = new TextDecoder("utf-8"); - return object ? decoder.decode(object).split("|") : []; + return object ? (await object.text()).split("|") : []; } async function saveMods(mods) { @@ -46,26 +45,21 @@ async function addMod(mod) { const mods = await getMods(); mods.push(mod); await saveMods(mods); - console.log("Mod added: " + mod); } async function removeMod(index) { const mods = await getMods(); if (index >= 0 && index < mods.length) { - const removedMod = mods.splice(index, 1); + mods.splice(index, 1); await saveMods(mods); - console.log("Mod removed: " + removedMod); - } else { - console.log("Invalid index"); } } async function resetMods() { await saveMods([]); - console.log("Mods reset"); } -window.modLoader = async function modLoader(modsArr) { +window.modLoader = async function modLoader(modsArr = []) { if (!window.eaglerMLoaderMainRun) { var searchParams = new URLSearchParams(location.search); searchParams.getAll("mod").forEach((modToAdd) => { @@ -94,52 +88,13 @@ window.modLoader = async function modLoader(modsArr) { }); } - // Reverse engineer eaglercraftx virtual file system to gain external access to mod store WITHOUT messing with java teavm nonsense - var StoreId = "EF_MODS"; - var decoder = new TextDecoder("utf-8"); console.log("[EaglerML] Searching in iDB"); try { - var database = await promisifyIDBRequest(indexedDB.open(StoreId)); - var storeIsValid = !!database.objectStoreNames[0]; - if (!storeIsValid) { - throw new Error("Invalid object store"); - } - var key = database.objectStoreNames[0].length === 0 ? "filesystem" : database.objectStoreNames[0]; - var transaction = database.transaction([key], "readwrite"); - var objectStore = transaction.objectStore("filesystem"); - var object = await promisifyIDBRequest(objectStore.get(["mods.txt"])); - if (!object) { - throw new Error("No mods.txt found"); - } - var mods = decoder.decode(object.data); - if (mods.length === 0) { - throw new Error("No mods found"); - } - var modsArr = mods.split("|"); - for (var modFilePath of modsArr) { - if (modFilePath.length === 0) { - continue; - } - var modUrl = null; - if (modFilePath.startsWith("web@")) { - modUrl = modFilePath.replace("web@", ""); - } else { - var modFile = await promisifyIDBRequest(objectStore.get(["mods/" + modFilePath])); - if (!modFile) { - continue; - } - var modData = decoder.decode(modFile.data); - var modBlob = new Blob([modData], { - type: 'text/javascript' - }); - modUrl = URL.createObjectURL(modBlob); - } - if (!modUrl) { - continue; - } - modsArr.push(modUrl); - console.log("Loaded iDB mod: " + modFilePath); - } + var idbMods = await getMods(); + 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); } diff --git a/modloader.js b/modloader.js index 4423bcb..e149676 100644 --- a/modloader.js +++ b/modloader.js @@ -28,8 +28,7 @@ async function getMods() { const transaction = db.transaction(["filesystem"], "readonly"); const objectStore = transaction.objectStore("filesystem"); const object = await promisifyIDBRequest(objectStore.get("mods.txt")); - const decoder = new TextDecoder("utf-8"); - return object ? decoder.decode(object).split("|") : []; + return object ? (await object.text()).split("|") : []; } async function saveMods(mods) { @@ -46,17 +45,13 @@ async function addMod(mod) { const mods = await getMods(); mods.push(mod); await saveMods(mods); - console.log("Mod added: " + mod); } async function removeMod(index) { const mods = await getMods(); if (index >= 0 && index < mods.length) { - const removedMod = mods.splice(index, 1); + mods.splice(index, 1); await saveMods(mods); - console.log("Mod removed: " + removedMod); - } else { - console.log("Invalid index"); } } @@ -65,7 +60,7 @@ async function resetMods() { console.log("Mods reset"); } -window.modLoader = async function modLoader(modsArr) { +window.modLoader = async function modLoader(modsArr = []) { if (!window.eaglerMLoaderMainRun) { var searchParams = new URLSearchParams(location.search); searchParams.getAll("mod").forEach((modToAdd) => { @@ -94,52 +89,13 @@ window.modLoader = async function modLoader(modsArr) { }); } - // Reverse engineer eaglercraftx virtual file system to gain external access to mod store WITHOUT messing with java teavm nonsense - var StoreId = "EF_MODS"; - var decoder = new TextDecoder("utf-8"); console.log("[EaglerML] Searching in iDB"); try { - var database = await promisifyIDBRequest(indexedDB.open(StoreId)); - var storeIsValid = !!database.objectStoreNames[0]; - if (!storeIsValid) { - throw new Error("Invalid object store"); - } - var key = database.objectStoreNames[0].length === 0 ? "filesystem" : database.objectStoreNames[0]; - var transaction = database.transaction([key], "readwrite"); - var objectStore = transaction.objectStore("filesystem"); - var object = await promisifyIDBRequest(objectStore.get(["mods.txt"])); - if (!object) { - throw new Error("No mods.txt found"); - } - var mods = decoder.decode(object.data); - if (mods.length === 0) { - throw new Error("No mods found"); - } - var modsArr = mods.split("|"); - for (var modFilePath of modsArr) { - if (modFilePath.length === 0) { - continue; - } - var modUrl = null; - if (modFilePath.startsWith("web@")) { - modUrl = modFilePath.replace("web@", ""); - } else { - var modFile = await promisifyIDBRequest(objectStore.get(["mods/" + modFilePath])); - if (!modFile) { - continue; - } - var modData = decoder.decode(modFile.data); - var modBlob = new Blob([modData], { - type: 'text/javascript' - }); - modUrl = URL.createObjectURL(modBlob); - } - if (!modUrl) { - continue; - } - modsArr.push(modUrl); - console.log("Loaded iDB mod: " + modFilePath); - } + var idbMods = await getMods(); + 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); }