From 3dc920c14455372ed9e9894f8b31324afc68219b Mon Sep 17 00:00:00 2001 From: ZXMushroom63 Date: Thu, 29 Aug 2024 18:31:55 +0800 Subject: [PATCH] READY! --- examplemods/timescale_command.js | 5 +- injector.html | 380 +++++++++++++++++++++---------- postinit.js | 231 ++++++++++++------- 3 files changed, 418 insertions(+), 198 deletions(-) diff --git a/examplemods/timescale_command.js b/examplemods/timescale_command.js index 2839eec..4e45e37 100644 --- a/examplemods/timescale_command.js +++ b/examplemods/timescale_command.js @@ -12,13 +12,13 @@ } PluginAPI.javaClient.$timer.$timerSpeed = speed; } - PluginAPI.displayToChat("[Timescale] Set world timescale to " + speed + "."); + PluginAPI.displayToChat("[Timescale] Set world timescale to " + speed.toFixed(2) + "."); } }); PluginAPI.dedicatedServer.appendCode(function () { globalThis.timeScale = 1n; globalThis.timeScaleDividing = false; - PluginAPI.addEventListener("handleslashcommand", (event) => { + PluginAPI.addEventListener("processcommand", (event) => { if (event.command.toLowerCase().startsWith("/timescale")) { var speed = parseFloat(event.command.split(" ")[1]); if (!speed) { @@ -45,5 +45,4 @@ } }; }); - })(); \ No newline at end of file diff --git a/injector.html b/injector.html index ec3c62b..c2c59e1 100644 --- a/injector.html +++ b/injector.html @@ -26,8 +26,7 @@

EaglerForge Injector

Adds ModAPI with more functionality (adds hooking into functions, exposes - all classes, etc) to unminified unobfuscated EaglercraftX - builds. + all classes, etc) to unminified unobfuscated EaglercraftX builds.




@@ -208,7 +207,7 @@ ModAPI.hooks._postInit ||= ()=>{}; ModAPI.hooks._rippedStaticProperties ||= {}; ModAPI.hooks._rippedStaticIndexer ||= {}; `; -var freezeCallstack = `if(ModAPI.hooks.freezeCallstack){return false};`; + var freezeCallstack = `if(ModAPI.hooks.freezeCallstack){return false};`; document.querySelector("#giveme").addEventListener("click", () => { if ( !document.querySelector("input").files || @@ -248,17 +247,29 @@ var main;(function(){` /*/EaglerForge Client Patch/*/` ); - patchedFile = patchedFile.replaceAll(`return thread != null && thread.isResuming()`, (match)=>{ - return freezeCallstack + match; - }); + patchedFile = patchedFile.replaceAll( + `return thread != null && thread.isResuming()`, + (match) => { + return freezeCallstack + match; + } + ); - patchedFile = patchedFile.replaceAll(`return thread != null && thread.isSuspending();`, (match)=>{ - return freezeCallstack + match; - }); + patchedFile = patchedFile.replaceAll( + `return thread != null && thread.isSuspending();`, + (match) => { + return freezeCallstack + match; + } + ); - patchedFile = patchedFile.replaceAll(`return $rt_currentNativeThread;`, (match)=>{ - return `if(ModAPI.hooks.freezeCallstack){return {push: (a)=>{console.log("Data pushed to stack: ") + a}, pop: ()=>{console.warn("Frozen stack was popped, context is now unstable.")}}};` + match; - }); + patchedFile = patchedFile.replaceAll( + `return $rt_currentNativeThread;`, + (match) => { + return ( + `if(ModAPI.hooks.freezeCallstack){return {push: (a)=>{console.log("Data pushed to stack: ") + a}, pop: ()=>{console.warn("Frozen stack was popped, context is now unstable.")}}};` + + match + ); + } + ); patchedFile = patchedFile.replace( ` id="game_frame">`, @@ -302,9 +313,7 @@ var main;(function(){` return ModAPI.hooks.methods[\`${fullName}\`].apply(this, args); } ModAPI.hooks._rippedMethodTypeMap[\`${fullName}\`] = \`${ - match.endsWith("($this") - ? "instance" - : "static" + match.endsWith("($this") ? "instance" : "static" }\`; ModAPI.hooks.methods[\`${fullName}\`]=` + match.replace(fullName + "(", "(") @@ -312,41 +321,68 @@ var main;(function(){` return match; } ); - var staticVariables = [...patchedFile.matchAll(/var \S+?_\S+?_\S+? = null;/gm)].flatMap(x => {return x[0]}); + var staticVariables = [ + ...patchedFile.matchAll(/var \S+?_\S+?_\S+? = null;/gm), + ].flatMap((x) => { + return x[0]; + }); //Todo: add support for static properties on classes with constructors like this: function nmcg_GuiMainMenu() { - patchedFile = patchedFile.replaceAll(/var \S+?_\S+? = \$rt_classWithoutFields\(\S*?\);/gm, function (match) { - var prefix = match.replaceAll(/ = \$rt_classWithoutFields\(\S*?\);/gm, ""); - var entries = []; - staticVariables.forEach(entry => { - if (entry.startsWith(prefix)) { - var variableName = entry.replace("var ", "").replace(" = null;", ""); - var segments = variableName.split("_"); - segments.splice(0, 2); - var name = segments.join("_"); - entries.push({ - "name": name, - "variable": variableName, - }); - } - }); - var getComponents = ""; - entries.forEach(entry => { - getComponents+= ` + patchedFile = patchedFile.replaceAll( + /var \S+?_\S+? = \$rt_classWithoutFields\(\S*?\);/gm, + function (match) { + var prefix = match.replaceAll( + / = \$rt_classWithoutFields\(\S*?\);/gm, + "" + ); + var entries = []; + staticVariables.forEach((entry) => { + if (entry.startsWith(prefix)) { + var variableName = entry + .replace("var ", "") + .replace(" = null;", ""); + var segments = variableName.split("_"); + segments.splice(0, 2); + var name = segments.join("_"); + entries.push({ + name: name, + variable: variableName, + }); + } + }); + var getComponents = ""; + entries.forEach((entry) => { + getComponents += ` case \`${entry.name}\`: return ${entry.variable}; - break;` - }); + break;`; + }); - var setComponents = ""; - entries.forEach(entry => { - setComponents+= ` + var setComponents = ""; + entries.forEach((entry) => { + setComponents += ` case \`${entry.name}\`: ${entry.variable} = c; break;`; - }); - var proxy = ` - ModAPI.hooks._rippedStaticIndexer[\`${prefix.replace("var ", "")}\`] = [${entries.flatMap((x)=>{return "\"" + x.name + "\""}).join(",")}]; - ModAPI.hooks._rippedStaticProperties[\`${prefix.replace("var ", "")}\`] = new Proxy({}, { + }); + var proxy = ` + ModAPI.hooks._rippedStaticIndexer[\`${prefix.replace( + "var ", + "" + )}\`] = [${entries + .flatMap((x) => { + return '"' + x.name + '"'; + }) + .join(",")}]; + ModAPI.hooks._rippedStaticProperties[\`${prefix.replace( + "var ", + "" + )}\`] = new Proxy({${ + entries + .flatMap((x) => { + return '"' + x.name + '"'; + }) + .join(":null,") + (entries.length > 0 ? ":null" : "") + }}, { get: function (a,b,c) { switch (b) { ${getComponents} @@ -359,13 +395,19 @@ var main;(function(){` } });`; return match + proxy; - }); - patchedFile = patchedFile.replaceAll(/function \$rt_\S+?\(/gm, (match)=>{ - var name = match.replace("function ", ""); - name = name.substring(0, name.length - 1); - return `ModAPI.hooks._teavm[\`${name}\`]=${name}; - ` + match; - }); + } + ); + patchedFile = patchedFile.replaceAll( + /function \$rt_\S+?\(/gm, + (match) => { + var name = match.replace("function ", ""); + name = name.substring(0, name.length - 1); + return ( + `ModAPI.hooks._teavm[\`${name}\`]=${name}; + ` + match + ); + } + ); patchedFile = patchedFile.replaceAll(/main\(\);\s*?}/gm, (match) => { return match.replace("main();", "main();ModAPI.hooks._postInit();"); }); @@ -411,7 +453,7 @@ var main;(function(){` name += "_" + methodName; return name; } - ModAPI.util.getCompiledNameFromPackage = function (classId) { + ModAPI.util.getCompiledNameFromPackage = ModAPI.util.getCompiledName = function (classId) { var name = ""; var classStuff = classId.split("."); classStuff.forEach((component, i) => { @@ -425,75 +467,106 @@ var main;(function(){` } ModAPI.version = "v2.0"; ModAPI.flavour = "injector"; + ModAPI.GNU = "terry pratchett"; ModAPI.credits = ["ZXMushroom63", "radmanplays", "OtterCodes101", "TheIdiotPlays"]; ModAPI.hooks.regenerateClassMap = function () { ModAPI.hooks._rippedConstructorKeys = Object.keys(ModAPI.hooks._rippedConstructors); ModAPI.hooks._rippedMethodKeys = Object.keys(ModAPI.hooks._rippedMethodTypeMap); + + var compiledNames = new Set(); + var metaMap = {}; + + //Loop through ripped metadata passes. Classes obtained through this method have full metadata (superclasses, full names, binary names, actual class) ModAPI.hooks._rippedData.forEach(block => { block.forEach(item => { if (typeof item === "function") { if (!item.$meta || typeof item.$meta.name !== "string") { return; } - - var classId = item.$meta.name; - var compiledName = ModAPI.util.getCompiledNameFromPackage(classId); - - - if (!ModAPI.hooks._classMap[classId]) { - ModAPI.hooks._classMap[classId] = { - "name": classId.split(".")[classId.split(".").length - 1], - "id": classId, - "binaryName": item.$meta.binaryName, - "constructors": [], - "methods": {}, - "staticMethods": {}, - "staticVariables": {}, - "staticVariableNames": [], - "class": item, - "compiledName": compiledName - } - } - if (typeof item.$meta.superclass === "function" && item.$meta.superclass.$meta) { - ModAPI.hooks._classMap[classId].superclass = item.$meta.superclass.$meta.name; - } - ModAPI.hooks._classMap[classId].staticVariableNames = ModAPI.hooks._rippedStaticIndexer[compiledName]; - ModAPI.hooks._classMap[classId].staticVariables = ModAPI.hooks._rippedStaticProperties[compiledName]; - if (item["$$constructor$$"]) { - //Class does not have any hand written constructors - //Eg: class MyClass {} - ModAPI.hooks._classMap[classId].constructors.push(item["$$constructor$$"]); - } else { - //Class has hand written constructors, we need to search in the stash - ModAPI.hooks._rippedConstructorKeys.forEach(constructor => { - if (constructor.startsWith(compiledName + "__init_") && !constructor.includes("$lambda$")) { - ModAPI.hooks._classMap[classId].constructors.push(ModAPI.hooks._rippedConstructors[constructor]); - } - }); - } - ModAPI.hooks._rippedMethodKeys.forEach((method) => { - if (method.startsWith(compiledName + "_") && !method.includes("$lambda$")) { - var targetMethodMap = ModAPI.hooks._classMap[classId].methods; - if (ModAPI.hooks._rippedMethodTypeMap[method] === "static") { - targetMethodMap = ModAPI.hooks._classMap[classId].staticMethods; - } - targetMethodMap[method.replace(compiledName + "_", "")] = { - method: ModAPI.hooks.methods[method], - proxiedMethod: function (...args) { - return ModAPI.hooks.methods[method].apply(this, args); - }, - methodName: method - }; - } - }); + var compiledName = ModAPI.util.getCompiledNameFromPackage(item.$meta.name); + compiledNames.add(compiledName); + metaMap[compiledName] = item; } }); }); + + ModAPI.hooks._rippedConstructorKeys.forEach(constructor => { + if (typeof constructor === "string" && constructor.length > 0) { + //Constructor names are phrased as aaa_Apple__init_3 or similar, the separator is __init_ + var constructorData = constructor.split("__init_"); + if (constructorData[0] && constructorData[0].includes("_")) { + compiledNames.add(constructorData[0]); + } + } + }); + + + //Initialise all compiled names into the class map + compiledNames.forEach(compiledName => { + var item = metaMap[compiledName]; + var classId = item?.$meta?.name || null; + + if (!ModAPI.hooks._classMap[compiledName]) { + ModAPI.hooks._classMap[compiledName] = { + "name": compiledName.split("_")[1], + "id": classId, + "binaryName": item?.$meta?.binaryName || null, + "constructors": [], + "methods": {}, + "staticMethods": {}, + "staticVariables": {}, + "staticVariableNames": [], + "class": item || null, + "hasMeta": !!item, + "compiledName": compiledName + } + } + if (typeof item?.$meta?.superclass === "function" && item?.$meta?.superclass?.$meta) { + ModAPI.hooks._classMap[compiledName].superclass = item.$meta.superclass.$meta.name; + } else { + ModAPI.hooks._classMap[compiledName].superclass = null; + } + ModAPI.hooks._classMap[compiledName].staticVariableNames = ModAPI.hooks._rippedStaticIndexer[compiledName]; + ModAPI.hooks._classMap[compiledName].staticVariables = ModAPI.hooks._rippedStaticProperties[compiledName]; + if (item?.["$$constructor$$"]) { + //Class does not have any hand written constructors + //Eg: class MyClass {} + ModAPI.hooks._classMap[compiledName].constructors.push(item["$$constructor$$"]); + } else { + //Class has hand written constructors, we need to search in the stash + ModAPI.hooks._rippedConstructorKeys.forEach(constructor => { + if (constructor.startsWith(compiledName + "__init_") && !constructor.includes("$lambda$")) { + ModAPI.hooks._classMap[compiledName].constructors.push(ModAPI.hooks._rippedConstructors[constructor]); + } + }); + } + ModAPI.hooks._rippedMethodKeys.forEach((method) => { + if (method.startsWith(compiledName + "_") && !method.includes("$lambda$")) { + var targetMethodMap = ModAPI.hooks._classMap[compiledName].methods; + if (ModAPI.hooks._rippedMethodTypeMap[method] === "static") { + targetMethodMap = ModAPI.hooks._classMap[compiledName].staticMethods; + } + targetMethodMap[method.replace(compiledName + "_", "")] = { + method: ModAPI.hooks.methods[method], + proxiedMethod: function (...args) { + return ModAPI.hooks.methods[method].apply(this, args); + }, + methodName: method + }; + } + }); + }); + console.log("[ModAPI] Regenerated hook classmap."); } ModAPI.hooks.regenerateClassMap(); var reloadDeprecationWarnings = 0; const TeaVM_to_BaseData_ProxyConf = { get(target, prop, receiver) { + if (prop === "getRef") { + return function () { + return target; + } + } if (prop === "reload") { return function () { if (reloadDeprecationWarnings < 10) { @@ -527,6 +600,11 @@ var main;(function(){` if (outputValue && typeof outputValue === "object" && !Array.isArray(outputValue)) { return new Proxy(outputValue, TeaVM_to_Recursive_BaseData_ProxyConf); } + if (prop === "getRef") { + return function () { + return target; + } + } return outputValue; }, set(object, prop, value) { @@ -536,6 +614,11 @@ var main;(function(){` } const TeaVM_to_Recursive_BaseData_ProxyConf = { get(target, prop, receiver) { + if (prop === "getRef") { + return function () { + return target; + } + } if (prop === "reload") { return function () { if (reloadDeprecationWarnings < 10) { @@ -566,25 +649,44 @@ var main;(function(){` return true; }, }; + const StaticProps_ProxyConf = { + get(target, prop, receiver) { + var outProp = prop; + var outputValue = Reflect.get(target, outProp, receiver); + if (outputValue && typeof outputValue === "object" && Array.isArray(outputValue.data) && typeof outputValue.type === "function") { + return new Proxy(outputValue.data, TeaVMArray_To_Recursive_BaseData_ProxyConf); + } + if (outputValue && typeof outputValue === "object" && !Array.isArray(outputValue)) { + return new Proxy(outputValue, TeaVM_to_Recursive_BaseData_ProxyConf); + } + return outputValue; + }, + set(object, prop, value) { + var outProp = prop; + object[outProp] = value; + return true; + }, + }; ModAPI.util.TeaVM_to_BaseData_ProxyConf = TeaVM_to_BaseData_ProxyConf; ModAPI.util.TeaVMArray_To_Recursive_BaseData_ProxyConf = TeaVMArray_To_Recursive_BaseData_ProxyConf; ModAPI.util.TeaVM_to_Recursive_BaseData_ProxyConf = TeaVM_to_Recursive_BaseData_ProxyConf; + ModAPI.util.StaticProps_ProxyConf = StaticProps_ProxyConf; ModAPI.required = new Set(); ModAPI.events = {}; ModAPI.events.types = ["event"]; ModAPI.events.listeners = { "event": [] }; ModAPI.addEventListener = function addEventListener(name, callback) { - if (!callback) { - throw new Error("Invalid callback!"); + if (!callback || typeof callback !== "function") { + throw new Error("[ModAPI] Invalid callback!"); } if (ModAPI.events.types.includes(name)) { if (!Array.isArray(ModAPI.events.listeners[name])) { ModAPI.events.listeners[name] = []; } ModAPI.events.listeners[name].push(callback); - console.log("Added new event listener."); + console.log("[ModAPI] Added new event listener."); } else { - throw new Error("This event does not exist!"); + throw new Error("[ModAPI] This event does not exist!"); } }; @@ -599,19 +701,20 @@ var main;(function(){` if (!slow) { if (targetArr.indexOf(func) !== -1) { targetArr.splice(targetArr.indexOf(func), 1); - console.log("Removed event listener."); + console.log("[ModAPI] Removed event listener."); } } else { var functionString = func.toString(); targetArr.forEach((f, i) => { if (f.toString() === functionString) { targetArr.splice(i, 1); - console.log("Removed event listener."); + console.log("[ModAPI] Removed event listener."); } }); } }; - ModAPI.events.newEvent = function newEvent(name) { + ModAPI.events.newEvent = function newEvent(name, side) { + console.log("[ModAPI] Registered "+side+" event: "+name); ModAPI.events.types.push(name); }; @@ -642,8 +745,8 @@ var main;(function(){` func({ event: name, data: data }); }); }; - ModAPI.events.newEvent("update"); - + ModAPI.events.newEvent("update", "client"); + ModAPI.require = function (module) { ModAPI.required.add(module); }; @@ -690,7 +793,7 @@ var main;(function(){` var v = typeof param === "object" ? param.msg : (param + ""); v ||= ""; var jclString = ModAPI.util.string(v); - ModAPI.hooks.methods["nmcg_GuiNewChat_printChatMessage"](ModAPI.javaClient.$ingameGUI.$persistantChatGUI, ModAPI.hooks._classMap["net.minecraft.util.ChatComponentText"].constructors[0](jclString)); + ModAPI.hooks.methods["nmcg_GuiNewChat_printChatMessage"](ModAPI.javaClient.$ingameGUI.$persistantChatGUI, ModAPI.hooks._classMap[ModAPI.util.getCompiledName("net.minecraft.util.ChatComponentText")].constructors[0](jclString)); } const updateMethodName = ModAPI.util.getMethodFromPackage("net.minecraft.client.entity.EntityPlayerSP", "onUpdate"); @@ -721,7 +824,7 @@ var main;(function(){` return x; }; - ModAPI.events.newEvent("sendchatmessage"); + ModAPI.events.newEvent("sendchatmessage", "client"); const sendChatMessageMethodName = ModAPI.util.getMethodFromPackage("net.minecraft.client.entity.EntityPlayerSP", "sendChatMessage"); const sendChatMessage = ModAPI.hooks.methods[sendChatMessageMethodName]; ModAPI.hooks.methods[sendChatMessageMethodName] = function ($this, $message) { @@ -739,7 +842,7 @@ var main;(function(){` return sendChatMessage.apply(this, [$this, $message]); } - ModAPI.events.newEvent("tick"); + ModAPI.events.newEvent("tick", "server"); const serverTickMethodName = ModAPI.util.getMethodFromPackage("net.minecraft.server.MinecraftServer", "tick"); const serverTickMethod = ModAPI.hooks.methods[serverTickMethodName]; ModAPI.hooks.methods[serverTickMethodName] = function ($this) { @@ -751,7 +854,7 @@ var main;(function(){` return serverTickMethod.apply(this, [$this]); } - ModAPI.events.newEvent("serverstart"); + ModAPI.events.newEvent("serverstart", "server"); const serverStartMethodName = ModAPI.util.getMethodFromPackage("net.lax1dude.eaglercraft.v1_8.sp.server.EaglerMinecraftServer", "startServer"); const serverStartMethod = ModAPI.hooks.methods[serverStartMethodName]; ModAPI.hooks.methods[serverStartMethodName] = function ($this) { @@ -762,7 +865,7 @@ var main;(function(){` return x; } - ModAPI.events.newEvent("serverstop"); + ModAPI.events.newEvent("serverstop", "server"); const serverStopMethodName = ModAPI.util.getMethodFromPackage("net.minecraft.server.MinecraftServer", "stopServer"); const serverStopMethod = ModAPI.hooks.methods[serverStopMethodName]; ModAPI.hooks.methods[serverStopMethodName] = function ($this) { @@ -771,11 +874,52 @@ var main;(function(){` ModAPI.events.callEvent("serverstop", {}); return x; } + + ModAPI.events.newEvent("receivechatmessage", "server"); + const receiveChatMessageMethodName = ModAPI.util.getMethodFromPackage("net.minecraft.network.play.client.C01PacketChatMessage", "processPacket"); + const receiveChatMessageMethod = ModAPI.hooks.methods[receiveChatMessageMethodName]; + ModAPI.hooks.methods[receiveChatMessageMethodName] = function (...args) { + var $this = args[0]; + var data = { + preventDefault: false, + message: ModAPI.util.jclStrToJsStr($this.$message3) + } + ModAPI.events.callEvent("sendchatmessage", data); + if (data.preventDefault) { + return; + } + if (typeof data.message === "string") { + ModAPI.util.setStringContent($this.$message3, data.message) + } + var x = receiveChatMessageMethod.apply(this, args); + return x; + } + + ModAPI.events.newEvent("processcommand", "server"); + const processCommandMethodName = ModAPI.util.getMethodFromPackage("net.minecraft.command.CommandHandler", "executeCommand"); + const processCommandMethod = ModAPI.hooks.methods[processCommandMethodName]; + ModAPI.hooks.methods[processCommandMethodName] = function ($this, $sender, $rawCommand) { + var data = { + preventDefault: false, + sender: new Proxy($sender, TeaVM_to_Recursive_BaseData_ProxyConf), + command: ModAPI.util.jclStrToJsStr($rawCommand) + } + ModAPI.events.callEvent("processcommand", data); + if (data.preventDefault) { + return; + } + if (typeof data.command === "string") { + ModAPI.util.setStringContent($rawCommand, data.command) + } + var x = processCommandMethod.apply(this, [$this, $sender, $rawCommand]); + return x; + } + + 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); })();`; - - diff --git a/postinit.js b/postinit.js index 0bd49a2..c3d3ae9 100644 --- a/postinit.js +++ b/postinit.js @@ -33,7 +33,7 @@ name += "_" + methodName; return name; } - ModAPI.util.getCompiledNameFromPackage = function (classId) { + ModAPI.util.getCompiledNameFromPackage = ModAPI.util.getCompiledName = function (classId) { var name = ""; var classStuff = classId.split("."); classStuff.forEach((component, i) => { @@ -47,70 +47,96 @@ } ModAPI.version = "v2.0"; ModAPI.flavour = "injector"; + ModAPI.GNU = "terry pratchett"; ModAPI.credits = ["ZXMushroom63", "radmanplays", "OtterCodes101", "TheIdiotPlays"]; ModAPI.hooks.regenerateClassMap = function () { ModAPI.hooks._rippedConstructorKeys = Object.keys(ModAPI.hooks._rippedConstructors); ModAPI.hooks._rippedMethodKeys = Object.keys(ModAPI.hooks._rippedMethodTypeMap); + + var compiledNames = new Set(); + var metaMap = {}; + + //Loop through ripped metadata passes. Classes obtained through this method have full metadata (superclasses, full names, binary names, actual class) ModAPI.hooks._rippedData.forEach(block => { block.forEach(item => { if (typeof item === "function") { if (!item.$meta || typeof item.$meta.name !== "string") { return; } - - var classId = item.$meta.name; - var compiledName = ModAPI.util.getCompiledNameFromPackage(classId); - - - if (!ModAPI.hooks._classMap[classId]) { - ModAPI.hooks._classMap[classId] = { - "name": classId.split(".")[classId.split(".").length - 1], - "id": classId, - "binaryName": item.$meta.binaryName, - "constructors": [], - "methods": {}, - "staticMethods": {}, - "staticVariables": {}, - "staticVariableNames": [], - "class": item, - "compiledName": compiledName - } - } - if (typeof item.$meta.superclass === "function" && item.$meta.superclass.$meta) { - ModAPI.hooks._classMap[classId].superclass = item.$meta.superclass.$meta.name; - } - ModAPI.hooks._classMap[classId].staticVariableNames = ModAPI.hooks._rippedStaticIndexer[compiledName]; - ModAPI.hooks._classMap[classId].staticVariables = ModAPI.hooks._rippedStaticProperties[compiledName]; - if (item["$$constructor$$"]) { - //Class does not have any hand written constructors - //Eg: class MyClass {} - ModAPI.hooks._classMap[classId].constructors.push(item["$$constructor$$"]); - } else { - //Class has hand written constructors, we need to search in the stash - ModAPI.hooks._rippedConstructorKeys.forEach(constructor => { - if (constructor.startsWith(compiledName + "__init_") && !constructor.includes("$lambda$")) { - ModAPI.hooks._classMap[classId].constructors.push(ModAPI.hooks._rippedConstructors[constructor]); - } - }); - } - ModAPI.hooks._rippedMethodKeys.forEach((method) => { - if (method.startsWith(compiledName + "_") && !method.includes("$lambda$")) { - var targetMethodMap = ModAPI.hooks._classMap[classId].methods; - if (ModAPI.hooks._rippedMethodTypeMap[method] === "static") { - targetMethodMap = ModAPI.hooks._classMap[classId].staticMethods; - } - targetMethodMap[method.replace(compiledName + "_", "")] = { - method: ModAPI.hooks.methods[method], - proxiedMethod: function (...args) { - return ModAPI.hooks.methods[method].apply(this, args); - }, - methodName: method - }; - } - }); + var compiledName = ModAPI.util.getCompiledNameFromPackage(item.$meta.name); + compiledNames.add(compiledName); + metaMap[compiledName] = item; } }); }); + + ModAPI.hooks._rippedConstructorKeys.forEach(constructor => { + if (typeof constructor === "string" && constructor.length > 0) { + //Constructor names are phrased as aaa_Apple__init_3 or similar, the separator is __init_ + var constructorData = constructor.split("__init_"); + if (constructorData[0] && constructorData[0].includes("_")) { + compiledNames.add(constructorData[0]); + } + } + }); + + + //Initialise all compiled names into the class map + compiledNames.forEach(compiledName => { + var item = metaMap[compiledName]; + var classId = item?.$meta?.name || null; + + if (!ModAPI.hooks._classMap[compiledName]) { + ModAPI.hooks._classMap[compiledName] = { + "name": compiledName.split("_")[1], + "id": classId, + "binaryName": item?.$meta?.binaryName || null, + "constructors": [], + "methods": {}, + "staticMethods": {}, + "staticVariables": {}, + "staticVariableNames": [], + "class": item || null, + "hasMeta": !!item, + "compiledName": compiledName + } + } + if (typeof item?.$meta?.superclass === "function" && item?.$meta?.superclass?.$meta) { + ModAPI.hooks._classMap[compiledName].superclass = item.$meta.superclass.$meta.name; + } else { + ModAPI.hooks._classMap[compiledName].superclass = null; + } + ModAPI.hooks._classMap[compiledName].staticVariableNames = ModAPI.hooks._rippedStaticIndexer[compiledName]; + ModAPI.hooks._classMap[compiledName].staticVariables = ModAPI.hooks._rippedStaticProperties[compiledName]; + if (item?.["$$constructor$$"]) { + //Class does not have any hand written constructors + //Eg: class MyClass {} + ModAPI.hooks._classMap[compiledName].constructors.push(item["$$constructor$$"]); + } else { + //Class has hand written constructors, we need to search in the stash + ModAPI.hooks._rippedConstructorKeys.forEach(constructor => { + if (constructor.startsWith(compiledName + "__init_") && !constructor.includes("$lambda$")) { + ModAPI.hooks._classMap[compiledName].constructors.push(ModAPI.hooks._rippedConstructors[constructor]); + } + }); + } + ModAPI.hooks._rippedMethodKeys.forEach((method) => { + if (method.startsWith(compiledName + "_") && !method.includes("$lambda$")) { + var targetMethodMap = ModAPI.hooks._classMap[compiledName].methods; + if (ModAPI.hooks._rippedMethodTypeMap[method] === "static") { + targetMethodMap = ModAPI.hooks._classMap[compiledName].staticMethods; + } + targetMethodMap[method.replace(compiledName + "_", "")] = { + method: ModAPI.hooks.methods[method], + proxiedMethod: function (...args) { + return ModAPI.hooks.methods[method].apply(this, args); + }, + methodName: method + }; + } + }); + }); + console.log("[ModAPI] Regenerated hook classmap."); } ModAPI.hooks.regenerateClassMap(); var reloadDeprecationWarnings = 0; @@ -131,9 +157,6 @@ } var outProp = "$" + prop; - if (target["__modapi_noprefix__"]) { - outProp = prop; - } var outputValue = Reflect.get(target, outProp, receiver); if (outputValue && typeof outputValue === "object" && Array.isArray(outputValue.data) && typeof outputValue.type === "function") { return outputValue.data; @@ -147,9 +170,6 @@ }, set(object, prop, value) { var outProp = "$" + prop; - if (target["__modapi_noprefix__"]) { - outProp = prop; - } object[outProp] = value; return true; }, @@ -189,9 +209,6 @@ } var outProp = "$" + prop; - if (target["__modapi_noprefix__"]) { - outProp = prop; - } var outputValue = Reflect.get(target, outProp, receiver); if (outputValue && typeof outputValue === "object" && Array.isArray(outputValue.data) && typeof outputValue.type === "function") { return new Proxy(outputValue.data, TeaVMArray_To_Recursive_BaseData_ProxyConf); @@ -208,9 +225,24 @@ }, set(object, prop, value) { var outProp = "$" + prop; - if (target["__modapi_noprefix__"]) { - outProp = prop; + object[outProp] = value; + return true; + }, + }; + const StaticProps_ProxyConf = { + get(target, prop, receiver) { + var outProp = prop; + var outputValue = Reflect.get(target, outProp, receiver); + if (outputValue && typeof outputValue === "object" && Array.isArray(outputValue.data) && typeof outputValue.type === "function") { + return new Proxy(outputValue.data, TeaVMArray_To_Recursive_BaseData_ProxyConf); } + if (outputValue && typeof outputValue === "object" && !Array.isArray(outputValue)) { + return new Proxy(outputValue, TeaVM_to_Recursive_BaseData_ProxyConf); + } + return outputValue; + }, + set(object, prop, value) { + var outProp = prop; object[outProp] = value; return true; }, @@ -218,22 +250,23 @@ ModAPI.util.TeaVM_to_BaseData_ProxyConf = TeaVM_to_BaseData_ProxyConf; ModAPI.util.TeaVMArray_To_Recursive_BaseData_ProxyConf = TeaVMArray_To_Recursive_BaseData_ProxyConf; ModAPI.util.TeaVM_to_Recursive_BaseData_ProxyConf = TeaVM_to_Recursive_BaseData_ProxyConf; + ModAPI.util.StaticProps_ProxyConf = StaticProps_ProxyConf; ModAPI.required = new Set(); ModAPI.events = {}; ModAPI.events.types = ["event"]; ModAPI.events.listeners = { "event": [] }; ModAPI.addEventListener = function addEventListener(name, callback) { - if (!callback) { - throw new Error("Invalid callback!"); + if (!callback || typeof callback !== "function") { + throw new Error("[ModAPI] Invalid callback!"); } if (ModAPI.events.types.includes(name)) { if (!Array.isArray(ModAPI.events.listeners[name])) { ModAPI.events.listeners[name] = []; } ModAPI.events.listeners[name].push(callback); - console.log("Added new event listener."); + console.log("[ModAPI] Added new event listener."); } else { - throw new Error("This event does not exist!"); + throw new Error("[ModAPI] This event does not exist!"); } }; @@ -248,19 +281,20 @@ if (!slow) { if (targetArr.indexOf(func) !== -1) { targetArr.splice(targetArr.indexOf(func), 1); - console.log("Removed event listener."); + console.log("[ModAPI] Removed event listener."); } } else { var functionString = func.toString(); targetArr.forEach((f, i) => { if (f.toString() === functionString) { targetArr.splice(i, 1); - console.log("Removed event listener."); + console.log("[ModAPI] Removed event listener."); } }); } }; - ModAPI.events.newEvent = function newEvent(name) { + ModAPI.events.newEvent = function newEvent(name, side) { + console.log("[ModAPI] Registered "+side+" event: "+name); ModAPI.events.types.push(name); }; @@ -291,8 +325,8 @@ func({ event: name, data: data }); }); }; - ModAPI.events.newEvent("update"); - + ModAPI.events.newEvent("update", "client"); + ModAPI.require = function (module) { ModAPI.required.add(module); }; @@ -339,7 +373,7 @@ var v = typeof param === "object" ? param.msg : (param + ""); v ||= ""; var jclString = ModAPI.util.string(v); - ModAPI.hooks.methods["nmcg_GuiNewChat_printChatMessage"](ModAPI.javaClient.$ingameGUI.$persistantChatGUI, ModAPI.hooks._classMap["net.minecraft.util.ChatComponentText"].constructors[0](jclString)); + ModAPI.hooks.methods["nmcg_GuiNewChat_printChatMessage"](ModAPI.javaClient.$ingameGUI.$persistantChatGUI, ModAPI.hooks._classMap[ModAPI.util.getCompiledName("net.minecraft.util.ChatComponentText")].constructors[0](jclString)); } const updateMethodName = ModAPI.util.getMethodFromPackage("net.minecraft.client.entity.EntityPlayerSP", "onUpdate"); @@ -370,7 +404,7 @@ return x; }; - ModAPI.events.newEvent("sendchatmessage"); + ModAPI.events.newEvent("sendchatmessage", "client"); const sendChatMessageMethodName = ModAPI.util.getMethodFromPackage("net.minecraft.client.entity.EntityPlayerSP", "sendChatMessage"); const sendChatMessage = ModAPI.hooks.methods[sendChatMessageMethodName]; ModAPI.hooks.methods[sendChatMessageMethodName] = function ($this, $message) { @@ -388,7 +422,7 @@ return sendChatMessage.apply(this, [$this, $message]); } - ModAPI.events.newEvent("tick"); + ModAPI.events.newEvent("tick", "server"); const serverTickMethodName = ModAPI.util.getMethodFromPackage("net.minecraft.server.MinecraftServer", "tick"); const serverTickMethod = ModAPI.hooks.methods[serverTickMethodName]; ModAPI.hooks.methods[serverTickMethodName] = function ($this) { @@ -400,7 +434,7 @@ return serverTickMethod.apply(this, [$this]); } - ModAPI.events.newEvent("serverstart"); + ModAPI.events.newEvent("serverstart", "server"); const serverStartMethodName = ModAPI.util.getMethodFromPackage("net.lax1dude.eaglercraft.v1_8.sp.server.EaglerMinecraftServer", "startServer"); const serverStartMethod = ModAPI.hooks.methods[serverStartMethodName]; ModAPI.hooks.methods[serverStartMethodName] = function ($this) { @@ -411,7 +445,7 @@ return x; } - ModAPI.events.newEvent("serverstop"); + ModAPI.events.newEvent("serverstop", "server"); const serverStopMethodName = ModAPI.util.getMethodFromPackage("net.minecraft.server.MinecraftServer", "stopServer"); const serverStopMethod = ModAPI.hooks.methods[serverStopMethodName]; ModAPI.hooks.methods[serverStopMethodName] = function ($this) { @@ -420,4 +454,47 @@ ModAPI.events.callEvent("serverstop", {}); return x; } + + ModAPI.events.newEvent("receivechatmessage", "server"); + const receiveChatMessageMethodName = ModAPI.util.getMethodFromPackage("net.minecraft.network.play.client.C01PacketChatMessage", "processPacket"); + const receiveChatMessageMethod = ModAPI.hooks.methods[receiveChatMessageMethodName]; + ModAPI.hooks.methods[receiveChatMessageMethodName] = function (...args) { + var $this = args[0]; + var data = { + preventDefault: false, + message: ModAPI.util.jclStrToJsStr($this.$message3) + } + ModAPI.events.callEvent("sendchatmessage", data); + if (data.preventDefault) { + return; + } + if (typeof data.message === "string") { + ModAPI.util.setStringContent($this.$message3, data.message) + } + var x = receiveChatMessageMethod.apply(this, args); + return x; + } + + ModAPI.events.newEvent("processcommand", "server"); + const processCommandMethodName = ModAPI.util.getMethodFromPackage("net.minecraft.command.CommandHandler", "executeCommand"); + const processCommandMethod = ModAPI.hooks.methods[processCommandMethodName]; + ModAPI.hooks.methods[processCommandMethodName] = function ($this, $sender, $rawCommand) { + var data = { + preventDefault: false, + sender: new Proxy($sender, TeaVM_to_Recursive_BaseData_ProxyConf), + command: ModAPI.util.jclStrToJsStr($rawCommand) + } + ModAPI.events.callEvent("processcommand", data); + if (data.preventDefault) { + return; + } + if (typeof data.command === "string") { + ModAPI.util.setStringContent($rawCommand, data.command) + } + var x = processCommandMethod.apply(this, [$this, $sender, $rawCommand]); + return x; + } + + 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); })(); \ No newline at end of file