|
| 1 | +package com.cleanroommc.groovyscript.core.mixin.groovy; |
| 2 | + |
| 3 | +import com.cleanroommc.groovyscript.sandbox.mapper.GroovyDeobfMapper; |
| 4 | +import net.minecraftforge.fml.relauncher.FMLLaunchHandler; |
| 5 | +import org.codehaus.groovy.ast.*; |
| 6 | +import org.codehaus.groovy.ast.Parameter; |
| 7 | +import org.codehaus.groovy.vmplugin.v8.Java8; |
| 8 | +import org.spongepowered.asm.mixin.Mixin; |
| 9 | +import org.spongepowered.asm.mixin.Overwrite; |
| 10 | +import org.spongepowered.asm.mixin.Shadow; |
| 11 | + |
| 12 | +import java.lang.annotation.Annotation; |
| 13 | +import java.lang.reflect.*; |
| 14 | +import java.util.Map; |
| 15 | + |
| 16 | +@Mixin(value = Java8.class, remap = false) |
| 17 | +public abstract class Java8Mixin { |
| 18 | + |
| 19 | + @Shadow |
| 20 | + protected abstract ClassNode makeClassNode(CompileUnit cu, Type t, Class<?> c); |
| 21 | + |
| 22 | + @Shadow |
| 23 | + protected abstract void setAnnotationMetaData(Annotation[] annotations, AnnotatedNode target); |
| 24 | + |
| 25 | + @Shadow |
| 26 | + protected abstract Parameter[] makeParameters(CompileUnit cu, Type[] types, Class<?>[] cls, Annotation[][] parameterAnnotations, Member member); |
| 27 | + |
| 28 | + @Shadow |
| 29 | + protected abstract ClassNode[] makeClassNodes(CompileUnit cu, Type[] types, Class<?>[] cls); |
| 30 | + |
| 31 | + @Shadow |
| 32 | + private static void setMethodDefaultValue(MethodNode mn, Method m) { |
| 33 | + } |
| 34 | + |
| 35 | + @Shadow |
| 36 | + protected abstract GenericsType[] configureTypeVariable(TypeVariable<?>[] tvs); |
| 37 | + |
| 38 | + @Shadow |
| 39 | + protected abstract Annotation[][] getConstructorParameterAnnotations(Constructor<?> constructor); |
| 40 | + |
| 41 | + @Shadow |
| 42 | + protected abstract void makeInterfaceTypes(CompileUnit cu, ClassNode classNode, Class<?> clazz); |
| 43 | + |
| 44 | + @Shadow |
| 45 | + protected abstract void makePermittedSubclasses(CompileUnit cu, ClassNode classNode, Class<?> clazz); |
| 46 | + |
| 47 | + @Shadow |
| 48 | + protected abstract void makeRecordComponents(CompileUnit cu, ClassNode classNode, Class<?> clazz); |
| 49 | + |
| 50 | + /** |
| 51 | + * @author brachy84 |
| 52 | + * @reason remapping minecraft fields and methods |
| 53 | + */ |
| 54 | + @Overwrite |
| 55 | + public void configureClassNode(final CompileUnit compileUnit, final ClassNode classNode) { |
| 56 | + try { |
| 57 | + Class<?> clazz = classNode.getTypeClass(); |
| 58 | + Map<String, String> deobfFields = FMLLaunchHandler.isDeobfuscatedEnvironment() ? null : GroovyDeobfMapper.getDeobfFields(clazz); |
| 59 | + Field[] fields = clazz.getDeclaredFields(); |
| 60 | + for (Field f : fields) { |
| 61 | + ClassNode ret = makeClassNode(compileUnit, f.getGenericType(), f.getType()); |
| 62 | + String name = deobfFields != null ? deobfFields.getOrDefault(f.getName(), f.getName()) : f.getName(); |
| 63 | + FieldNode fn = new FieldNode(name, f.getModifiers(), ret, classNode, null); |
| 64 | + setAnnotationMetaData(f.getAnnotations(), fn); |
| 65 | + classNode.addField(fn); |
| 66 | + } |
| 67 | + Map<String, String> deobfMethods = FMLLaunchHandler.isDeobfuscatedEnvironment() ? null : GroovyDeobfMapper.getDeobfMethods(clazz); |
| 68 | + Method[] methods = clazz.getDeclaredMethods(); |
| 69 | + for (Method m : methods) { |
| 70 | + ClassNode ret = makeClassNode(compileUnit, m.getGenericReturnType(), m.getReturnType()); |
| 71 | + Parameter[] params = makeParameters(compileUnit, m.getGenericParameterTypes(), m.getParameterTypes(), m.getParameterAnnotations(), m); |
| 72 | + ClassNode[] exceptions = makeClassNodes(compileUnit, m.getGenericExceptionTypes(), m.getExceptionTypes()); |
| 73 | + String name = deobfMethods != null ? deobfMethods.getOrDefault(m.getName(), m.getName()) : m.getName(); |
| 74 | + MethodNode mn = new MethodNode(name, m.getModifiers(), ret, params, exceptions, null); |
| 75 | + mn.setSynthetic(m.isSynthetic()); |
| 76 | + setMethodDefaultValue(mn, m); |
| 77 | + setAnnotationMetaData(m.getAnnotations(), mn); |
| 78 | + mn.setGenericsTypes(configureTypeVariable(m.getTypeParameters())); |
| 79 | + classNode.addMethod(mn); |
| 80 | + } |
| 81 | + Constructor<?>[] constructors = clazz.getDeclaredConstructors(); |
| 82 | + for (Constructor<?> ctor : constructors) { |
| 83 | + Parameter[] params = makeParameters(compileUnit, ctor.getGenericParameterTypes(), ctor.getParameterTypes(), getConstructorParameterAnnotations(ctor), ctor); |
| 84 | + ClassNode[] exceptions = makeClassNodes(compileUnit, ctor.getGenericExceptionTypes(), ctor.getExceptionTypes()); |
| 85 | + ConstructorNode cn = classNode.addConstructor(ctor.getModifiers(), params, exceptions, null); |
| 86 | + setAnnotationMetaData(ctor.getAnnotations(), cn); |
| 87 | + } |
| 88 | + |
| 89 | + Class<?> sc = clazz.getSuperclass(); |
| 90 | + if (sc != null) classNode.setUnresolvedSuperClass(makeClassNode(compileUnit, clazz.getGenericSuperclass(), sc)); |
| 91 | + makeInterfaceTypes(compileUnit, classNode, clazz); |
| 92 | + makePermittedSubclasses(compileUnit, classNode, clazz); |
| 93 | + makeRecordComponents(compileUnit, classNode, clazz); |
| 94 | + setAnnotationMetaData(clazz.getAnnotations(), classNode); |
| 95 | + |
| 96 | + PackageNode packageNode = classNode.getPackage(); |
| 97 | + if (packageNode != null) { |
| 98 | + setAnnotationMetaData(clazz.getPackage().getAnnotations(), packageNode); |
| 99 | + } |
| 100 | + } catch (NoClassDefFoundError e) { |
| 101 | + throw new NoClassDefFoundError("Unable to load class " + classNode.toString(false) + " due to missing dependency " + e.getMessage()); |
| 102 | + } catch (MalformedParameterizedTypeException e) { |
| 103 | + throw new RuntimeException("Unable to configure class node for class " + classNode.toString(false) + " due to malformed parameterized types", e); |
| 104 | + } |
| 105 | + } |
| 106 | +} |
0 commit comments