Merge pull request #27 from ZXMushroom63/main

Update NoReflect to add Render API
This commit is contained in:
Oliver Anderson 2024-05-31 18:05:38 -06:00 committed by GitHub
commit 588b2da356
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 387 additions and 45 deletions

214
ExampleMods/tracers.js Normal file
View File

@ -0,0 +1,214 @@
//Tracer hack w/ NoReflect
ModAPI.require("player");
//init function
function initTracers() {
//Get necessary classes and store them
const classes = {
EntityPlayerSP: ModAPI.reflect.getClassByName("EntityPlayerSP"),
EntityPlayer: ModAPI.reflect.getClassByName("EntityPlayer"),
EntityItem: ModAPI.reflect.getClassByName("EntityItem"),
EntityAnimal: ModAPI.reflect.getClassByName("EntityAnimal"),
EntityMob: ModAPI.reflect.getClassByName("EntityMob"),
GlStateManager: ModAPI.reflect.getClassByName("GlStateManager"),
EaglercraftGPU: ModAPI.reflect.getClassByName("EaglercraftGPU"),
MathHelper: ModAPI.reflect.getClassByName("MathHelper"),
EntityRenderer: ModAPI.reflect.getClassByName("EntityRenderer"),
Tessellator: ModAPI.reflect.getClassByName("Tessellator"),
WorldRenderer: ModAPI.reflect.getClassByName("WorldRenderer")
};
//Get the vertex format for 'POSITION'
const positionVertexFormat = ModAPI.reflect.getClassByName("VertexFormat").class.$platformClass.$$enumConstants$$().data[5];
//Utility functions for type checking
function isEntityPlayerSP(obj) {
return classes.EntityPlayerSP.isObjInstanceOf({ obj: obj });
}
function isEntityPlayer(obj) {
return classes.EntityPlayer.isObjInstanceOf({ obj: obj });
}
function isEntityItem(obj) {
return classes.EntityItem.isObjInstanceOf({ obj: obj });
}
function isEntityAnimal(obj) {
return classes.EntityAnimal.isObjInstanceOf({ obj: obj });
}
function isEntityMob(obj) {
return classes.EntityMob.isObjInstanceOf({ obj: obj });
}
//Utility functions for running methods on classes/instances of classes
function glFunction(name, args) {
return classes.GlStateManager.methods.filter((method) => {
return method.methodName === name
})[0].exec(args);
}
function gpuFunction(name, args) {
return classes.EaglercraftGPU.methods.filter((method) => {
return method.methodName === name
})[0].exec(args);
}
function entityRendererFunction(name, args) {
return classes.EntityRenderer.methods.filter((method) => {
return method.methodName === name
})[0].exec(args);
}
function mathHelperFunction(name, args) {
return classes.MathHelper.methods.filter((method) => {
return method.methodName === name
})[0].exec(args);
}
function tessellatorFunction(name, args) {
return classes.Tessellator.methods.filter((method) => {
return method.methodName === name
})[0].exec(args);
}
function worldRendererFunction(name, args) {
return classes.WorldRenderer.methods.filter((method) => {
return method.methodName === name
})[0].exec(args);
}
//Function to get the player's look vector (position right in front of their nose)
function getClientLookVec() {
var f = mathHelperFunction("cos", {value: -ModAPI.player.rotationYaw * 0.017453292 - Math.PI});
var f1 = mathHelperFunction("sin", {parFloat1: -ModAPI.player.rotationYaw * 0.017453292 - Math.PI});
var f2 = -mathHelperFunction("cos", {value: -ModAPI.player.rotationPitch * 0.017453292});
var f3 = mathHelperFunction("sin", {parFloat1: -ModAPI.player.rotationPitch * 0.017453292});
return [f1 * f2, f3 + ModAPI.player.getEyeHeight(), f * f2];
}
//Function to draw a line between two poitns
function drawLine(start, end) {
//Get the tessellator by running Tessellator.getInstance()
var tessellator = tessellatorFunction("getInstance", {});
//Get the WorldRenderer instance by running tessellator.getWorldRenderer()
var worldrenderer = tessellatorFunction("getWorldRenderer", {
_self: tessellator
});
//Run worldrenderer.begin(3, positionVertexFormat) to start building the lines
worldRendererFunction("begin", {
_self: worldrenderer,
parInt1: 3,
parVertexFormat: positionVertexFormat
});
//Add the start position and end the vertex immediately.
worldRendererFunction("endVertex", {
_self: worldRendererFunction("pos", {
_self: worldrenderer,
parDouble1: start[0],
parDouble2: start[1],
parDouble3: start[2]
})
});
//Add the start position and end the vertex immediately.
worldRendererFunction("endVertex", {
_self: worldRendererFunction("pos", {
_self: worldrenderer,
parDouble1: end[0],
parDouble2: end[1],
parDouble3: end[2]
})
});
//Draw to screen
tessellatorFunction("draw", {
_self: tessellator
});
}
//Every time a frame is rendered
ModAPI.addEventListener("render", (event) => {
//Check if both the player and the world instance exist
if (ModAPI.player && ModAPI.mcinstance.$theWorld) {
//Store world and render manager
const world = ModAPI.mcinstance.$theWorld;
const renderManager = ModAPI.mcinstance.$renderManager;
//Loop through loaded entities
for (let i = 0; i < world.$loadedEntityList.$array1.data.length; i++) {
const entity = world.$loadedEntityList.$array1.data[i];
//Checks to avoid tracing to self and invalid entities
if (!entity || isEntityPlayerSP(entity)) {
continue;
}
if (!(isEntityAnimal(entity) || isEntityItem(entity) || isEntityMob(entity) || isEntityPlayer(entity))) {
continue;
}
//Temporarily disable view bobbing
var bobbing = ModAPI.mcinstance.$gameSettings.$viewBobbing;
ModAPI.mcinstance.$gameSettings.$viewBobbing = 0;
//Update camera transform to remove view bobbing
entityRendererFunction("setupCameraTransform", {
partialTicks: event.partialTicks,
pass: 0
});
//WebGL commands to disable depth-test & depth-write, as well as selecting a blend function and line width.
glFunction("blendFunc", { srcFactor: 770, dstFactor: 771 });
glFunction("enableBlend", {});
gpuFunction("glLineWidth", { f: 3.0 });
glFunction("disableTexture2D", {});
glFunction("disableDepth", {});
glFunction("depthMask", { flagIn: false });
//Choose tracer color based on entity type.
if (isEntityPlayer(entity)) {
glFunction("color", { colorRed: 1, colorGreen: 0, colorBlue: 0, colorAlpha: 0.5 });
} else if (isEntityAnimal(entity)) {
glFunction("color", { colorRed: 0, colorGreen: 0, colorBlue: 1, colorAlpha: 0.5 });
} else if (isEntityMob(entity)) {
glFunction("color", { colorRed: 1, colorGreen: 1, colorBlue: 0, colorAlpha: 0.5 });
} else if (isEntityItem(entity)) {
glFunction("color", { colorRed: 0, colorGreen: 1, colorBlue: 1, colorAlpha: 0.5 });
}
//Start is equal to the client look vector
var start = getClientLookVec();
//End is equal to the center of the entities' bounding box minus the render position.
var end = [
((entity.$boundingBox.$minX0 + entity.$boundingBox.$maxX0) / 2) - 0.05 - renderManager.$renderPosX,
((entity.$boundingBox.$minY0 + entity.$boundingBox.$maxY0) / 2) - 0.05 - renderManager.$renderPosY,
((entity.$boundingBox.$minZ0 + entity.$boundingBox.$maxZ0) / 2) - 0.05 - renderManager.$renderPosZ
];
//Draw the line
drawLine(start, end);
//Restore the gl state
glFunction("enableTexture2D", {});
glFunction("depthMask", { flagIn: true });
glFunction("enableDepth", {});
glFunction("disableBlend", {});
//Restore view bobbing
ModAPI.mcinstance.$gameSettings.$viewBobbing = bobbing;
entityRendererFunction("setupCameraTransform", {
partialTicks: event.partialTicks,
pass: 0
});
}
}
});
}
initTracers();

View File

@ -1,52 +1,60 @@
const templateClassdef = `
//CLASSDEF FOR %classname%
BaseData reflect_%classname% = new ModData();
//classdef for %classname%
public static void reflect_%classname%_generator(ArrayList<BaseData> reflectProfiles) {
BaseData reflect_%classname% = new ModData();
ArrayList<BaseData> reflect_%classname%_constructors = new ArrayList<BaseData>();
%constructordefs%
BaseData[] reflect_%classname%_constructors_arr = new BaseData[reflect_%classname%_constructors.size()];
for (int i = 0; i < reflect_%classname%_constructors_arr.length; i++) {
reflect_%classname%_constructors_arr[i] = reflect_%classname%_constructors.get(i);
}
ArrayList<BaseData> reflect_%classname%_constructors = new ArrayList<BaseData>();
%constructordefs%
BaseData[] reflect_%classname%_constructors_arr = new BaseData[reflect_%classname%_constructors.size()];
for (int i = 0; i < reflect_%classname%_constructors_arr.length; i++) {
reflect_%classname%_constructors_arr[i] = reflect_%classname%_constructors.get(i);
}
ArrayList<BaseData> reflect_%classname%_methods = new ArrayList<BaseData>();
%methoddefs%
BaseData[] reflect_%classname%_methods_arr = new BaseData[reflect_%classname%_methods.size()];
for (int i = 0; i < reflect_%classname%_methods_arr.length; i++) {
reflect_%classname%_methods_arr[i] = reflect_%classname%_methods.get(i);
}
ArrayList<BaseData> reflect_%classname%_methods = new ArrayList<BaseData>();
%methoddefs%
BaseData[] reflect_%classname%_methods_arr = new BaseData[reflect_%classname%_methods.size()];
for (int i = 0; i < reflect_%classname%_methods_arr.length; i++) {
reflect_%classname%_methods_arr[i] = reflect_%classname%_methods.get(i);
}
reflect_%classname%.set("constructors", reflect_%classname%_constructors_arr);
reflect_%classname%.set("methods", reflect_%classname%_methods_arr);
reflect_%classname%.set("className", "%classname%");
reflect_%classname%.set("classId", "%classid%");
reflect_%classname%.set("class", %classname%.class);
reflectProfiles.add(reflect_%classname%);
reflect_%classname%.set("constructors", reflect_%classname%_constructors_arr);
reflect_%classname%.set("methods", reflect_%classname%_methods_arr);
reflect_%classname%.set("className", "%classname%");
reflect_%classname%.set("classId", "%classid%");
reflect_%classname%.set("class", %classname%.class);
reflect_%classname%.setCallbackBooleanWithDataArg("isObjInstanceOf", (args)->{
return args.getReflective("obj") instanceof %classname%;
});
reflectProfiles.add(reflect_%classname%);
}
`;
//IXCVVIX
//CXVIIVX
//MVVMCXI
const templateConstructor = `
BaseData reflect_%classname%_constructor_%constructorname%_%idx% = new ModData();
reflect_%classname%_constructor_%constructorname%_%idx%.set("returnType", %returntype%);
reflect_%classname%_constructor_%constructorname%_%idx%.set("argnames", %argkeys%);
reflect_%classname%_constructor_%constructorname%_%idx%.set("argtypes", %argvalues%);
reflect_%classname%_constructor_%constructorname%_%idx%.%constructorimpl%
reflect_%classname%_constructors.add(reflect_%classname%_constructor_%constructorname%_%idx%);
BaseData reflect_%classname%_constructor_%constructorname%_%idx% = new ModData();
reflect_%classname%_constructor_%constructorname%_%idx%.set("returnType", %returntype%);
reflect_%classname%_constructor_%constructorname%_%idx%.set("argnames", %argkeys%);
reflect_%classname%_constructor_%constructorname%_%idx%.set("argtypes", %argvalues%);
reflect_%classname%_constructor_%constructorname%_%idx%.%constructorimpl%
reflect_%classname%_constructors.add(reflect_%classname%_constructor_%constructorname%_%idx%);
`;
const templateMethod = `
BaseData reflect_%classname%_method_%methodname%_%idx% = new ModData();
reflect_%classname%_method_%methodname%_%idx%.set("methodName", "%methodname%");
reflect_%classname%_method_%methodname%_%idx%.set("returnType", %returntype%);
reflect_%classname%_method_%methodname%_%idx%.set("static", %static%);
reflect_%classname%_method_%methodname%_%idx%.set("argnames", %argkeys%);
reflect_%classname%_method_%methodname%_%idx%.set("argtypes", %argvalues%);
reflect_%classname%_method_%methodname%_%idx%.%methodimpl%
reflect_%classname%_methods.add(reflect_%classname%_method_%methodname%_%idx%);
BaseData reflect_%classname%_method_%methodname%_%idx% = new ModData();
reflect_%classname%_method_%methodname%_%idx%.set("methodName", "%methodname%");
reflect_%classname%_method_%methodname%_%idx%.set("returnType", %returntype%);
reflect_%classname%_method_%methodname%_%idx%.set("static", %static%);
reflect_%classname%_method_%methodname%_%idx%.set("argnames", %argkeys%);
reflect_%classname%_method_%methodname%_%idx%.set("argtypes", %argvalues%);
reflect_%classname%_method_%methodname%_%idx%.%methodimpl%
reflect_%classname%_methods.add(reflect_%classname%_method_%methodname%_%idx%);
`;
const classDefCallTemplate = ` PLReflect.reflect_%classname%_generator(reflectProfiles);
`;
const templateManager = `
import net.eaglerforge.api.*;
import java.util.ArrayList;
@ -55,14 +63,24 @@ import org.teavm.jso.JSBody;
import org.teavm.jso.JSObject;
import org.teavm.jso.JSFunctor;
//AUTOGENERATED BY NOREFLECT
// _ _ ___ __ _ _
// | \\| |___| _ \\___ / _| |___ __| |_
// | .\` / _ \\ / -_) _| / -_) _| _|
// |_|\\_\\___/_|_\\___|_| |_\\___\\__|\\__|
// _________________________________
//AutoGenerated by NoReflect
//Made by ZXMushroom63
public class PLReflect extends ModData {
%classdefs%
public static PLReflect makeModData() {
PLReflect plReflectGlobal = new PLReflect();
ArrayList<BaseData> reflectProfiles = new ArrayList<BaseData>();
%classdefs%
%classdefcalls%
BaseData[] reflectProfilesArr = new BaseData[reflectProfiles.size()];
for (int i = 0; i < reflectProfilesArr.length; i++) {
reflectProfilesArr[i] = reflectProfiles.get(i);
@ -127,6 +145,7 @@ function createManagerFile(managerTemplate, config, zip, dataDump, classIdMap) {
var imports = [];
var classText = "";
var classCallText = "";
var classes = Object.keys(dataDump);
for (let i = 0; i < classes.length; i++) {
const className = classes[i];
@ -182,7 +201,7 @@ function createManagerFile(managerTemplate, config, zip, dataDump, classIdMap) {
tmpMethodText = tmpMethodText.replaceAll("%idx%", method.idx);
tmpMethodText = tmpMethodText.replaceAll("%static%", method.isStatic);
tmpMethodText = tmpMethodText.replaceAll("%methodname%", method.name);
tmpMethodText = tmpMethodText.replaceAll("%returntype%", "\""+className+"\"");
tmpMethodText = tmpMethodText.replaceAll("%returntype%", "\""+method.returnType+"\"");
tmpMethodText = tmpMethodText.replaceAll("%argkeys%", `new String[]{${(()=>{
var txt = "";
var argumentKeys = Object.keys(method.arguments);
@ -214,6 +233,7 @@ function createManagerFile(managerTemplate, config, zip, dataDump, classIdMap) {
tmpClassText = tmpClassText.replaceAll("%methoddefs%", methodText);
classText += tmpClassText;
classCallText += classDefCallTemplate.replaceAll("%classname%", className);
}
for (let i = 0; i < config.imports.length; i++) {
manager = `import ${config.imports[i]}` + ";\n" + manager;
@ -232,6 +252,7 @@ function createManagerFile(managerTemplate, config, zip, dataDump, classIdMap) {
manager = `package ${config.managerFile.match(/(.*)(?=\.[^.]*$)/g)[0]}` + ";\n" + manager;
manager = manager.replaceAll("%classdefs%", classText);
manager = manager.replaceAll("%classdefcalls%", classCallText);
zip.file(filePath, manager);
}
@ -247,7 +268,10 @@ async function generate(fileList) {
return;
}
try {
cfg = JSON.parse(document.querySelector("#config").value.trim());
var cfgString = document.querySelector("#config").value.trim();
cfgString = cfgString.replace(/\/\/.*$/gm, '');
cfgString = cfgString.replace(/\/\*[\s\S]*?\*\//gm, '');
cfg = JSON.parse(cfgString);
} catch (e) {
logTxt("[ERROR] Invalid config.");
return;

View File

@ -97,8 +97,97 @@
<br>
<textarea id="config" spellcheck="false">
{
"targetFiles": ["net.minecraft.item.ItemStack", "net.minecraft.client.Minecraft"],
"imports": ["java.lang.String"],
"targetFiles": [
"net.minecraft.item.ItemStack",
"net.minecraft.client.Minecraft",
"net.lax1dude.eaglercraft.v1_8.opengl.EaglercraftGPU",
"net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager",
"net.minecraft.client.renderer.entity.RenderManager",
"net.minecraft.client.renderer.Tessellator",
"net.minecraft.client.renderer.RenderGlobal",
"net.minecraft.client.renderer.EntityRenderer",
"net.lax1dude.eaglercraft.v1_8.opengl.VertexFormat",
"net.lax1dude.eaglercraft.v1_8.opengl.WorldRenderer",
"net.minecraft.util.AxisAlignedBB",
"net.minecraft.util.Vec3",
"net.minecraft.util.MathHelper",
"net.minecraft.client.multiplayer.WorldClient",
"net.minecraft.world.World",
"net.minecraft.world.WorldServer",
"net.minecraft.server.MinecraftServer",
"net.minecraft.entity.Entity",
"net.minecraft.entity.EntityLivingBase",
"net.minecraft.entity.EntityLiving",
"net.minecraft.entity.EntityCreature",
"net.minecraft.entity.EntityMinecartCommandBlock",
"net.minecraft.entity.boss.EntityDragon",
"net.minecraft.entity.boss.EntityWither",
"net.minecraft.entity.effect.EntityLightningBolt",
"net.minecraft.entity.item.EntityArmorStand",
"net.minecraft.entity.item.EntityBoat",
"net.minecraft.entity.item.EntityEnderCrystal",
"net.minecraft.entity.item.EntityEnderEye",
"net.minecraft.entity.item.EntityEnderPearl",
"net.minecraft.entity.item.EntityExpBottle",
"net.minecraft.entity.item.EntityFallingBlock",
"net.minecraft.entity.item.EntityFireworkRocket",
"net.minecraft.entity.item.EntityItem",
"net.minecraft.entity.item.EntityItemFrame",
"net.minecraft.entity.item.EntityMinecart",
"net.minecraft.entity.item.EntityMinecartChest",
"net.minecraft.entity.item.EntityMinecartContainer",
"net.minecraft.entity.item.EntityMinecartEmpty",
"net.minecraft.entity.item.EntityMinecartFurnace",
"net.minecraft.entity.item.EntityMinecartHopper",
"net.minecraft.entity.item.EntityMinecartTNT",
"net.minecraft.entity.item.EntityPainting",
"net.minecraft.entity.item.EntityTNTPrimed",
"net.minecraft.entity.item.EntityXPOrb",
"net.minecraft.entity.monster.EntityBlaze",
"net.minecraft.entity.monster.EntityCaveSpider",
"net.minecraft.entity.monster.EntityCreeper",
"net.minecraft.entity.monster.EntityEnderman",
"net.minecraft.entity.monster.EntityEndermite",
"net.minecraft.entity.monster.EntityGhast",
"net.minecraft.entity.monster.EntityGiantZombie",
"net.minecraft.entity.monster.EntityGolem",
"net.minecraft.entity.monster.EntityGuardian",
"net.minecraft.entity.monster.EntityIronGolem",
"net.minecraft.entity.monster.EntityMagmaCube",
"net.minecraft.entity.monster.EntityMob",
"net.minecraft.entity.monster.EntityPigZombie",
"net.minecraft.entity.monster.EntitySilverfish",
"net.minecraft.entity.monster.EntitySkeleton",
"net.minecraft.entity.monster.EntitySlime",
"net.minecraft.entity.monster.EntitySnowman",
"net.minecraft.entity.monster.EntitySpider",
"net.minecraft.entity.monster.EntityWitch",
"net.minecraft.entity.monster.EntityZombie",
"net.minecraft.entity.passive.EntityAmbientCreature",
"net.minecraft.entity.passive.EntityAnimal",
"net.minecraft.entity.passive.EntityBat",
"net.minecraft.entity.passive.EntityChicken",
"net.minecraft.entity.passive.EntityCow",
"net.minecraft.entity.passive.EntityHorse",
"net.minecraft.entity.passive.EntityMooshroom",
"net.minecraft.entity.passive.EntityOcelot",
"net.minecraft.entity.passive.EntityPig",
"net.minecraft.entity.passive.EntityRabbit",
"net.minecraft.entity.passive.EntitySheep",
"net.minecraft.entity.passive.EntitySquid",
"net.minecraft.entity.passive.EntityTameable",
"net.minecraft.entity.passive.EntityVillager",
"net.minecraft.entity.passive.EntityWaterMob",
"net.minecraft.entity.passive.EntityWolf",
"net.minecraft.entity.player.EntityPlayer",
"net.minecraft.entity.player.EntityPlayerMP",
"net.minecraft.client.entity.EntityPlayerSP",
"net.minecraft.client.entity.EntityOtherPlayerMP",
"net.minecraft.client.entity.AbstractClientPlayer",
"net.minecraft.init.Blocks",
"net.minecraft.init.Items"
],
"imports": ["java.lang.String", "java.util.Calendar", "net.minecraft.world.WorldSettings.GameType"],
"managerFile": "net.eaglerforge.reflect.PLReflect",
"includeReadFiles": false,
"attemptAutoImport": true

View File

@ -31,6 +31,7 @@ function reconJ(java, className) {
javaText = javaText.replace(/\/\/.*$/gm, '');
javaText = javaText.replace(/\/\*[\s\S]*?\*\//gm, '');
javaText = javaText.replace(/[ \t](public|private|protected|)\s*(static|) (class|enum) .+ \{(\W|\w)*?\n(\t)\}/gm, '');
let constructorRegex = /(public|protected|private|static|\s) +(\w+) *\(([^)]*)\)/g;
@ -38,6 +39,10 @@ function reconJ(java, className) {
return !line[0].includes(" private ") && !line[0].includes(" protected ") && !line[0].includes("\n\t\t") && line[1] !== "private" && line[1] !== "protected";
})];
if (javaText.match(/^(public|private|protected|) abstract class /gm)) {
constructors = [];
}
let constructorDetails = constructors.map((constructor) => {
let constructorName = constructor[2];
let argumentString = constructor[3];
@ -79,10 +84,10 @@ function reconJ(java, className) {
};
});
let methodRegex = /(public|static|private|protected|\s)* +([\w\<\>\[\]]+)\s+(\w+) *\(([^)]*)\)/g;
let methodRegex = /(public|static|private|protected|final|\s)* +([\w\<\>\[\]]+)\s+(\w+) *\(([^)]*)\)/g;
let methods = [...javaText.matchAll(methodRegex).filter((line)=>{
return !line[0].includes("> ") && !line[0].startsWith(" else ") && !line[0].startsWith(" new ") && !line[0].includes(" private ") && !line[0].includes("\tprotected ") && !line[0].includes("\tprivate ") && !line[0].includes(" protected ") && !line[0].includes("\n\t\t");
return !line[0].includes("> ") && !line[0].startsWith(" else ") && !line[0].startsWith(" new ") && !line[0].includes(" private ") && !line[0].includes("\tprotected ") && !line[0].includes("\tprivate ") && !line[0].includes(" protected ") && !line[0].includes("\n\t\t") && line[0].includes("public ");
//Doesn't support Type<Subtype> yet
})];
@ -93,14 +98,24 @@ function reconJ(java, className) {
let argumentString = method[4];
let arguments = {};
let methodContainsInlineClasses = false;
if (argumentString.trim().length > 0) {
let argumentList = argumentString.split(",");
argumentList.forEach((argument) => {
let [type, name] = argument.trim().split(" ");
let [type, name] = argument.trim().split(" ").filter(potential => {
return potential !== "final";
});
if (type.includes(".")) {
methodContainsInlineClasses = true;
}
arguments[name] = type;
});
}
if (methodContainsInlineClasses) {
return false;
}
let argStr = "";
var argumentsKeys = Object.keys(arguments);
for (let i = 0; i < argumentsKeys.length; i++) {
@ -158,8 +173,8 @@ function reconJ(java, className) {
});
return {
className: className,
constructors: constructorDetails,
methods: methodDetails,
constructors: constructorDetails.filter(obj => obj),
methods: methodDetails.filter(obj => obj),
usedClasses: [...new Set(usedClasses)]
}
}