add interfaces and implements

This commit is contained in:
ZXMushroom63 2025-01-26 19:30:47 +08:00
parent bd4b5b9d39
commit 42a0f3e148
4 changed files with 43 additions and 17 deletions

View File

@ -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:

View File

@ -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 ||= {};

View File

@ -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...");
@ -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,8 +231,11 @@ 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

View File

@ -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 = {