diff --git a/src/main/java/fr/catcore/modremapperapi/remapping/MRAClassVisitor.java b/src/main/java/fr/catcore/modremapperapi/remapping/MRAClassVisitor.java index 24f48d5..0f2588c 100644 --- a/src/main/java/fr/catcore/modremapperapi/remapping/MRAClassVisitor.java +++ b/src/main/java/fr/catcore/modremapperapi/remapping/MRAClassVisitor.java @@ -1,13 +1,13 @@ package fr.catcore.modremapperapi.remapping; +import io.github.fabriccompatibiltylayers.modremappingapi.impl.VisitorInfosImpl; import org.objectweb.asm.*; -import java.util.Map; - public class MRAClassVisitor extends ClassVisitor { - private final VisitorInfos infos; + private final VisitorInfosImpl infos; private final String className; - protected MRAClassVisitor(ClassVisitor classVisitor, VisitorInfos infos, String className) { + + protected MRAClassVisitor(ClassVisitor classVisitor, VisitorInfosImpl infos, String className) { super(Opcodes.ASM9, classVisitor); this.infos = infos; this.className = className; @@ -15,30 +15,24 @@ protected MRAClassVisitor(ClassVisitor classVisitor, VisitorInfos infos, String @Override public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { - VisitorInfos.Type superType = new VisitorInfos.Type(superName); + String superType = superName; - for (Map.Entry entry : infos.SUPERS.entrySet()) { - if (entry.getKey().type.equals(superName)) { - superType = entry.getValue(); - break; - } + if (infos.SUPERS.containsKey(superName)) { + superType = infos.SUPERS.get(superName); } - super.visit(version, access, name, signature, superType.type, interfaces); + super.visit(version, access, name, signature, superType, interfaces); } @Override public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String descriptor, boolean visible) { - VisitorInfos.Type superType = new VisitorInfos.Type(descriptor); + String annotationType = descriptor; - for (Map.Entry entry : infos.ANNOTATION.entrySet()) { - if (entry.getKey().type.equals(descriptor)) { - superType = entry.getValue(); - break; - } + if (infos.ANNOTATION.containsKey(descriptor)) { + annotationType = infos.ANNOTATION.get(descriptor); } - return super.visitTypeAnnotation(typeRef, typePath, superType.type, visible); + return super.visitTypeAnnotation(typeRef, typePath, annotationType, visible); } @Override diff --git a/src/main/java/fr/catcore/modremapperapi/remapping/MRAMethodVisitor.java b/src/main/java/fr/catcore/modremapperapi/remapping/MRAMethodVisitor.java index 936b900..0c23151 100644 --- a/src/main/java/fr/catcore/modremapperapi/remapping/MRAMethodVisitor.java +++ b/src/main/java/fr/catcore/modremapperapi/remapping/MRAMethodVisitor.java @@ -1,14 +1,15 @@ package fr.catcore.modremapperapi.remapping; +import io.github.fabriccompatibiltylayers.modremappingapi.impl.VisitorInfosImpl; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import java.util.Map; -public class MRAMethodVisitor extends MethodVisitor { - private final VisitorInfos infos; +public class MRAMethodVisitor extends MethodVisitor implements Opcodes { + private final VisitorInfosImpl infos; private final String className; - protected MRAMethodVisitor(MethodVisitor methodVisitor, VisitorInfos visitorInfos, String className) { + protected MRAMethodVisitor(MethodVisitor methodVisitor, VisitorInfosImpl visitorInfos, String className) { super(Opcodes.ASM9, methodVisitor); this.infos = visitorInfos; this.className = className; @@ -16,59 +17,128 @@ protected MRAMethodVisitor(MethodVisitor methodVisitor, VisitorInfos visitorInfo @Override public void visitTypeInsn(int opcode, String type) { - VisitorInfos.Type superType = new VisitorInfos.Type(type); + String currentType = type; - for (Map.Entry entry : infos.METHOD_TYPE.entrySet()) { - if (entry.getKey().type.equals(type)) { - superType = entry.getValue(); - break; - } + boolean skip = false; + + if (opcode == NEW && infos.INSTANTIATION.containsKey(type)) { + currentType = infos.INSTANTIATION.get(type); + skip = true; + } + + if (!skip && infos.METHOD_TYPE.containsKey(type)) { + currentType = infos.METHOD_TYPE.get(type); } - super.visitTypeInsn(opcode, superType.type); + super.visitTypeInsn(opcode, currentType); } @Override public void visitFieldInsn(int opcode, String owner, String name, String descriptor) { - VisitorInfos.MethodNamed superType = new VisitorInfos.MethodNamed(owner, name); + String currentOwner = owner; + String currentName = name; + String currentDescriptor = descriptor; + + if (infos.FIELD_REF.containsKey(owner)) { + Map> fields = infos.FIELD_REF.get(owner); + + Map args = fields.get(name); + + if (args == null) { + args = fields.get(""); + } - for (Map.Entry entry : infos.METHOD_FIELD.entrySet()) { - if (entry.getKey().owner.equals(owner)) { - if (entry.getKey().name.isEmpty() || entry.getKey().name.equals(name)) { - superType = entry.getValue(); + if (args != null) { + io.github.fabriccompatibiltylayers.modremappingapi.api.VisitorInfos.FullClassMember classMember = args.get(descriptor); + + if (classMember == null) { + classMember = args.get(""); + } + + if (classMember != null) { + currentOwner = classMember.owner; + currentName = classMember.name; + currentDescriptor = classMember.desc; } } } - super.visitFieldInsn(opcode, superType.owner, superType.name.isEmpty() ? name : superType.name, descriptor); + if (currentName.isEmpty()) { + currentName = name; + } + + if (currentDescriptor == null || currentDescriptor.isEmpty()) { + currentDescriptor = descriptor; + } + + super.visitFieldInsn(opcode, currentOwner, currentName, currentDescriptor); } @Override public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) { - VisitorInfos.MethodNamed superType = new VisitorInfos.MethodNamed(owner, name); + int currentOpcode = opcode; + String currentOwner = owner; + String currentName = name; + String currentDescriptor = descriptor; - for (Map.Entry entry : infos.METHOD_METHOD.entrySet()) { - if (entry.getKey().owner.equals(owner)) { - if (entry.getKey().name.isEmpty() || entry.getKey().name.equals(name)) { - superType = entry.getValue(); + boolean skip = false; + + if (opcode == INVOKESPECIAL && infos.INSTANTIATION.containsKey(owner) && name.equals("")) { + currentOwner = infos.INSTANTIATION.get(owner); + skip = true; + } + + if (!skip && (opcode == INVOKEVIRTUAL || opcode == INVOKESTATIC)) { + if (infos.METHOD_INVOCATION.containsKey(owner)) { + Map> methods = infos.METHOD_INVOCATION.get(owner); + + Map args = methods.get(currentName); + + if (args == null) { + args = methods.get(""); + } + + if (args != null) { + io.github.fabriccompatibiltylayers.modremappingapi.api.VisitorInfos.FullClassMember fullClassMember = args.get(currentDescriptor); + + if (fullClassMember == null) { + fullClassMember = args.get(""); + } + + if (fullClassMember != null) { + currentOwner = fullClassMember.owner; + currentName = fullClassMember.name; + currentDescriptor = fullClassMember.desc; + + if (fullClassMember.isStatic != null) currentOpcode = fullClassMember.isStatic ? INVOKESTATIC : INVOKEVIRTUAL; + } } } } - super.visitMethodInsn(opcode, superType.owner, superType.name.isEmpty() ? name : superType.name, descriptor, isInterface); + if (currentName.isEmpty()) { + currentName = name; + } + + if (currentDescriptor == null || currentDescriptor.isEmpty()) { + currentDescriptor = descriptor; + } + + super.visitMethodInsn(currentOpcode, currentOwner, currentName, currentDescriptor, isInterface); } @Override public void visitLdcInsn(Object value) { - VisitorInfos.MethodValue val = new VisitorInfos.MethodValue(this.className, value); + Object currentValue = value; + + if (infos.LDC.containsKey(this.className)) { + Map map = infos.LDC.get(this.className); - for (Map.Entry entry : infos.METHOD_LDC.entrySet()) { - if (entry.getKey().value.equals(value)) { - val = entry.getValue(); - break; + if (map.containsKey(value)) { + currentValue = map.get(value); } } - super.visitLdcInsn(val.value); + super.visitLdcInsn(currentValue); } } diff --git a/src/main/java/fr/catcore/modremapperapi/remapping/MRAPostApplyVisitor.java b/src/main/java/fr/catcore/modremapperapi/remapping/MRAPostApplyVisitor.java index f95b790..7296feb 100644 --- a/src/main/java/fr/catcore/modremapperapi/remapping/MRAPostApplyVisitor.java +++ b/src/main/java/fr/catcore/modremapperapi/remapping/MRAPostApplyVisitor.java @@ -1,18 +1,19 @@ package fr.catcore.modremapperapi.remapping; +import io.github.fabriccompatibiltylayers.modremappingapi.impl.VisitorInfosImpl; import net.fabricmc.tinyremapper.TinyRemapper; import net.fabricmc.tinyremapper.api.TrClass; import org.objectweb.asm.ClassVisitor; public class MRAPostApplyVisitor implements TinyRemapper.ApplyVisitorProvider { - private VisitorInfos infos; + private VisitorInfosImpl infos; @Override public ClassVisitor insertApplyVisitor(TrClass cls, ClassVisitor next) { final String className = cls.getName(); return new MRAClassVisitor(next, infos, className); } - public void setInfos(VisitorInfos infos) { + public void setInfos(VisitorInfosImpl infos) { this.infos = infos; } } diff --git a/src/main/java/fr/catcore/modremapperapi/remapping/RemapUtil.java b/src/main/java/fr/catcore/modremapperapi/remapping/RemapUtil.java index 37c9bb4..ad4954f 100644 --- a/src/main/java/fr/catcore/modremapperapi/remapping/RemapUtil.java +++ b/src/main/java/fr/catcore/modremapperapi/remapping/RemapUtil.java @@ -8,6 +8,7 @@ import fr.catcore.modremapperapi.utils.MappingsUtils; import io.github.fabriccompatibiltylayers.modremappingapi.api.MappingUtils; import io.github.fabriccompatibiltylayers.modremappingapi.impl.MappingsUtilsImpl; +import io.github.fabriccompatibiltylayers.modremappingapi.impl.VisitorInfosImpl; import net.fabricmc.api.EnvType; import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.mappingio.MappingVisitor; @@ -517,7 +518,7 @@ private static TinyRemapper makeRemapper(MappingTree... trees) { MRAPostApplyVisitor applyVisitor = new MRAPostApplyVisitor(); MixinPostApplyVisitor mixinPostApplyVisitor = new MixinPostApplyVisitor(trees); - VisitorInfos infos = new VisitorInfos(); + VisitorInfosImpl infos = new VisitorInfosImpl(); for (ModRemapper modRemapper : ModRemappingAPI.MOD_REMAPPERS) { modRemapper.registerVisitors(infos); diff --git a/src/main/java/fr/catcore/modremapperapi/remapping/VisitorInfos.java b/src/main/java/fr/catcore/modremapperapi/remapping/VisitorInfos.java index 3c5db58..2e7a12e 100644 --- a/src/main/java/fr/catcore/modremapperapi/remapping/VisitorInfos.java +++ b/src/main/java/fr/catcore/modremapperapi/remapping/VisitorInfos.java @@ -1,41 +1,41 @@ package fr.catcore.modremapperapi.remapping; -import java.util.HashMap; -import java.util.Map; import java.util.Objects; +@Deprecated public class VisitorInfos { - protected final Map SUPERS = new HashMap<>(); - protected final Map ANNOTATION = new HashMap<>(); - protected final Map METHOD_TYPE = new HashMap<>(); - protected final Map METHOD_FIELD = new HashMap<>(); - protected final Map METHOD_METHOD = new HashMap<>(); - protected final Map METHOD_LDC = new HashMap<>(); - - public void registerSuperType(Type methodType, Type methodType2) { - SUPERS.put(methodType, methodType2); + + @Deprecated + public void registerSuperType(Type target, Type replacement) { + throw new RuntimeException("This is not supposed to happen!"); } - public void registerTypeAnnotation(Type methodType, Type methodType2) { - ANNOTATION.put(methodType, methodType2); + @Deprecated + public void registerTypeAnnotation(Type target, Type replacement) { + throw new RuntimeException("This is not supposed to happen!"); } - public void registerMethodTypeIns(Type methodType, Type methodType2) { - METHOD_TYPE.put(methodType, methodType2); + @Deprecated + public void registerMethodTypeIns(Type target, Type replacement) { + throw new RuntimeException("This is not supposed to happen!"); } - public void registerMethodFieldIns(MethodNamed methodNamed, MethodNamed methodNamed2) { - METHOD_FIELD.put(methodNamed, methodNamed2); + @Deprecated + public void registerMethodFieldIns(MethodNamed target, MethodNamed replacementObject) { + throw new RuntimeException("This is not supposed to happen!"); } - public void registerMethodMethodIns(MethodNamed methodNamed, MethodNamed methodNamed2) { - METHOD_METHOD.put(methodNamed, methodNamed2); + @Deprecated + public void registerMethodMethodIns(MethodNamed target, MethodNamed replacementObject) { + throw new RuntimeException("This is not supposed to happen!"); } - public void registerMethodLdcIns(MethodValue methodValue, MethodValue methodValue2) { - METHOD_LDC.put(methodValue, methodValue2); + @Deprecated + public void registerMethodLdcIns(MethodValue target, MethodValue replacement) { + throw new RuntimeException("This is not supposed to happen!"); } + @Deprecated public static class Type { public final String type; @@ -52,6 +52,7 @@ public boolean equals(Object o) { } } + @Deprecated public static class MethodValue { public final String owner; public final Object value; @@ -70,6 +71,7 @@ public boolean equals(Object o) { } } + @Deprecated public static class MethodNamed { public final String owner, name; diff --git a/src/main/java/io/github/fabriccompatibiltylayers/modremappingapi/api/MappingUtils.java b/src/main/java/io/github/fabriccompatibiltylayers/modremappingapi/api/MappingUtils.java index e106b69..a1571b9 100644 --- a/src/main/java/io/github/fabriccompatibiltylayers/modremappingapi/api/MappingUtils.java +++ b/src/main/java/io/github/fabriccompatibiltylayers/modremappingapi/api/MappingUtils.java @@ -1,6 +1,7 @@ package io.github.fabriccompatibiltylayers.modremappingapi.api; import io.github.fabriccompatibiltylayers.modremappingapi.impl.MappingsUtilsImpl; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public interface MappingUtils { @@ -37,10 +38,12 @@ static MappingUtils.ClassMember mapMethod(Class owner, String methodName, Cla } class ClassMember { - public final String name; + public final @NotNull String name; public final @Nullable String desc; - public ClassMember(String name, @Nullable String desc) { + public ClassMember(@NotNull String name, @Nullable String desc) { + assert name != null; + this.name = name; this.desc = desc; } diff --git a/src/main/java/io/github/fabriccompatibiltylayers/modremappingapi/api/ModRemapper.java b/src/main/java/io/github/fabriccompatibiltylayers/modremappingapi/api/ModRemapper.java new file mode 100644 index 0000000..243a3cb --- /dev/null +++ b/src/main/java/io/github/fabriccompatibiltylayers/modremappingapi/api/ModRemapper.java @@ -0,0 +1,36 @@ +package io.github.fabriccompatibiltylayers.modremappingapi.api; + +import fr.catcore.modremapperapi.api.RemapLibrary; +import fr.catcore.modremapperapi.remapping.RemapUtil; +import net.fabricmc.api.EnvType; +import net.fabricmc.loader.api.FabricLoader; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public interface ModRemapper { + String[] getJarFolders(); + + default RemapLibrary[] getRemapLibraries() { + List libraries = new ArrayList<>(); + addRemapLibraries(libraries, FabricLoader.getInstance().getEnvironmentType()); + return libraries.toArray(new RemapLibrary[0]); + } + + @SuppressWarnings("unused") + default void addRemapLibraries(List libraries, EnvType environment) {} + + Map> getExclusions(); + + void getMappingList(RemapUtil.MappingList list); + + void registerVisitors(VisitorInfos infos); + + default Optional getDefaultPackage() { + return Optional.empty(); + } + + default void afterRemap() {} +} diff --git a/src/main/java/io/github/fabriccompatibiltylayers/modremappingapi/api/VisitorInfos.java b/src/main/java/io/github/fabriccompatibiltylayers/modremappingapi/api/VisitorInfos.java new file mode 100644 index 0000000..42db29c --- /dev/null +++ b/src/main/java/io/github/fabriccompatibiltylayers/modremappingapi/api/VisitorInfos.java @@ -0,0 +1,34 @@ +package io.github.fabriccompatibiltylayers.modremappingapi.api; + +import org.jetbrains.annotations.Nullable; + +public interface VisitorInfos { + void registerSuperType(String target, String replacement); + + void registerTypeAnnotation(String target, String replacement); + + void registerMethodTypeIns(String target, String replacement); + + void registerFieldRef(String targetClass, String targetField, String targetDesc, FullClassMember classMember); + + void registerMethodInvocation(String targetClass, String targetMethod, String targetDesc, FullClassMember classMember); + + void registerLdc(String targetClass, Object targetLdc, Object replacement); + + void registerInstantiation(String target, String replacement); + + class FullClassMember extends MappingUtils.ClassMember { + public final String owner; + public final @Nullable Boolean isStatic; + + public FullClassMember(String owner, String name, @Nullable String desc, @Nullable Boolean isStatic) { + super(name, desc); + this.owner = owner; + this.isStatic = isStatic; + } + + public FullClassMember(String owner, String name, @Nullable Boolean isStatic) { + this(name, owner, null, isStatic); + } + } +} diff --git a/src/main/java/io/github/fabriccompatibiltylayers/modremappingapi/impl/VisitorInfosImpl.java b/src/main/java/io/github/fabriccompatibiltylayers/modremappingapi/impl/VisitorInfosImpl.java new file mode 100644 index 0000000..4a399c1 --- /dev/null +++ b/src/main/java/io/github/fabriccompatibiltylayers/modremappingapi/impl/VisitorInfosImpl.java @@ -0,0 +1,107 @@ +package io.github.fabriccompatibiltylayers.modremappingapi.impl; + +import io.github.fabriccompatibiltylayers.modremappingapi.api.VisitorInfos; +import org.jetbrains.annotations.ApiStatus; + +import java.util.HashMap; +import java.util.Map; + +@ApiStatus.Internal +public class VisitorInfosImpl extends fr.catcore.modremapperapi.remapping.VisitorInfos implements VisitorInfos { + public final Map SUPERS = new HashMap<>(); + public final Map ANNOTATION = new HashMap<>(); + public final Map METHOD_TYPE = new HashMap<>(); + + public final Map INSTANTIATION = new HashMap<>(); + public final Map>> METHOD_INVOCATION = new HashMap<>(); + public final Map>> FIELD_REF = new HashMap<>(); + public final Map> LDC = new HashMap<>(); + + @Override + public void registerSuperType(String target, String replacement) { + SUPERS.put(target, replacement); + } + + @Override + public void registerTypeAnnotation(String target, String replacement) { + ANNOTATION.put(target, replacement); + } + + @Override + public void registerMethodTypeIns(String target, String replacement) { + METHOD_TYPE.put(target, replacement); + } + + @Override + public void registerFieldRef(String targetClass, String targetField, String targetDesc, FullClassMember classMember) { + FIELD_REF.computeIfAbsent(targetClass, k -> new HashMap<>()) + .computeIfAbsent(targetField, k -> new HashMap<>()) + .put(targetDesc, classMember); + } + + @Override + public void registerMethodInvocation(String targetClass, String targetMethod, String targetDesc, FullClassMember classMember) { + METHOD_INVOCATION.computeIfAbsent(targetClass, k -> new HashMap<>()) + .computeIfAbsent(targetMethod, k -> new HashMap<>()) + .put(targetDesc, classMember); + } + + @Override + public void registerLdc(String targetClass, Object targetLdc, Object replacement) { + LDC.computeIfAbsent(targetClass, k -> new HashMap<>()) + .put(targetLdc, replacement); + } + + @Override + public void registerInstantiation(String target, String replacement) { + INSTANTIATION.put(target, replacement); + } + + // Backward compatibility zone + @Deprecated + public void registerSuperType(Type target, Type replacement) { + registerSuperType(target.type, replacement.type); + } + + @Deprecated + public void registerTypeAnnotation(Type target, Type replacement) { + registerTypeAnnotation(target.type, replacement.type); + } + + @Deprecated + public void registerMethodTypeIns(Type target, Type replacement) { + registerMethodTypeIns(target.type, replacement.type); + } + + @Deprecated + public void registerMethodFieldIns(MethodNamed target, MethodNamed replacementObject) { + registerMethodNamed(target, replacementObject, FIELD_REF); + } + + @Deprecated + public void registerMethodMethodIns(MethodNamed target, MethodNamed replacementObject) { + registerMethodNamed(target, replacementObject, METHOD_INVOCATION); + } + + @Deprecated + public void registerMethodLdcIns(MethodValue target, MethodValue replacement) { + LDC.computeIfAbsent(target.owner, k -> new HashMap<>()) + .put(target.value, replacement.value); + } + + private void registerMethodNamed(MethodNamed target, MethodNamed replacementObject, Map>> map) { + String targetClass = target.owner; + String targetMember = target.name; + + String replacement = replacementObject.name; + if (replacement == null) replacement = ""; + + FullClassMember classMember = new FullClassMember(replacementObject.owner, replacement, null, null); + + if (targetMember == null) targetMember = ""; + + map.computeIfAbsent(targetClass, k -> new HashMap<>()) + .computeIfAbsent(targetMember, k -> new HashMap<>()) + .put("", classMember); + } +}