From 42a0f3e148d9c331f0718fddaf2aa62aa7232767 Mon Sep 17 00:00:00 2001 From: ZXMushroom63 Date: Sun, 26 Jan 2025 19:30:47 +0800 Subject: [PATCH] add interfaces and implements --- docs/apidoc/reflect.md | 3 +++ index.html | 1 + injector.js | 35 ++++++++++++++++++++--------------- postinit.js | 21 +++++++++++++++++++-- 4 files changed, 43 insertions(+), 17 deletions(-) diff --git a/docs/apidoc/reflect.md b/docs/apidoc/reflect.md index c6b2770..08e0580 100644 --- a/docs/apidoc/reflect.md +++ b/docs/apidoc/reflect.md @@ -24,6 +24,9 @@ Methods: - Copies methods from a reflect class and it's parents onto a target native JavaScript class. This allows TeaVM to use these objects normally, without you having to manually reimplement every method. In other words, this is the equivalent of extending a class. - Also adds some metadata to make the class work with `ModAPI.util.asClass` - [Example usage](https://github.com/eaglerforge/EaglerForgeInjector/blob/6e8598c180f96a65c0c101be72e6d0fa53195404/examplemods/unlucky_blocks.js#L37) +- `ModAPI.reflect.implements(target: Class/ConstructorFunction, interface: ReflectClass)` + - Marks the provided interface as a supertype of the target class. + - JavaScript equivalent of the `implements` keyword ### ReflectClass Definition Each `ReflectClass` has the following properties: diff --git a/index.html b/index.html index ffbb2b7..6032025 100644 --- a/index.html +++ b/index.html @@ -151,6 +151,7 @@ ModAPI.hooks ||= {}; ModAPI.hooks.freezeCallstack = false; ModAPI.hooks._rippedData ||= []; + ModAPI.hooks._rippedInterfaceMap ||= {}; ModAPI.hooks._teavm ||= {}; ModAPI.hooks._rippedConstructors ||= {}; ModAPI.hooks._rippedInternalConstructors ||= {}; diff --git a/injector.js b/injector.js index 7048e86..386e80b 100644 --- a/injector.js +++ b/injector.js @@ -50,13 +50,13 @@ function entriesToStaticVariableProxy(entries, prefix, clinitList) { .join(",")}]; /*/ var proxy = `ModAPI.hooks._rippedStaticProperties[\`${prefix.replace( - "var ", - "" - )}\`] = new Proxy({${entries - .flatMap((x) => { - return '"' + x.name + '"'; - }) - .join(":null,") + (entries.length > 0 ? ":null" : "") + "var ", + "" + )}\`] = new Proxy({${entries + .flatMap((x) => { + return '"' + x.name + '"'; + }) + .join(":null,") + (entries.length > 0 ? ":null" : "") }}, { get: function (a,b,c) { switch (b) { @@ -136,7 +136,7 @@ var main;(function(){` patchedFile = patchedFile.replaceAll("function TeaVMThread(", "globalThis.ModAPI.hooks.TeaVMThread = TeaVMThread;\nfunction TeaVMThread("); _status("Getting clinit list..."); - var clinitList = [...patchedFile.matchAll(/^[\t ]*function \S+?_\S+?_\$callClinit\(/gm)].map(x=>x[0].replaceAll("function ", "").replaceAll("(", "").trim()); + var clinitList = [...patchedFile.matchAll(/^[\t ]*function \S+?_\S+?_\$callClinit\(/gm)].map(x => x[0].replaceAll("function ", "").replaceAll("(", "").trim()); console.log(clinitList); _status("Extracting constructors and methods..."); @@ -171,7 +171,7 @@ var main;(function(){` ); } ); - + const extractInstanceMethodRegex = /^[\t ]*function \S+?_\S+?_\S+?\((\$this)?/gm; // /^[\t ]*function \S+?_\S+?_\S+?\(\$this/gm const extractInstanceMethodFullNameRegex = /function (\S*?)\(/gm; // /function (\S*?)\(\$this/gm @@ -205,6 +205,7 @@ var main;(function(){` }).filter(x => { return (!x.includes("$_clinit_$")) && (!x.includes("$lambda$")) }); + //Also stores classes from $rt_classWithoutFields(0) patchedFile = patchedFile.replaceAll( /var \S+?_\S+? = \$rt_classWithoutFields\(\S*?\);/gm, function (match) { @@ -213,6 +214,7 @@ var main;(function(){` "" ); var entries = []; + staticVariables.forEach((entry) => { if (entry.startsWith(prefix)) { var variableName = entry @@ -229,14 +231,17 @@ var main;(function(){` }); var proxy = entriesToStaticVariableProxy(entries, prefix, clinitList); - - return match + proxy; + var shortPrefix = prefix.replace( + "var ", + "" + ); + return match + `ModAPI.hooks._rippedInterfaceMap[\`${shortPrefix}\`]=${shortPrefix};` + proxy; } ); //Edge cases. sigh //Done: add support for static properties on classes with constructors like this: function nmcg_GuiMainMenu() { - + patchedFile = patchedFile.replaceAll( /function [a-z]+?_([a-zA-Z0-9\$]+?)\(\) \{/gm, (match) => { @@ -335,7 +340,7 @@ document.querySelector("#giveme").addEventListener("click", () => { } else if (globalThis.doShronk) { patchedFile = await shronk(patchedFile); } - + patchedFile.replace(`{"._|_libserverside_|_."}`, ""); var blob = new Blob([patchedFile], { type: file.type }); saveAs(blob, "processed." + fileType); @@ -356,13 +361,13 @@ document.querySelector("#givemeserver").addEventListener("click", () => { file.text().then(async (string) => { var patchedFile = string; - + if (globalThis.doEaglerforge) { patchedFile = await processClasses(patchedFile); } else if (globalThis.doShronk) { patchedFile = await shronk(patchedFile); } - + patchedFile.replace(`{"._|_libserverside_|_."}`, `(${EFServer.toString()})()`); var blob = new Blob([patchedFile], { type: file.type }); saveAs(blob, "efserver." + fileType); diff --git a/postinit.js b/postinit.js index 6a0cab4..5a6c38b 100644 --- a/postinit.js +++ b/postinit.js @@ -269,6 +269,7 @@ globalThis.modapi_postinit = "(" + (() => { ModAPI.hooks._rippedConstructorKeys = Object.keys(ModAPI.hooks._rippedConstructors); ModAPI.hooks._rippedInternalConstructorKeys = Object.keys(ModAPI.hooks._rippedInternalConstructors); ModAPI.hooks._rippedMethodKeys = Object.keys(ModAPI.hooks._rippedMethodTypeMap); + ModAPI.hooks._rippedInterfaceKeys = Object.keys(ModAPI.hooks._rippedInterfaceMap); var compiledNames = new Set(); var metaMap = {}; @@ -302,10 +303,19 @@ globalThis.modapi_postinit = "(" + (() => { } }); + ModAPI.hooks._rippedInterfaceKeys.forEach(className => { + if (typeof className === "string" && className.length > 0) { + //Interfaces using $rt_classWithoutFields(0) and no constructors. + if (className && className.includes("_")) { + compiledNames.add(className); + } + } + }); + //Initialise all compiled names into the class map compiledNames.forEach(compiledName => { - var item = metaMap[compiledName]; + var item = metaMap[compiledName] || ModAPI.hooks._rippedInterfaceMap[compiledName]; var classId = item?.$meta?.name || null; if (!ModAPI.hooks._classMap[compiledName]) { @@ -321,7 +331,7 @@ globalThis.modapi_postinit = "(" + (() => { "staticVariables": {}, "staticVariableNames": [], "class": item || null, - "hasMeta": !!item, + "hasMeta": !!(item?.$meta), "instanceOf": function (object) { try { return ModAPI.hooks._teavm.$rt_isInstance(object, item || null); @@ -431,6 +441,13 @@ globalThis.modapi_postinit = "(" + (() => { }; classFn.classObject = null; } + ModAPI.reflect.implements = function implements(classFn, reflectClass) { + classFn.$meta ||= {}; + classFn.$meta.supertypes ||= []; + if (reflectClass && reflectClass.class) { + classFn.$meta.supertypes.push(reflectClass.class); + } + } var reloadDeprecationWarnings = 0; const TeaVMArray_To_Recursive_BaseData_ProxyConf = {