diff options
Diffstat (limited to 'src/main/java/moe/nea/firmament/init')
9 files changed, 458 insertions, 528 deletions
diff --git a/src/main/java/moe/nea/firmament/init/AutoDiscoveryPlugin.java b/src/main/java/moe/nea/firmament/init/AutoDiscoveryPlugin.java index 9b891a4..07e4549 100644 --- a/src/main/java/moe/nea/firmament/init/AutoDiscoveryPlugin.java +++ b/src/main/java/moe/nea/firmament/init/AutoDiscoveryPlugin.java @@ -1,6 +1,9 @@ package moe.nea.firmament.init; +import moe.nea.firmament.util.ErrorUtil; +import moe.nea.firmament.util.compatloader.ICompatMeta; + import java.io.File; import java.io.IOException; import java.net.MalformedURLException; @@ -16,160 +19,171 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; public class AutoDiscoveryPlugin { - private static final List<AutoDiscoveryPlugin> mixinPlugins = new ArrayList<>(); - - public static List<AutoDiscoveryPlugin> getMixinPlugins() { - return mixinPlugins; - } - - private String mixinPackage; - - public void setMixinPackage(String mixinPackage) { - this.mixinPackage = mixinPackage; - mixinPlugins.add(this); - } - - /** - * Resolves the base class root for a given class URL. This resolves either the JAR root, or the class file root. - * In either case the return value of this + the class name will resolve back to the original class url, or to other - * class urls for other classes. - */ - public URL getBaseUrlForClassUrl(URL classUrl) { - String string = classUrl.toString(); - if (classUrl.getProtocol().equals("jar")) { - try { - return new URL(string.substring(4).split("!")[0]); - } catch (MalformedURLException e) { - throw new RuntimeException(e); - } - } - if (string.endsWith(".class")) { - try { - return new URL(string.replace("\\", "/") - .replace(getClass().getCanonicalName() - .replace(".", "/") + ".class", "")); - } catch (MalformedURLException e) { - throw new RuntimeException(e); - } - } - return classUrl; - } - - /** - * Get the package that contains all the mixins. This value is set using {@link #setMixinPackage}. - */ - public String getMixinPackage() { - return mixinPackage; - } - - /** - * Get the path inside the class root to the mixin package - */ - public String getMixinBaseDir() { - return mixinPackage.replace(".", "/"); - } - - /** - * A list of all discovered mixins. - */ - private List<String> mixins = null; - - /** - * Try to add mixin class ot the mixins based on the filepath inside of the class root. - * Removes the {@code .class} file suffix, as well as the base mixin package. - * <p><b>This method cannot be called after mixin initialization.</p> - * - * @param className the name or path of a class to be registered as a mixin. - */ - public void tryAddMixinClass(String className) { - if (!className.endsWith(".class")) return; - String norm = (className.substring(0, className.length() - ".class".length())) - .replace("\\", "/") - .replace("/", "."); - if (norm.startsWith(getMixinPackage() + ".") && !norm.endsWith(".")) { - mixins.add(norm.substring(getMixinPackage().length() + 1)); - } - } - - private void tryDiscoverFromContentFile(URL url) { - Path file; - try { - file = Paths.get(getBaseUrlForClassUrl(url).toURI()); - } catch (URISyntaxException e) { - throw new RuntimeException(e); - } - System.out.println("Base directory found at " + file); - if (!Files.exists(file)) { - System.out.println("Skipping non-existing mixin root: " + file); - return; - } - if (Files.isDirectory(file)) { - walkDir(file); - } else { - walkJar(file); - } - System.out.println("Found mixins: " + mixins); - - } - - /** - * Search through the JAR or class directory to find mixins contained in {@link #getMixinPackage()} - */ - public List<String> getMixins() { - if (mixins != null) return mixins; - System.out.println("Trying to discover mixins"); - mixins = new ArrayList<>(); - URL classUrl = getClass().getProtectionDomain().getCodeSource().getLocation(); - System.out.println("Found classes at " + classUrl); - tryDiscoverFromContentFile(classUrl); - var classRoots = System.getProperty("firmament.classroots"); - if (classRoots != null && !classRoots.isBlank()) { - System.out.println("Found firmament class roots: " + classRoots); - for (String s : classRoots.split(File.pathSeparator)) { - if (s.isBlank()) { - continue; - } - try { - tryDiscoverFromContentFile(new File(s).toURI().toURL()); - } catch (MalformedURLException e) { - throw new RuntimeException(e); - } - } - } - return mixins; - } - - /** - * Search through directory for mixin classes based on {@link #getMixinBaseDir}. - * - * @param classRoot The root directory in which classes are stored for the default package. - */ - private void walkDir(Path classRoot) { - System.out.println("Trying to find mixins from directory"); - var path = classRoot.resolve(getMixinBaseDir()); - if (!Files.exists(path)) return; - try (Stream<Path> classes = Files.walk(path)) { - classes.map(it -> classRoot.relativize(it).toString()) - .forEach(this::tryAddMixinClass); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - /** - * Read through a JAR file, trying to find all mixins inside. - */ - private void walkJar(Path file) { - System.out.println("Trying to find mixins from jar file"); - try (ZipInputStream zis = new ZipInputStream(Files.newInputStream(file))) { - ZipEntry next; - while ((next = zis.getNextEntry()) != null) { - tryAddMixinClass(next.getName()); - zis.closeEntry(); - } - } catch (IOException e) { - throw new RuntimeException(e); - } - } + public static List<String> getDefaultAllMixinClassesFQNs() { + var defaultName = "moe.nea.firmament.mixins"; + var plugin = new AutoDiscoveryPlugin(); + plugin.setMixinPackage(defaultName); + var mixins = plugin.getMixins(); + return mixins.stream().map(it -> defaultName + "." + it).toList(); + } + + // TODO: remove println + + private static final List<AutoDiscoveryPlugin> mixinPlugins = new ArrayList<>(); + + public static List<AutoDiscoveryPlugin> getMixinPlugins() { + return mixinPlugins; + } + + private String mixinPackage; + + public void setMixinPackage(String mixinPackage) { + this.mixinPackage = mixinPackage; + mixinPlugins.add(this); + } + + /** + * Resolves the base class root for a given class URL. This resolves either the JAR root, or the class file root. + * In either case the return value of this + the class name will resolve back to the original class url, or to other + * class urls for other classes. + */ + public URL getBaseUrlForClassUrl(URL classUrl) { + String string = classUrl.toString(); + if (classUrl.getProtocol().equals("jar")) { + try { + return new URL(string.substring(4).split("!")[0]); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + } + if (string.endsWith(".class")) { + try { + return new URL(string.replace("\\", "/") + .replace(getClass().getCanonicalName() + .replace(".", "/") + ".class", "")); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + } + return classUrl; + } + + /** + * Get the package that contains all the mixins. This value is set using {@link #setMixinPackage}. + */ + public String getMixinPackage() { + return mixinPackage; + } + + /** + * Get the path inside the class root to the mixin package + */ + public String getMixinBaseDir() { + return mixinPackage.replace(".", "/"); + } + + /** + * A list of all discovered mixins. + */ + private List<String> mixins = null; + + /** + * Try to add mixin class ot the mixins based on the filepath inside of the class root. + * Removes the {@code .class} file suffix, as well as the base mixin package. + * <p><b>This method cannot be called after mixin initialization.</p> + * + * @param className the name or path of a class to be registered as a mixin. + */ + public void tryAddMixinClass(String className) { + if (!className.endsWith(".class")) return; + String norm = (className.substring(0, className.length() - ".class".length())) + .replace("\\", "/") + .replace("/", "."); + if (norm.startsWith(getMixinPackage() + ".") && !norm.endsWith(".") && ICompatMeta.Companion.shouldLoad(norm)) { + mixins.add(norm.substring(getMixinPackage().length() + 1)); + } + } + + private void tryDiscoverFromContentFile(URL url) { + Path file; + try { + file = Paths.get(getBaseUrlForClassUrl(url).toURI()); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + System.out.println("Base directory found at " + file); + if (!Files.exists(file)) { + System.out.println("Skipping non-existing mixin root: " + file); + return; + } + if (Files.isDirectory(file)) { + walkDir(file); + } else { + walkJar(file); + } + System.out.println("Found mixins: " + mixins); + + } + + /** + * Search through the JAR or class directory to find mixins contained in {@link #getMixinPackage()} + */ + public List<String> getMixins() { + if (mixins != null) return mixins; + try { + System.out.println("Trying to discover mixins"); + mixins = new ArrayList<>(); + URL classUrl = getClass().getProtectionDomain().getCodeSource().getLocation(); + System.out.println("Found classes at " + classUrl); + tryDiscoverFromContentFile(classUrl); + var classRoots = System.getProperty("firmament.classroots"); + if (classRoots != null && !classRoots.isBlank()) { + System.out.println("Found firmament class roots: " + classRoots); + for (String s : classRoots.split(File.pathSeparator)) { + if (s.isBlank()) { + continue; + } + tryDiscoverFromContentFile(new File(s).toURI().toURL()); + } + } + } catch (Exception e) { + e.printStackTrace(); + System.exit(1); + } + return mixins; + } + + /** + * Search through directory for mixin classes based on {@link #getMixinBaseDir}. + * + * @param classRoot The root directory in which classes are stored for the default package. + */ + private void walkDir(Path classRoot) { + System.out.println("Trying to find mixins from directory"); + var path = classRoot.resolve(getMixinBaseDir()); + if (!Files.exists(path)) return; + try (Stream<Path> classes = Files.walk(path)) { + classes.map(it -> classRoot.relativize(it).toString()) + .forEach(this::tryAddMixinClass); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * Read through a JAR file, trying to find all mixins inside. + */ + private void walkJar(Path file) { + System.out.println("Trying to find mixins from jar file"); + try (ZipInputStream zis = new ZipInputStream(Files.newInputStream(file))) { + ZipEntry next; + while ((next = zis.getNextEntry()) != null) { + tryAddMixinClass(next.getName()); + zis.closeEntry(); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } } diff --git a/src/main/java/moe/nea/firmament/init/ClientPlayerRiser.java b/src/main/java/moe/nea/firmament/init/ClientPlayerRiser.java deleted file mode 100644 index d60e3e7..0000000 --- a/src/main/java/moe/nea/firmament/init/ClientPlayerRiser.java +++ /dev/null @@ -1,75 +0,0 @@ -package moe.nea.firmament.init; - -import me.shedaniel.mm.api.ClassTinkerers; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.InsnNode; -import org.objectweb.asm.tree.MethodInsnNode; -import org.objectweb.asm.tree.MethodNode; -import org.objectweb.asm.tree.VarInsnNode; - -import java.lang.reflect.Modifier; -import java.util.Objects; - -public class ClientPlayerRiser extends RiserUtils { - @IntermediaryName(net.minecraft.entity.player.PlayerEntity.class) - String PlayerEntity; - @IntermediaryName(net.minecraft.world.World.class) - String World; - String GameProfile = "com.mojang.authlib.GameProfile"; - @IntermediaryName(net.minecraft.util.math.BlockPos.class) - String BlockPos; - @IntermediaryName(net.minecraft.client.network.AbstractClientPlayerEntity.class) - String AbstractClientPlayerEntity; - String GuiPlayer = "moe.nea.firmament.gui.entity.GuiPlayer"; - // World world, BlockPos pos, float yaw, GameProfile gameProfile - Type constructorDescriptor = Type.getMethodType(Type.VOID_TYPE, getTypeForClassName(World), getTypeForClassName(BlockPos), Type.FLOAT_TYPE, getTypeForClassName(GameProfile)); - - - private void mapClassNode(ClassNode classNode, Type superClass) { - for (MethodNode method : classNode.methods) { - if (Objects.equals(method.name, "<init>") && Type.getMethodType(method.desc).equals(constructorDescriptor)) { - modifyConstructor(method, superClass); - return; - } - } - var node = new MethodNode(Opcodes.ASM9, "<init>", constructorDescriptor.getDescriptor(), null, null); - classNode.methods.add(node); - modifyConstructor(node, superClass); - } - - - private void modifyConstructor(MethodNode method, Type superClass) { - method.access = (method.access | Modifier.PUBLIC) & ~Modifier.PRIVATE & ~Modifier.PROTECTED; - if (method.instructions.size() != 0) return; // Some other mod has already made a constructor here - - // World world, BlockPos pos, float yaw, GameProfile gameProfile - // ALOAD this - method.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); - - // ALOAD World - method.instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); - - // ALOAD BlockPos - method.instructions.add(new VarInsnNode(Opcodes.ALOAD, 2)); - - // ALOAD yaw - method.instructions.add(new VarInsnNode(Opcodes.FLOAD, 3)); - - // ALOAD gameProfile - method.instructions.add(new VarInsnNode(Opcodes.ALOAD, 4)); - - // Call super - method.instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, superClass.getInternalName(), "<init>", constructorDescriptor.getDescriptor(), false)); - - // Return - method.instructions.add(new InsnNode(Opcodes.RETURN)); - } - - @Override - public void addTinkerers() { - ClassTinkerers.addTransformation(AbstractClientPlayerEntity, it -> mapClassNode(it, getTypeForClassName(PlayerEntity)), true); - ClassTinkerers.addTransformation(GuiPlayer, it -> mapClassNode(it, getTypeForClassName(AbstractClientPlayerEntity)), true); - } -} diff --git a/src/main/java/moe/nea/firmament/init/EarlyRiser.java b/src/main/java/moe/nea/firmament/init/EarlyRiser.java index 9734e94..ae26bd7 100644 --- a/src/main/java/moe/nea/firmament/init/EarlyRiser.java +++ b/src/main/java/moe/nea/firmament/init/EarlyRiser.java @@ -4,9 +4,8 @@ package moe.nea.firmament.init; public class EarlyRiser implements Runnable { @Override public void run() { - new ClientPlayerRiser().addTinkerers(); new HandledScreenRiser().addTinkerers(); new SectionBuilderRiser().addTinkerers(); - new ItemColorsSodiumRiser().addTinkerers(); +// TODO: new ItemColorsSodiumRiser().addTinkerers(); } } diff --git a/src/main/java/moe/nea/firmament/init/HandledScreenRiser.java b/src/main/java/moe/nea/firmament/init/HandledScreenRiser.java index 355a666..98be517 100644 --- a/src/main/java/moe/nea/firmament/init/HandledScreenRiser.java +++ b/src/main/java/moe/nea/firmament/init/HandledScreenRiser.java @@ -2,8 +2,13 @@ package moe.nea.firmament.init; import me.shedaniel.mm.api.ClassTinkerers; -import net.minecraft.client.gui.Element; -import net.minecraft.client.gui.ParentElement; +import net.minecraft.client.gui.components.events.AbstractContainerEventHandler; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; +import net.minecraft.client.input.CharacterEvent; +import net.minecraft.client.input.KeyEvent; +import net.minecraft.client.input.MouseButtonEvent; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; @@ -20,30 +25,46 @@ import java.lang.reflect.Modifier; import java.util.function.Consumer; public class HandledScreenRiser extends RiserUtils { - @IntermediaryName(net.minecraft.client.gui.screen.Screen.class) - String Screen; - @IntermediaryName(net.minecraft.client.gui.screen.ingame.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", "net.minecraft.class_364", "method_25401", - mouseScrolledDesc.getDescriptor()); - // boolean keyReleased(int keyCode, int scanCode, int modifiers) - Type keyReleasedDesc = Type.getMethodType(Type.BOOLEAN_TYPE, Type.INT_TYPE, Type.INT_TYPE, Type.INT_TYPE); - 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, Type.CHAR_TYPE, Type.INT_TYPE); - String charTyped = remapper.mapMethodName("intermediary", Intermediary.<Element>className(), - Intermediary.methodName(Element::charTyped), - charTypedDesc.getDescriptor()); + Intermediary.InterClass Screen = Intermediary.<Screen>intermediaryClass(); + Intermediary.InterClass KeyInput = Intermediary.<KeyEvent>intermediaryClass(); + Intermediary.InterClass CharInput = Intermediary.<CharacterEvent>intermediaryClass(); + Intermediary.InterClass HandledScreen = Intermediary.<AbstractContainerScreen>intermediaryClass(); + Intermediary.InterClass AbstractContainerEventHandler = Intermediary.<AbstractContainerEventHandler>intermediaryClass(); + Intermediary.InterClass MouseButtonEvent = Intermediary.<MouseButtonEvent>intermediaryClass(); + Intermediary.InterMethod mouseScrolled = Intermediary.intermediaryMethod( + GuiEventListener::mouseScrolled, + Intermediary.ofClass(boolean.class), + Intermediary.ofClass(double.class), + Intermediary.ofClass(double.class), + Intermediary.ofClass(double.class), + Intermediary.ofClass(double.class) + ); + Intermediary.InterMethod mouseClickedScreen = Intermediary.intermediaryMethod( + //onMouseClicked$firmament + GuiEventListener::mouseClicked, + Intermediary.ofClass(boolean.class), + MouseButtonEvent, + Intermediary.ofClass(boolean.class) + ); + ; + Intermediary.InterMethod keyReleased = Intermediary.intermediaryMethod( + GuiEventListener::keyReleased, + Intermediary.ofClass(boolean.class), + KeyInput + ); + Intermediary.InterMethod charTyped = Intermediary.intermediaryMethod( + GuiEventListener::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); + addTransformation(Screen, this::addMouseClicked, true); } /** @@ -57,8 +78,8 @@ public class HandledScreenRiser extends RiserUtils { * @param insertInvoke insert the invokevirtual/invokestatic call */ void insertTrueHandler(MethodNode node, - Consumer<InsnList> insertLoads, - Consumer<InsnList> insertInvoke) { + Consumer<InsnList> insertLoads, + Consumer<InsnList> insertInvoke) { var insns = new InsnList(); insertLoads.accept(insns); @@ -77,26 +98,39 @@ public class HandledScreenRiser extends RiserUtils { void addKeyReleased(ClassNode classNode) { addSuperInjector( - classNode, keyReleased, keyReleasedDesc, "keyReleased_firmament", + classNode, keyReleased.mapped(), keyReleased.mappedDesc(), HandledScreen, Screen, "keyReleased_firmament", insns -> { // ALOAD 0, load this insns.add(new VarInsnNode(Opcodes.ALOAD, 0)); - // ILOAD 1-3, load args - insns.add(new VarInsnNode(Opcodes.ILOAD, 1)); - insns.add(new VarInsnNode(Opcodes.ILOAD, 2)); - insns.add(new VarInsnNode(Opcodes.ILOAD, 3)); + // ALOAD 1, load args + insns.add(new VarInsnNode(Opcodes.ALOAD, 1)); }); } + void addMouseClicked(ClassNode classNode) { + addSuperInjector( + classNode, mouseClickedScreen.mapped(), mouseClickedScreen.mappedDesc(), + Screen, AbstractContainerEventHandler, "onMouseClicked$firmament", + insns -> { + // load this + insns.add(new VarInsnNode(Opcodes.ALOAD, 0)); + // load mouse event + insns.add(new VarInsnNode(Opcodes.ALOAD, 1)); + // load doubled + insns.add(new VarInsnNode(Opcodes.ILOAD, 2)); + } + ); + } + void addCharTyped(ClassNode classNode) { addSuperInjector( - classNode, charTyped, charTypedDesc, "charTyped_firmament", + classNode, charTyped.mapped(), charTyped.mappedDesc(), + HandledScreen, Screen, "charTyped_firmament", insns -> { // ALOAD 0, load this insns.add(new VarInsnNode(Opcodes.ALOAD, 0)); - // ILOAD 1-2, load args. chars = ints - insns.add(new VarInsnNode(Opcodes.ILOAD, 1)); - insns.add(new VarInsnNode(Opcodes.ILOAD, 2)); + // ALOAD 1, load args + insns.add(new VarInsnNode(Opcodes.ALOAD, 1)); }); } @@ -104,6 +138,8 @@ public class HandledScreenRiser extends RiserUtils { ClassNode classNode, String name, Type desc, + Intermediary.InterClass currentClass, + Intermediary.InterClass parentClass, String firmamentName, Consumer<InsnList> loadArgs ) { @@ -119,8 +155,8 @@ 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(), - name, desc.getDescriptor())); + insns.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, parentClass.mapped().getInternalName(), + name, desc.getDescriptor())); // IRETURN return int on stack (booleans are int at runtime) insns.add(new InsnNode(Opcodes.IRETURN)); classNode.methods.add(keyReleasedNode); @@ -128,16 +164,16 @@ public class HandledScreenRiser extends RiserUtils { insertTrueHandler(keyReleasedNode, loadArgs, insns -> { // INVOKEVIRTUAL call custom handler insns.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, - getTypeForClassName(HandledScreen).getInternalName(), - firmamentName, - desc.getDescriptor())); + currentClass.mapped().getInternalName(), + firmamentName, + desc.getDescriptor())); }); } void addMouseScroll(ClassNode classNode) { addSuperInjector( - classNode, mouseScrolled, mouseScrolledDesc, "mouseScrolled_firmament", + classNode, mouseScrolled.mapped(), mouseScrolled.mappedDesc(), HandledScreen, Screen, "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/ItemColorsSodiumRiser.java b/src/main/java/moe/nea/firmament/init/ItemColorsSodiumRiser.java deleted file mode 100644 index 80ee9aa..0000000 --- a/src/main/java/moe/nea/firmament/init/ItemColorsSodiumRiser.java +++ /dev/null @@ -1,64 +0,0 @@ -package moe.nea.firmament.init; - -import me.shedaniel.mm.api.ClassTinkerers; -import moe.nea.firmament.util.ErrorUtil; -import net.fabricmc.loader.api.FabricLoader; -import net.minecraft.client.color.item.ItemColorProvider; -import net.minecraft.client.color.item.ItemColors; -import net.minecraft.item.ItemStack; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.InsnList; -import org.objectweb.asm.tree.InsnNode; -import org.objectweb.asm.tree.MethodInsnNode; -import org.objectweb.asm.tree.VarInsnNode; - -public class ItemColorsSodiumRiser extends RiserUtils { - @IntermediaryName(ItemColors.class) - String ItemColors; - @IntermediaryName(ItemColorProvider.class) - String ItemColorProvider; - @IntermediaryName(ItemStack.class) - String ItemStack; - String getColorProvider = "sodium$getColorProvider"; - Type getColorProviderDesc = Type.getMethodType(getTypeForClassName(ItemColorProvider), - getTypeForClassName(ItemStack)); - - @Override - public void addTinkerers() { - ClassTinkerers.addTransformation(ItemColors, this::addSodiumOverride, true); - } - - private void addSodiumOverride(ClassNode classNode) { - var node = findMethod(classNode, getColorProvider, getColorProviderDesc); - if (node == null) { - if (!FabricLoader.getInstance().isModLoaded("sodium")) - ErrorUtil.INSTANCE.softError("Sodium is present, but sodium color override could not be injected."); - return; - } - var p = node.instructions.getFirst(); - while (p != null) { - if (p.getOpcode() == Opcodes.ARETURN) { - node.instructions.insertBefore( - p, - mkOverrideSodiumCall() - ); - } - p = p.getNext(); - } - } - - private InsnList mkOverrideSodiumCall() { - var insnList = new InsnList(); - insnList.add(new VarInsnNode(Opcodes.ALOAD, 0)); - insnList.add(new InsnNode(Opcodes.SWAP)); - insnList.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, - getTypeForClassName(ItemColors).getInternalName(), - "overrideSodium_firmament", - Type.getMethodType(getTypeForClassName(ItemColorProvider), - getTypeForClassName(ItemColorProvider)).getDescriptor(), - false)); - return insnList; - } -} diff --git a/src/main/java/moe/nea/firmament/init/MixinPlugin.java b/src/main/java/moe/nea/firmament/init/MixinPlugin.java index 61e8f14..d48139b 100644 --- a/src/main/java/moe/nea/firmament/init/MixinPlugin.java +++ b/src/main/java/moe/nea/firmament/init/MixinPlugin.java @@ -8,54 +8,69 @@ import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; import org.spongepowered.asm.mixin.extensibility.IMixinInfo; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.stream.Collectors; public class MixinPlugin implements IMixinConfigPlugin { - AutoDiscoveryPlugin autoDiscoveryPlugin = new AutoDiscoveryPlugin(); - public static String mixinPackage; - @Override - public void onLoad(String mixinPackage) { - MixinExtrasBootstrap.init(); - MixinPlugin.mixinPackage = mixinPackage; - autoDiscoveryPlugin.setMixinPackage(mixinPackage); - } - - @Override - public String getRefMapperConfig() { - return null; - } - - @Override - public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { - if (!Boolean.getBoolean("firmament.debug") && mixinClassName.contains("devenv.")) { - return false; - } - return true; - } - - @Override - public void acceptTargets(Set<String> myTargets, Set<String> otherTargets) { - - } - - @Override - public List<String> getMixins() { - return autoDiscoveryPlugin.getMixins().stream().filter(it -> this.shouldApplyMixin(null, it)) - .toList(); - } - - @Override - public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { - - } - - public static List<String> appliedMixins = new ArrayList<>(); - - @Override - public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { - appliedMixins.add(mixinClassName); - } + AutoDiscoveryPlugin autoDiscoveryPlugin = new AutoDiscoveryPlugin(); + public static List<MixinPlugin> instances = new ArrayList<>(); + public String mixinPackage; + + @Override + public void onLoad(String mixinPackage) { + MixinExtrasBootstrap.init(); + instances.add(this); + this.mixinPackage = mixinPackage; + autoDiscoveryPlugin.setMixinPackage(mixinPackage); + } + + @Override |
