diff options
6 files changed, 144 insertions, 126 deletions
diff --git a/javaplugin/src/main/java/moe/nea/firmament/javaplugin/IntermediaryMethodReplacer.java b/javaplugin/src/main/java/moe/nea/firmament/javaplugin/IntermediaryMethodReplacer.java index cb87b20..d45563b 100644 --- a/javaplugin/src/main/java/moe/nea/firmament/javaplugin/IntermediaryMethodReplacer.java +++ b/javaplugin/src/main/java/moe/nea/firmament/javaplugin/IntermediaryMethodReplacer.java @@ -31,7 +31,7 @@ public class IntermediaryMethodReplacer extends TreeScanner<Void, Void> { public void replaceMethodName(JCTree.JCMethodInvocation node) { var select = node.getMethodSelect(); if (!(select instanceof JCTree.JCFieldAccess fieldAccess)) return; - if (!fieldAccess.name.contentEquals("methodName")) return; + if (!fieldAccess.name.contentEquals("intermediaryMethod")) return; if (!(node.args.head instanceof JCTree.JCMemberReference methodReference)) { plugin.utils.reportError(sourceFile, node, "Please provide a Class::method reference directly (and nothing else)"); return; @@ -43,14 +43,17 @@ public class IntermediaryMethodReplacer extends TreeScanner<Void, Void> { type.tsym.flatName().toString(), clearName ); - fieldAccess.name = plugin.names.fromString("id"); - node.args = List.of(plugin.treeMaker.Literal(intermediaryName)); + fieldAccess.name = plugin.names.fromString("ofMethod"); + var args = List.<JCTree.JCExpression>of(plugin.treeMaker.Literal(intermediaryName.interMethodName())); + args.tail = List.of(plugin.treeMaker.Literal(intermediaryName.interClassName())); + args.tail.tail = node.args.tail; + node.args = args; } public void replaceClassName(JCTree.JCMethodInvocation node) { var select = node.getMethodSelect(); if (!(select instanceof JCTree.JCFieldAccess fieldAccess)) return; - if (!fieldAccess.name.contentEquals("className")) return; + if (!fieldAccess.name.contentEquals("intermediaryClass")) return; if (node.getTypeArguments().size() != 1) { plugin.utils.reportError(sourceFile, node, "You need to explicitly provide the class you want the intermediary name for"); return; @@ -63,7 +66,7 @@ public class IntermediaryMethodReplacer extends TreeScanner<Void, Void> { plugin.utils.reportError(sourceFile, node, "Unknown class name " + sourceName); return; } - fieldAccess.name = plugin.names.fromString("id"); + fieldAccess.name = plugin.names.fromString("ofIntermediaryClass"); node.typeargs = List.nil(); node.args = List.of(plugin.treeMaker.Literal(mappedName)); } diff --git a/javaplugin/src/main/java/moe/nea/firmament/javaplugin/MappingTree.java b/javaplugin/src/main/java/moe/nea/firmament/javaplugin/MappingTree.java index eef5f9a..36713b6 100644 --- a/javaplugin/src/main/java/moe/nea/firmament/javaplugin/MappingTree.java +++ b/javaplugin/src/main/java/moe/nea/firmament/javaplugin/MappingTree.java @@ -18,15 +18,21 @@ public class MappingTree { if (sourceIndex < 0) throw new RuntimeException("Could not find source namespace " + sourceNamespace + " in mappings file."); this.classLookup = tinyV2File - .getClassEntries() - .stream() - .collect(Collectors.toMap(it -> it.getClassNames().get(sourceIndex), it -> it)); + .getClassEntries() + .stream() + .collect(Collectors.toMap(it -> it.getClassNames().get(sourceIndex), it -> it)); targetIndex = tinyV2File.getHeader().getNamespaces().indexOf(targetNamespace); if (targetIndex < 0) throw new RuntimeException("Could not find target namespace " + targetNamespace + " in mappings file."); } - public String resolveMethodToIntermediary(String className, String methodName) { + public record MethodCoordinate( + String interClassName, + String interMethodName + ) { + } + + public MethodCoordinate resolveMethodToIntermediary(String className, String methodName) { var classData = classLookup.get(className.replace(".", "/")); TinyMethod candidate = null; for (TinyMethod method : classData.getMethods()) { @@ -37,7 +43,11 @@ public class MappingTree { candidate = method; } } - return candidate.getMethodNames().get(targetIndex); + if (candidate == null) + throw new RuntimeException("Couldd not find candidate for method " + className + "." + methodName); + return new MethodCoordinate( + classData.getClassNames().get(targetIndex), + candidate.getMethodNames().get(targetIndex)); } public String resolveClassToIntermediary(String className) { @@ -46,6 +56,6 @@ public class MappingTree { return null; } return cls.getClassNames().get(targetIndex) - .replace("/", "."); + .replace("/", "."); } } diff --git a/src/main/java/moe/nea/firmament/init/HandledScreenRiser.java b/src/main/java/moe/nea/firmament/init/HandledScreenRiser.java index cb0058d..605e7ac 100644 --- a/src/main/java/moe/nea/firmament/init/HandledScreenRiser.java +++ b/src/main/java/moe/nea/firmament/init/HandledScreenRiser.java @@ -23,35 +23,36 @@ import java.lang.reflect.Modifier; import java.util.function.Consumer; public class HandledScreenRiser extends RiserUtils { - @IntermediaryName(Screen.class) - String Screen; - @IntermediaryName(KeyInput.class) - String KeyInput; - @IntermediaryName(CharInput.class) - String CharInput; - @IntermediaryName(HandledScreen.class) - String HandledScreen; - Type mouseScrolledDesc = Type.getMethodType(Type.BOOLEAN_TYPE, Type.DOUBLE_TYPE, Type.DOUBLE_TYPE, Type.DOUBLE_TYPE, Type.DOUBLE_TYPE); - String mouseScrolled = remapper.mapMethodName("intermediary", Intermediary.<Element>className(), - Intermediary.methodName(Element::mouseScrolled), - mouseScrolledDesc.getDescriptor()); - // boolean keyReleased(int keyCode, int scanCode, int modifiers) - Type keyReleasedDesc = Type.getMethodType(Type.BOOLEAN_TYPE, getTypeForClassName(KeyInput)); - String keyReleased = remapper.mapMethodName("intermediary", Intermediary.<Element>className(), - Intermediary.methodName(Element::keyReleased), - keyReleasedDesc.getDescriptor()); - // public boolean charTyped(char chr, int modifiers) - Type charTypedDesc = Type.getMethodType(Type.BOOLEAN_TYPE, getTypeForClassName(CharInput)); - String charTyped = remapper.mapMethodName("intermediary", Intermediary.<Element>className(), - Intermediary.methodName(Element::charTyped), - charTypedDesc.getDescriptor()); + Intermediary.InterClass Screen = Intermediary.<Screen>intermediaryClass(); + Intermediary.InterClass KeyInput = Intermediary.<KeyInput>intermediaryClass(); + Intermediary.InterClass CharInput = Intermediary.<CharInput>intermediaryClass(); + Intermediary.InterClass HandledScreen = Intermediary.<HandledScreen>intermediaryClass(); + Intermediary.InterMethod mouseScrolled = Intermediary.intermediaryMethod( + Element::mouseScrolled, + Intermediary.ofClass(boolean.class), + Intermediary.ofClass(double.class), + Intermediary.ofClass(double.class), + Intermediary.ofClass(double.class), + Intermediary.ofClass(double.class) + ); + Intermediary.InterMethod keyReleased = Intermediary.intermediaryMethod( + Element::keyReleased, + Intermediary.ofClass(boolean.class), + KeyInput + ); + Intermediary.InterMethod charTyped = Intermediary.intermediaryMethod( + Element::charTyped, + Intermediary.ofClass(boolean.class), + CharInput + ); + @Override public void addTinkerers() { - ClassTinkerers.addTransformation(HandledScreen, this::addMouseScroll, true); - ClassTinkerers.addTransformation(HandledScreen, this::addKeyReleased, true); - ClassTinkerers.addTransformation(HandledScreen, this::addCharTyped, true); + addTransformation(HandledScreen, this::addMouseScroll, true); + addTransformation(HandledScreen, this::addKeyReleased, true); + addTransformation(HandledScreen, this::addCharTyped, true); } /** @@ -85,7 +86,7 @@ public class HandledScreenRiser extends RiserUtils { void addKeyReleased(ClassNode classNode) { addSuperInjector( - classNode, keyReleased, keyReleasedDesc, "keyReleased_firmament", + classNode, keyReleased.mapped(), keyReleased.mappedDesc(), "keyReleased_firmament", insns -> { // ALOAD 0, load this insns.add(new VarInsnNode(Opcodes.ALOAD, 0)); @@ -96,7 +97,7 @@ public class HandledScreenRiser extends RiserUtils { void addCharTyped(ClassNode classNode) { addSuperInjector( - classNode, charTyped, charTypedDesc, "charTyped_firmament", + classNode, charTyped.mapped(), charTyped.mappedDesc(), "charTyped_firmament", insns -> { // ALOAD 0, load this insns.add(new VarInsnNode(Opcodes.ALOAD, 0)); @@ -124,7 +125,7 @@ public class HandledScreenRiser extends RiserUtils { var insns = keyReleasedNode.instructions; loadArgs.accept(insns); // INVOKESPECIAL call super method - insns.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, getTypeForClassName(Screen).getInternalName(), + insns.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, Screen.mapped().getInternalName(), name, desc.getDescriptor())); // IRETURN return int on stack (booleans are int at runtime) insns.add(new InsnNode(Opcodes.IRETURN)); @@ -133,7 +134,7 @@ public class HandledScreenRiser extends RiserUtils { insertTrueHandler(keyReleasedNode, loadArgs, insns -> { // INVOKEVIRTUAL call custom handler insns.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, - getTypeForClassName(HandledScreen).getInternalName(), + HandledScreen.mapped().getInternalName(), firmamentName, desc.getDescriptor())); }); @@ -142,7 +143,7 @@ public class HandledScreenRiser extends RiserUtils { void addMouseScroll(ClassNode classNode) { addSuperInjector( - classNode, mouseScrolled, mouseScrolledDesc, "mouseScrolled_firmament", + classNode, mouseScrolled.mapped(), mouseScrolled.mappedDesc(), "mouseScrolled_firmament", insns -> { // ALOAD 0, load this insns.add(new VarInsnNode(Opcodes.ALOAD, 0)); diff --git a/src/main/java/moe/nea/firmament/init/Intermediary.java b/src/main/java/moe/nea/firmament/init/Intermediary.java index 61494d7..3513a6b 100644 --- a/src/main/java/moe/nea/firmament/init/Intermediary.java +++ b/src/main/java/moe/nea/firmament/init/Intermediary.java @@ -7,57 +7,66 @@ import org.objectweb.asm.Type; import java.util.List; public class Intermediary { - private static final MappingResolver RESOLVER = FabricLoader.getInstance().getMappingResolver(); - - static String methodName(Object object) { - throw new AssertionError("Cannot be called at runtime"); - } - - static <T> String className() { - throw new AssertionError("Cannot be called at runtime"); - } - - static String id(String source) { - return source; - } - -// public record Class( -// Type intermediaryClass -// ) { -// public Class(String intermediaryClass) { -// this(Type.getObjectType(intermediaryClass.replace('.', '/'))); -// } -// -// public String getMappedName() { -// return RESOLVER.mapClassName("intermediary", intermediaryClass.getInternalName() -// .replace('/', '.')); -// } -// } -// -// public record Method( -// Type intermediaryClassName, -// String intermediaryMethodName, -// Type intermediaryReturnType, -// List<Type> intermediaryArgumentTypes -// ) { -// public Method( -// String intermediaryClassName, -// String intermediaryMethodName, -// String intermediaryReturnType, -// String... intermediaryArgumentTypes -// ) { -// this(intermediaryClassName, intermediaryMethodName, intermediaryReturnType, List.of(intermediaryArgumentTypes)); -// } -// -// public String getMappedMethodName() { -// return RESOLVER.mapMethodName("intermediary", -// intermediaryClassName.getInternalName().replace('/', '.')); -// } -// -// public Type getIntermediaryDescriptor() { -// return Type.getMethodType(intermediaryReturnType, intermediaryArgumentTypes.toArray(Type[]::new)); -// } -// -// -// } + private static final MappingResolver RESOLVER = FabricLoader.getInstance().getMappingResolver(); + + static InterMethod intermediaryMethod(Object object, InterClass returnType, InterClass... args) { + throw new AssertionError("Cannot be called at runtime"); + } + + static <T> InterClass intermediaryClass() { + throw new AssertionError("Cannot be called at runtime"); + } + + public static InterClass ofIntermediaryClass(String interClass) { + return new InterClass(Type.getObjectType(interClass.replace('.', '/'))); + } + + public static InterClass ofClass(Class<?> unmappedClass) { + return new InterClass(Type.getType(unmappedClass)); + } + + public static InterMethod ofMethod(String intermediary, String ownerType, InterClass returnType, InterClass... argTypes) { + return new InterMethod(intermediary, ofIntermediaryClass(ownerType), returnType, List.of(argTypes)); + } + + public record InterClass( + Type intermediary + ) { + public Type mapped() { + if (intermediary().getSort() != Type.OBJECT) + return intermediary(); + return Type.getObjectType(RESOLVER.mapClassName("intermediary", intermediary().getClassName()) + .replace('.', '/')); + } + } + + public record InterMethod( + String intermediary, + InterClass ownerType, + InterClass returnType, + List<InterClass> argumentTypes + ) { + public Type intermediaryDesc() { + return Type.getMethodType( + returnType.intermediary(), + argumentTypes().stream().map(InterClass::intermediary).toArray(Type[]::new) + ); + } + + public Type mappedDesc() { + return Type.getMethodType( + returnType.mapped(), + argumentTypes().stream().map(InterClass::mapped).toArray(Type[]::new) + ); + } + + public String mapped() { + return RESOLVER.mapMethodName( + "intermediary", + ownerType.intermediary().getClassName(), + intermediary(), + intermediaryDesc().getDescriptor() + ); + } + } } diff --git a/src/main/java/moe/nea/firmament/init/RiserUtils.java b/src/main/java/moe/nea/firmament/init/RiserUtils.java index c1c8fd1..ad4ac8f 100644 --- a/src/main/java/moe/nea/firmament/init/RiserUtils.java +++ b/src/main/java/moe/nea/firmament/init/RiserUtils.java @@ -1,12 +1,15 @@ package moe.nea.firmament.init; +import me.shedaniel.mm.api.ClassTinkerers; import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.MappingResolver; import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; +import java.util.function.Consumer; + public abstract class RiserUtils { protected Type getTypeForClassName(String className) { return Type.getObjectType(className.replace('.', '/')); @@ -24,4 +27,8 @@ public abstract class RiserUtils { return null; } + public void addTransformation(Intermediary.InterClass interClass, Consumer<ClassNode> transformer, boolean post) { + ClassTinkerers.addTransformation(interClass.mapped().getClassName(), transformer, post); + } + } diff --git a/src/main/java/moe/nea/firmament/init/SectionBuilderRiser.java b/src/main/java/moe/nea/firmament/init/SectionBuilderRiser.java index 8b65946..03c63b3 100644 --- a/src/main/java/moe/nea/firmament/init/SectionBuilderRiser.java +++ b/src/main/java/moe/nea/firmament/init/SectionBuilderRiser.java @@ -1,6 +1,5 @@ package moe.nea.firmament.init; -import me.shedaniel.mm.api.ClassTinkerers; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.block.BlockState; import net.minecraft.client.render.block.BlockRenderManager; @@ -19,36 +18,24 @@ import org.objectweb.asm.tree.VarInsnNode; public class SectionBuilderRiser extends RiserUtils { - @IntermediaryName(SectionBuilder.class) - String SectionBuilder; - @IntermediaryName(BlockPos.class) - String BlockPos; - @IntermediaryName(BlockRenderManager.class) - String BlockRenderManager; - @IntermediaryName(BlockState.class) - String BlockState; - @IntermediaryName(BlockStateModel.class) - String BlockStateModel; + Intermediary.InterClass SectionBuilder = Intermediary.<SectionBuilder>intermediaryClass(); + Intermediary.InterClass BlockPos = Intermediary.<BlockPos>intermediaryClass(); + Intermediary.InterClass BlockRenderManager = Intermediary.<BlockRenderManager>intermediaryClass(); + Intermediary.InterClass BlockState = Intermediary.<BlockState>intermediaryClass(); + Intermediary.InterClass BlockStateModel = Intermediary.<BlockStateModel>intermediaryClass(); String CustomBlockTextures = "moe.nea.firmament.features.texturepack.CustomBlockTextures"; - Type getModelDesc = Type.getMethodType( - getTypeForClassName(BlockRenderManager), - getTypeForClassName(BlockState) - ); - String getModel = remapper.mapMethodName( - "intermediary", - Intermediary.<BlockRenderManager>className(), - Intermediary.methodName(net.minecraft.client.render.block.BlockRenderManager::getModel), - Type.getMethodDescriptor( - getTypeForClassName(Intermediary.<BlockStateModel>className()), - getTypeForClassName(Intermediary.<BlockState>className()) - ) - ); + Intermediary.InterMethod getModel = + Intermediary.intermediaryMethod( + net.minecraft.client.render.block.BlockRenderManager::getModel, + BlockStateModel, + BlockState + ); @Override public void addTinkerers() { if (FabricLoader.getInstance().isModLoaded("fabric-renderer-indigo")) - ClassTinkerers.addTransformation(SectionBuilder, this::handle, true); + addTransformation(SectionBuilder, this::handle, true); } private void handle(ClassNode classNode) { @@ -67,10 +54,10 @@ public class SectionBuilderRiser extends RiserUtils { private void handleIndigo(MethodNode method) { LocalVariableNode blockPosVar = null, blockStateVar = null; for (LocalVariableNode localVariable : method.localVariables) { - if (Type.getType(localVariable.desc).equals(getTypeForClassName(BlockPos))) { + if (Type.getType(localVariable.desc).equals(BlockPos.mapped())) { blockPosVar = localVariable; } - if (Type.getType(localVariable.desc).equals(getTypeForClassName(BlockState))) { + if (Type.getType(localVariable.desc).equals(BlockState.mapped())) { blockStateVar = localVariable; } } @@ -81,7 +68,8 @@ public class SectionBuilderRiser extends RiserUtils { for (AbstractInsnNode instruction : method.instructions) { if (instruction.getOpcode() != Opcodes.INVOKEVIRTUAL) continue; var methodInsn = (MethodInsnNode) instruction; - if (!(methodInsn.name.equals(getModel) && Type.getObjectType(methodInsn.owner).equals(getTypeForClassName(BlockRenderManager)))) + if (!(methodInsn.name.equals(getModel.mapped()) && + Type.getObjectType(methodInsn.owner).equals(BlockRenderManager.mapped()))) continue; method.instructions.insertBefore( methodInsn, @@ -106,10 +94,10 @@ public class SectionBuilderRiser extends RiserUtils { getTypeForClassName(CustomBlockTextures).getInternalName(), "patchIndigo", Type.getMethodDescriptor( - getTypeForClassName(BlockStateModel), - getTypeForClassName(BlockStateModel), - getTypeForClassName(BlockPos), - getTypeForClassName(BlockState)), + (BlockStateModel).mapped(), + (BlockStateModel).mapped(), + (BlockPos).mapped(), + (BlockState).mapped()), false )); method.instructions.insert(methodInsn, insnList); |
