Skip to content

Commit

Permalink
Fix most reflection related crashes
Browse files Browse the repository at this point in the history
  • Loading branch information
thecatcore committed Apr 23, 2024
1 parent 5fe734f commit 313c4e5
Show file tree
Hide file tree
Showing 10 changed files with 192 additions and 151 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,12 @@ public void registerVisitors(VisitorInfos visitorInfos) {
@Override
public void afterRemap() {
Mixins.addConfiguration("fabricated-forge.mods.mixins.json");
Utils.TRANSFORMER_EXCLUSIONS.add("fr.catcore.fabricatedforge.compat.asm.BetterClassWriter");
Utils.TRANSFORMER_EXCLUSIONS.add("fr.catcore.");
try {
Class.forName("fr.catcore.fabricatedforge.compat.asm.RemapAwareClass");
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
ClassTransformer.registerPostTransformer(new ASMRemapperTransformer());
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
package fr.catcore.fabricatedforge.compat.asm;

import fr.catcore.modremapperapi.api.IClassTransformer;
import io.github.fabriccompatibiltylayers.modremappingapi.api.MappingUtils;
import org.jetbrains.annotations.Nullable;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ASMRemapperTransformer implements IClassTransformer, Opcodes {
Expand All @@ -27,6 +31,65 @@ public class ASMRemapperTransformer implements IClassTransformer, Opcodes {
{"org/objectweb/asm/ClassWriter", "fr/catcore/fabricatedforge/compat/asm/BetterClassWriter"}
});

private final static Map<String, Map<String, Map<String, ClassAwareMember>>> CALL_REPLACER = new HashMap<>();

private final static List<String> TRANSFORMED = new ArrayList<>();

private static void registerCallReplacer(String className, Object... args) {
Map<String, Map<String, ClassAwareMember>> classMap = CALL_REPLACER.compute(className, (s, stringMapMap) -> new HashMap<>());

for (int i = 0; i < args.length; i++) {
String name = (String) args[i];
String desc = (String) args[i + 1];
ClassAwareMember member = (ClassAwareMember) args[i + 2];

Map<String, ClassAwareMember> methodMap = classMap.compute(name, (s, stringClassAwareMemberMap) -> new HashMap<>());
methodMap.put(desc, member);

i += 2;
}
}

static {
registerCallReplacer("java/lang/Class",
"getDeclaredMethod", "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", new ClassAwareMember(
"fr/catcore/fabricatedforge/compat/asm/RemapAwareClass",
"getDeclaredMethod",
"(Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;"
),

"getDeclaredField", "(Ljava/lang/String;)Ljava/lang/reflect/Field;", new ClassAwareMember(
"fr/catcore/fabricatedforge/compat/asm/RemapAwareClass",
"getDeclaredField",
"(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/reflect/Field;"
),

"getMethod", "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", new ClassAwareMember(
"fr/catcore/fabricatedforge/compat/asm/RemapAwareClass",
"getMethod",
"(Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;"
),

"getField", "(Ljava/lang/String;)Ljava/lang/reflect/Field;", new ClassAwareMember(
"fr/catcore/fabricatedforge/compat/asm/RemapAwareClass",
"getField",
"(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/reflect/Field;"
),

"forName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;", new ClassAwareMember(
"fr/catcore/fabricatedforge/compat/asm/RemapAwareClass",
"forName",
"(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"
),

"forName", "(Ljava/lang/String;)Ljava/lang/Class;", new ClassAwareMember(
"fr/catcore/fabricatedforge/compat/asm/RemapAwareClass",
"forName",
"(Ljava/lang/String;)Ljava/lang/Class;"
)
);
}

@Override
public boolean handlesClass(String s, String s1) {
for (String exclude : EXCLUDED) {
Expand All @@ -38,6 +101,9 @@ public boolean handlesClass(String s, String s1) {

@Override
public byte[] transformClass(String s, String s1, byte[] bytes) {
if (TRANSFORMED.contains(s)) return bytes;
TRANSFORMED.add(s);

ClassNode classNode = new ClassNode();
ClassReader classReader = new ClassReader(bytes);
classReader.accept(classNode, 0);
Expand All @@ -56,12 +122,31 @@ public byte[] transformClass(String s, String s1, byte[] bytes) {
typeInsnNode.desc = INSTANCE_REPLACER.get(typeInsnNode.desc);
touched = true;
}
} else if (insnNode.getOpcode() == INVOKESPECIAL && insnNode instanceof MethodInsnNode) {
} else if (insnNode instanceof MethodInsnNode) {
MethodInsnNode methodInsnNode = (MethodInsnNode) insnNode;

if (methodInsnNode.name.equals("<init>") && INSTANCE_REPLACER.containsKey(methodInsnNode.owner)) {
methodInsnNode.owner = INSTANCE_REPLACER.get(methodInsnNode.owner);
touched = true;
if (methodInsnNode.getOpcode() == INVOKESPECIAL) {
if (methodInsnNode.name.equals("<init>") && INSTANCE_REPLACER.containsKey(methodInsnNode.owner)) {
methodInsnNode.owner = INSTANCE_REPLACER.get(methodInsnNode.owner);
touched = true;
}
} else if (methodInsnNode.getOpcode() == INVOKEVIRTUAL || methodInsnNode.getOpcode() == INVOKESTATIC) {
if (CALL_REPLACER.containsKey(methodInsnNode.owner)) {
Map<String, Map<String, ClassAwareMember>> classMethods = CALL_REPLACER.get(methodInsnNode.owner);

if (classMethods.containsKey(methodInsnNode.name)) {
Map<String, ClassAwareMember> classMethod = classMethods.get(methodInsnNode.name);

if (classMethod.containsKey(methodInsnNode.desc)) {
ClassAwareMember classAwareMember = classMethod.get(methodInsnNode.desc);
methodInsnNode.setOpcode(INVOKESTATIC);
methodInsnNode.owner = classAwareMember.owner;
methodInsnNode.name = classAwareMember.name;
methodInsnNode.desc = classAwareMember.desc;
touched = true;
}
}
}
}
}

Expand All @@ -71,7 +156,7 @@ public byte[] transformClass(String s, String s1, byte[] bytes) {
}

if (touched) {
ClassWriter classWriter = new ClassWriter(3);
ClassWriter classWriter = new BetterClassWriter(3);
classNode.accept(classWriter);

bytes = classWriter.toByteArray();
Expand All @@ -90,4 +175,12 @@ private static Map<String, String> arrayToMap(String[][] arrays) {

return map;
}

public static class ClassAwareMember extends MappingUtils.ClassMember {
public final String owner;
public ClassAwareMember(String owner, String name, @Nullable String desc) {
super(name, desc);
this.owner = owner;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package fr.catcore.fabricatedforge.compat.asm;

import net.fabricmc.loader.api.FabricLoader;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;

Expand All @@ -13,31 +12,8 @@ public BetterClassWriter(ClassReader classReader, int flags) {
super(classReader, flags);
}

@Override
protected String getCommonSuperClass(String type1, String type2) {
try {
return super.getCommonSuperClass(type1, type2);
} catch (TypeNotPresentException e) {
if ("cpw/mods/fml/common/MinecraftDummyContainer".equals(type1) && "cpw/mods/fml/common/ModContainer".equals(type2)) {
return type2;
}

if ("net/minecraft/class_1071".equals(type1) && "net/minecraft/class_987".equals(type2)) {
return "java/lang/Object";
}

if ("net/minecraft/class_987".equals(type1) && "java/lang/Object".equals(type2)) {
return type2;
}

System.out.println("Common of: " + type1 + " " + type2);
e.printStackTrace();
return "java/lang/Object";
}
}

@Override
protected ClassLoader getClassLoader() {
return FabricLoader.getInstance().getClass().getClassLoader();
return this.getClass().getClassLoader();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package fr.catcore.fabricatedforge.compat.asm;

import io.github.fabriccompatibiltylayers.modremappingapi.api.MappingUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class RemapAwareClass {
public static Class<?> forName(String className)
throws ClassNotFoundException {
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
className = MappingUtils.mapClass(className);

return Class.forName(className);
}
}
public static Class<?> forName(String className, boolean initialize,
ClassLoader loader)
throws ClassNotFoundException {
try {
return Class.forName(className, initialize, loader);
} catch (ClassNotFoundException e) {
className = MappingUtils.mapClass(className);

return Class.forName(className, initialize, loader);
}
}

public static Method getDeclaredMethod(Class<?> clazz, String name, Class<?>... parameterTypes) throws NoSuchMethodException {
try {
return clazz.getDeclaredMethod(name, parameterTypes);
} catch (NoSuchMethodException e) {
name = MappingUtils.mapMethod(clazz, name, parameterTypes).name;

return clazz.getDeclaredMethod(name, parameterTypes);
}
}

public static Field getDeclaredField(Class<?> clazz, String name) throws NoSuchFieldException {
try {
return clazz.getDeclaredField(name);
} catch (NoSuchFieldException e) {
name = MappingUtils.mapField(clazz, name).name;

return clazz.getDeclaredField(name);
}
}

public static Method getMethod(Class<?> clazz, String name, Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException {
final String originalName = name;
try {
return clazz.getMethod(name, parameterTypes);
} catch (NoSuchMethodException e) {
name = MappingUtils.mapMethod(clazz, name, parameterTypes).name;

try {
return clazz.getMethod(name, parameterTypes);
} catch (NoSuchMethodException e1) {
return getDeclaredMethod(clazz, originalName, parameterTypes);
}
}
}

public static Field getField(Class<?> clazz, String name) throws NoSuchFieldException, SecurityException {
final String originalName = name;
try {
return clazz.getField(name);
} catch (NoSuchFieldException e) {
name = MappingUtils.mapField(clazz, name).name;

try {
return clazz.getField(name);
} catch (NoSuchFieldException e1) {
return getDeclaredField(clazz, originalName);
}
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,29 +1,3 @@
accessWidener v2 named

### NEI
accessible field net/minecraft/client/gui/screen/ingame/HandledScreen field_1346 Lnet/minecraft/client/render/item/ItemRenderer;
accessible field net/minecraft/client/gui/screen/ingame/HandledScreen backgroundWidth I
accessible field net/minecraft/client/gui/screen/ingame/HandledScreen backgroundHeight I
accessible field net/minecraft/client/gui/screen/ingame/HandledScreen x I
accessible field net/minecraft/client/gui/screen/ingame/HandledScreen y I
accessible method net/minecraft/client/gui/screen/ingame/HandledScreen getSlotAt (II)Lnet/minecraft/inventory/slot/Slot;
extendable method net/minecraft/client/gui/screen/ingame/HandledScreen getSlotAt (II)Lnet/minecraft/inventory/slot/Slot;
accessible method net/minecraft/client/gui/screen/ingame/HandledScreen onMouseClick (Lnet/minecraft/inventory/slot/Slot;III)V
accessible method net/minecraft/client/gui/screen/ingame/HandledScreen drawSlot (Lnet/minecraft/inventory/slot/Slot;)V
extendable method net/minecraft/client/gui/screen/ingame/HandledScreen drawSlot (Lnet/minecraft/inventory/slot/Slot;)V

accessible field net/minecraft/client/class_469 connection Lnet/minecraft/network/Connection;
accessible field net/minecraft/entity/EntityType CLASS_ID_MAP Ljava/util/Map;
accessible field net/minecraft/client/gui/screen/Screen textRenderer Lnet/minecraft/client/font/TextRenderer;
accessible field net/minecraft/client/gui/screen/Screen field_1229 Lnet/minecraft/client/Minecraft;
accessible method net/minecraft/client/gui/DrawableHelper fillGradient (IIIIII)V
accessible field net/minecraft/client/gui/DrawableHelper zOffset F
accessible field net/minecraft/client/gui/screen/ingame/CreativeInventoryScreen selectedTab I
accessible field net/minecraft/client/gui/screen/Screen buttons Ljava/util/List;
accessible class net/minecraft/inventory/slot/class_1019
accessible method net/minecraft/inventory/slot/class_1019 <init> (Lnet/minecraft/screen/PlayerScreenHandler;Lnet/minecraft/inventory/Inventory;IIII)V

accessible field net/minecraft/world/chunk/ServerChunkProvider chunks Ljava/util/List;
accessible field net/minecraft/inventory/CraftingInventory stacks [Lnet/minecraft/item/ItemStack;
accessible field net/minecraft/client/Minecraft ticker Lnet/minecraft/client/render/ClientTickTracker;
accessible field net/minecraft/nbt/NbtCompound data Ljava/util/Map;
accessible field net/minecraft/client/Minecraft ticker Lnet/minecraft/client/render/ClientTickTracker;
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
"codechickencore.DelegatedTransformerMixin",
"codechickencore.DescriptorMappingMixin",
"immibiscore.ImmibisCoreMixin",
"nei.FurnaceRecipeHandlerMixin",
"nei.TMIUninstallerMixin",
"treecapitator.ItemInWorldManagerTransformerMixin"
],
Expand Down
16 changes: 0 additions & 16 deletions src/main/java/cpw/mods/fml/relauncher/FMLRelauncher.java
Original file line number Diff line number Diff line change
Expand Up @@ -170,22 +170,6 @@ private void setupHome(File minecraftHome) {
}

private File computeExistingClientHome() {
// Class<? super Object> mcMaster = ReflectionHelper.getClass(this.getClass().getClassLoader(), new String[]{"net.minecraft.client.Minecraft"});
// String str = System.getProperty("minecraft.applet.TargetDirectory");
// if (str != null) {
// str = str.replace('/', File.separatorChar);
// ReflectionHelper.setPrivateValue(mcMaster, null, new File(str), new String[]{"minecraftDir", "an", "minecraftDir"});
// }
//
// Method setupHome = ReflectionHelper.findMethod(mcMaster, null, new String[]{"getMinecraftDir", "getMinecraftDir", "b"}, new Class[0]);
//
// try {
// setupHome.invoke(null);
// } catch (Exception var5) {
// }
//
// return (File)ReflectionHelper.getPrivateValue(mcMaster, null, new String[]{"minecraftDir", "an", "minecraftDir"});

return FabricLoader.getInstance().getGameDir().toFile();
}

Expand Down
Loading

0 comments on commit 313c4e5

Please sign in to comment.