From d1e773120c3f0184ffea8a43c9a2d9dbdec21a03 Mon Sep 17 00:00:00 2001 From: Su5eD Date: Tue, 31 Oct 2023 10:56:53 +0100 Subject: [PATCH] Move redirectors of Map.put to KeyMappingLookup.put Remove duplicate keybindings registered by mods Fixes #173 --- gradle.properties | 2 +- .../transformer/MixinPatchTransformer.java | 31 ++++++++++++++ .../connector/mod/mixin/OptionsMixin.java | 40 +++++++++++++++++++ src/mod/resources/connectormod.mixins.json | 1 + 4 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 src/mod/java/dev/su5ed/sinytra/connector/mod/mixin/OptionsMixin.java diff --git a/gradle.properties b/gradle.properties index a7bfcfc2..f934f680 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,7 +4,7 @@ org.gradle.jvmargs=-Xmx3G org.gradle.daemon=true # Versions -versionConnector=1.0.0-beta.22 +versionConnector=1.0.0-beta.23 versionAdapter=1.7.0-1.20.1-20231012.193807 versionAdapterDefinition=1.8.4 diff --git a/src/main/java/dev/su5ed/sinytra/connector/transformer/MixinPatchTransformer.java b/src/main/java/dev/su5ed/sinytra/connector/transformer/MixinPatchTransformer.java index 02fbb5c4..81cb55be 100644 --- a/src/main/java/dev/su5ed/sinytra/connector/transformer/MixinPatchTransformer.java +++ b/src/main/java/dev/su5ed/sinytra/connector/transformer/MixinPatchTransformer.java @@ -32,6 +32,7 @@ import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; +import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.FieldInsnNode; import org.objectweb.asm.tree.InsnList; @@ -53,6 +54,7 @@ import java.util.Collection; import java.util.HashMap; import java.util.List; +import java.util.ListIterator; import java.util.Map; import java.util.Set; import java.util.stream.Stream; @@ -404,6 +406,35 @@ public class MixinPatchTransformer implements Transformer { methodNode.instructions.insert(insns); return Patch.Result.APPLY; }) + .build(), + // Move redirectors of Map.put to KeyMappingLookup.put + Patch.builder() + .targetClass("net/minecraft/client/KeyMapping") + .targetMethod("m_90854_()V") + .targetInjectionPoint("Ljava/util/Map;put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;") + .modifyInjectionPoint("Lnet/minecraftforge/client/settings/KeyMappingLookup;put(Lcom/mojang/blaze3d/platform/InputConstants$Key;Lnet/minecraft/client/KeyMapping;)V") + .targetMixinType(Patch.REDIRECT) + .modifyParams(builder -> builder + .replace(0, Type.getObjectType("net/minecraftforge/client/settings/KeyMappingLookup")) + .replace(1, Type.getObjectType("com/mojang/blaze3d/platform/InputConstants$Key")) + .replace(2, Type.getObjectType("net/minecraft/client/KeyMapping"))) + .transform((classNode, methodNode, methodContext, patchContext) -> { + for (ListIterator iterator = methodNode.instructions.iterator(); iterator.hasNext(); ) { + AbstractInsnNode insn = iterator.next(); + if (insn.getOpcode() == Opcodes.ARETURN) { + methodNode.instructions.insertBefore(insn, new InsnNode(Opcodes.POP)); + methodNode.instructions.set(insn, new InsnNode(Opcodes.RETURN)); + } + else if (insn instanceof MethodInsnNode minsn && minsn.name.equals("put") && minsn.desc.equals("(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;")) { + minsn.desc = "(Lcom/mojang/blaze3d/platform/InputConstants$Key;Lnet/minecraft/client/KeyMapping;)V"; + minsn.itf = false; + minsn.setOpcode(Opcodes.INVOKEVIRTUAL); + methodNode.instructions.insert(minsn, new InsnNode(Opcodes.ACONST_NULL)); + } + } + methodNode.desc = Type.getMethodDescriptor(Type.VOID_TYPE, Type.getArgumentTypes(methodNode.desc)); + return Patch.Result.APPLY; + }) .build() ); private static final List CLASS_TRANSFORMS = List.of( diff --git a/src/mod/java/dev/su5ed/sinytra/connector/mod/mixin/OptionsMixin.java b/src/mod/java/dev/su5ed/sinytra/connector/mod/mixin/OptionsMixin.java new file mode 100644 index 00000000..f62ff9a0 --- /dev/null +++ b/src/mod/java/dev/su5ed/sinytra/connector/mod/mixin/OptionsMixin.java @@ -0,0 +1,40 @@ +package dev.su5ed.sinytra.connector.mod.mixin; + +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; +import net.minecraft.client.KeyMapping; +import net.minecraft.client.Options; +import org.apache.commons.lang3.ArrayUtils; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.HashSet; +import java.util.Set; + +@Mixin(Options.class) +public abstract class OptionsMixin { + @Shadow + public KeyMapping[] keyMappings; + + @Inject(method = "load(Z)V", at = { + @At(value = "INVOKE", target = "Ljava/util/function/Consumer;accept(Ljava/lang/Object;)V"), + @At(value = "RETURN", ordinal = 0) + }, remap = false) + private void onForgeReLoad(boolean limited, CallbackInfo ci) { + if (limited) { + // Remove duplicate keybindings + Set seen = new HashSet<>(); + IntSet toRemove = new IntOpenHashSet(); + for (int i = 0; i < this.keyMappings.length; i++) { + KeyMapping mapping = this.keyMappings[i]; + if (!seen.add(mapping.getName())) { + toRemove.add(i); + } + } + this.keyMappings = ArrayUtils.removeAll(this.keyMappings, toRemove.toIntArray()); + } + } +} diff --git a/src/mod/resources/connectormod.mixins.json b/src/mod/resources/connectormod.mixins.json index b664483d..b480c6b8 100644 --- a/src/mod/resources/connectormod.mixins.json +++ b/src/mod/resources/connectormod.mixins.json @@ -28,6 +28,7 @@ "HumanoidArmorLayerMixin", "ItemBlockRenderTypesMixin", "ItemOverridesMixin", + "OptionsMixin", "boot.MinecraftMixin", "fieldtypes.BlockColorsMixin", "fieldtypes.ItemColorsMixin",