diff --git a/examplemods/talkback.js b/examplemods/talkback.js new file mode 100644 index 0000000..d6155fb --- /dev/null +++ b/examplemods/talkback.js @@ -0,0 +1,15 @@ +(() => { + PluginAPI.dedicatedServer.appendCode(function () { + PluginAPI.addEventListener("processcommand", (event) => { + if (event.command.toLowerCase().startsWith("/talkback")) { + var message = event.command.substring("/talkback ".length); + if ( + ModAPI.hooks._teavm.$rt_isInstance(event.sender, ModAPI.hooks._classMap[ModAPI.util.getCompiledName("net.minecraft.entity.player.EntityPlayerMP")].class) + ) { + event.sender.addChatMessage(ModAPI.hooks._classMap[ModAPI.util.getCompiledName("net.minecraft.util.ChatComponentText")].constructors[0](ModAPI.util.str(message.toUpperCase()))); + } + event.preventDefault = true; + } + }); + }); +})(); \ No newline at end of file diff --git a/injector.html b/injector.html index 8160c04..4a8b0ac 100644 --- a/injector.html +++ b/injector.html @@ -262,5 +262,6 @@ var main;(function(){` + diff --git a/modgui.injector.js b/modgui.injector.js index 54e01f6..d2d64e2 100644 --- a/modgui.injector.js +++ b/modgui.injector.js @@ -1 +1,195 @@ -globalThis.modapi_guikit = ``; \ No newline at end of file +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 = \`
+
+

EaglerForge Mod Manager

+

+ + {splash_msg} +

+
+ Warning: installing malicious mods can delete your worlds, ip-grab you, or even download more serious malware onto your computer. The EaglerForge developers are not liable for any damage caused by the use of EaglerForge and its related tools. +
+
+ + + + + + + + + + + +
+ URL + + Controls +
+ +
+ + + + +
+ + (reload to apply changes) + + + + +
\`; + 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); + }); + + } +})();`; \ No newline at end of file diff --git a/modgui.js b/modgui.js index b229d48..2e5c7b9 100644 --- a/modgui.js +++ b/modgui.js @@ -1,2 +1,195 @@ // 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 = `
+
+

EaglerForge Mod Manager

+

+ + {splash_msg} +

+
+ Warning: installing malicious mods can delete your worlds, ip-grab you, or even download more serious malware onto your computer. The EaglerForge developers are not liable for any damage caused by the use of EaglerForge and its related tools. +
+
+ + + + + + + + + + + +
+ URL + + Controls +
+ +
+ + + + +
+ + (reload to apply changes) + + + + +
`; + 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); + }); + + } +})(); \ No newline at end of file diff --git a/modloader.injector.js b/modloader.injector.js index 2122e59..325866b 100644 --- a/modloader.injector.js +++ b/modloader.injector.js @@ -5,29 +5,48 @@ globalThis.modapi_modloader = `function promisifyIDBRequest(request) { }); } +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 promisifyIDBRequest(indexedDB.open("EF_MODS")); - const transaction = db.transaction(["filesystem"], "readwrite"); + const db = await getDatabase(); + const transaction = db.transaction(["filesystem"], "readonly"); const objectStore = transaction.objectStore("filesystem"); - const object = await promisifyIDBRequest(objectStore.get(["mods.txt"])); + const object = await promisifyIDBRequest(objectStore.get("mods.txt")); const decoder = new TextDecoder("utf-8"); - return object ? decoder.decode(object.data).split("|") : []; + return object ? decoder.decode(object).split("|") : []; } async function saveMods(mods) { - const db = await promisifyIDBRequest(indexedDB.open("EF_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({ data: modsBlob }, ["mods.txt"])); + await promisifyIDBRequest(objectStore.put(modsBlob, "mods.txt")); } async function addMod(mod) { const mods = await getMods(); mods.push(mod); await saveMods(mods); + console.log("Mod added: " + mod); } async function removeMod(index) { @@ -35,11 +54,15 @@ async function removeMod(index) { if (index >= 0 && index < mods.length) { const removedMod = 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) { @@ -154,7 +177,7 @@ window.modLoader = async function modLoader(modsArr) { console.log("[EaglerML] Loading " + currentMod + " via method B."); var script = document.createElement("script"); script.src = currentMod; - script.setAttribute("data-Mod", currentMod); + script.setAttribute("data-mod", currentMod); script.setAttribute("data-isMod", true); script.onerror = () => { console.log( @@ -196,7 +219,7 @@ window.modLoader = async function modLoader(modsArr) { methodB(currentMod); return; } - script.setAttribute("data-Mod", currentMod); + script.setAttribute("data-mod", currentMod); script.setAttribute("data-isMod", true); script.onerror = () => { console.log( diff --git a/modloader.js b/modloader.js index d36e797..4423bcb 100644 --- a/modloader.js +++ b/modloader.js @@ -5,29 +5,48 @@ function promisifyIDBRequest(request) { }); } +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 promisifyIDBRequest(indexedDB.open("EF_MODS")); - const transaction = db.transaction(["filesystem"], "readwrite"); + const db = await getDatabase(); + const transaction = db.transaction(["filesystem"], "readonly"); const objectStore = transaction.objectStore("filesystem"); - const object = await promisifyIDBRequest(objectStore.get(["mods.txt"])); + const object = await promisifyIDBRequest(objectStore.get("mods.txt")); const decoder = new TextDecoder("utf-8"); - return object ? decoder.decode(object.data).split("|") : []; + return object ? decoder.decode(object).split("|") : []; } async function saveMods(mods) { - const db = await promisifyIDBRequest(indexedDB.open("EF_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({ data: modsBlob }, ["mods.txt"])); + await promisifyIDBRequest(objectStore.put(modsBlob, "mods.txt")); } async function addMod(mod) { const mods = await getMods(); mods.push(mod); await saveMods(mods); + console.log("Mod added: " + mod); } async function removeMod(index) { @@ -35,11 +54,15 @@ async function removeMod(index) { if (index >= 0 && index < mods.length) { const removedMod = 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) { diff --git a/postinit.injector.js b/postinit.injector.js index d06ed4e..1e47220 100644 --- a/postinit.injector.js +++ b/postinit.injector.js @@ -1,6 +1,15 @@ 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. + var startedModLoader = false; + + function startModLoader() { + if (!startedModLoader) { + startedModLoader = true; + modLoader([]); + } + } + ModAPI.hooks._classMap = {}; globalThis.PluginAPI ||= ModAPI; ModAPI.mcinstance ||= {}; @@ -294,7 +303,7 @@ globalThis.modapi_postinit = `(() => { } }; ModAPI.events.newEvent = function newEvent(name, side) { - console.log("[ModAPI] Registered "+side+" event: "+name); + console.log("[ModAPI] Registered " + side + " event: " + name); ModAPI.events.types.push(name); }; @@ -390,6 +399,9 @@ globalThis.modapi_postinit = `(() => { //args[0] means $this (ie: minecraft instance). ModAPI.mcinstance = ModAPI.javaClient = args[0]; ModAPI.settings = new Proxy(ModAPI.mcinstance.$gameSettings, TeaVM_to_Recursive_BaseData_ProxyConf); + + startModLoader(); + return x; }; @@ -497,4 +509,33 @@ globalThis.modapi_postinit = `(() => { ModAPI.items = new Proxy(ModAPI.hooks._classMap[ModAPI.util.getCompiledName("net.minecraft.init.Items")].staticVariables, StaticProps_ProxyConf); ModAPI.blocks = new Proxy(ModAPI.hooks._classMap[ModAPI.util.getCompiledName("net.minecraft.init.Blocks")].staticVariables, StaticProps_ProxyConf); + + + 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); + + //NOT A BUG DO NOT FIX + var msg = Math.random() < 0.05 ? "Plugins" : "Mods"; + + // Find the right constructor. (int id, int x, int y, int width, int height, String buttonText); + var btnConstructor = ModAPI.hooks._classMap['nmcg_GuiButton'].constructors.filter(c => {return c.length === 6})[0]; + var btn = btnConstructor(9635329, 0, args[0].$height8 - 21, 100, 20, ModAPI.util.str(msg)); + args[0].$buttonList.$add(btn); + + return x; + } + + const originalOptionsAction = ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.minecraft.client.gui.GuiOptions", "actionPerformed")]; + ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.minecraft.client.gui.GuiOptions", "actionPerformed")] = function (...args) { + if (args[1] && args[1].$id12 === 9635329) { + if (typeof window.modapi_displayModGui === "function") { + window.modapi_displayModGui(); + } else { + alert("[ModAPI] Mod Manager GUI does not exist!") + } + } + var x = originalOptionsAction.apply(this, args); + return x; + } })();`; \ No newline at end of file