From 2a1d09fcc035f2ff6ec8a8a75f0ecdaeb9ed294d Mon Sep 17 00:00:00 2001 From: Empa <42304516+ItsEmpa@users.noreply.github.com> Date: Wed, 20 Nov 2024 22:18:31 +0100 Subject: [PATCH] Fix: Custom Garden Keybinds (#2948) Co-authored-by: Empa Co-authored-by: hannibal2 <24389977+hannibal00212@users.noreply.github.com> --- .../config/features/garden/KeyBindConfig.java | 49 ++---- .../garden/farming/GardenCustomKeybinds.kt | 151 ++++++++++++------ .../transformers/AccessorKeyBinding.java | 9 +- .../mixins/transformers/MixinKeyBinding.java | 5 +- .../skyhanni/utils/KeyboardManager.kt | 3 + 5 files changed, 126 insertions(+), 91 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/garden/KeyBindConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/garden/KeyBindConfig.java index 8c7d11cf83a7..0ab88ae7d6e9 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/garden/KeyBindConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/garden/KeyBindConfig.java @@ -1,12 +1,14 @@ package at.hannibal2.skyhanni.config.features.garden; import at.hannibal2.skyhanni.config.FeatureToggle; +import at.hannibal2.skyhanni.features.garden.farming.GardenCustomKeybinds; +import at.hannibal2.skyhanni.utils.KeyboardManager; import com.google.gson.annotations.Expose; import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean; import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorButton; import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorKeybind; import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; -import net.minecraft.client.Minecraft; +import io.github.notenoughupdates.moulconfig.observer.Property; import org.lwjgl.input.Keyboard; public class KeyBindConfig { @@ -23,70 +25,49 @@ public class KeyBindConfig { @ConfigOption(name = "Disable All", desc = "Disable all keys.") @ConfigEditorButton(buttonText = "Disable") - public Runnable presetDisable = () -> { - attack = Keyboard.KEY_NONE; - useItem = Keyboard.KEY_NONE; - left = Keyboard.KEY_NONE; - right = Keyboard.KEY_NONE; - forward = Keyboard.KEY_NONE; - back = Keyboard.KEY_NONE; - jump = Keyboard.KEY_NONE; - sneak = Keyboard.KEY_NONE; - - Minecraft.getMinecraft().thePlayer.closeScreen(); - }; + public Runnable presetDisable = GardenCustomKeybinds::disableAll; @ConfigOption(name = "Set Default", desc = "Reset all keys to default.") @ConfigEditorButton(buttonText = "Default") - public Runnable presetDefault = () -> { - attack = -100; - useItem = -99; - left = Keyboard.KEY_A; - right = Keyboard.KEY_D; - forward = Keyboard.KEY_W; - back = Keyboard.KEY_S; - jump = Keyboard.KEY_SPACE; - sneak = Keyboard.KEY_LSHIFT; - Minecraft.getMinecraft().thePlayer.closeScreen(); - }; + public Runnable presetDefault = GardenCustomKeybinds::defaultAll; @Expose @ConfigOption(name = "Attack", desc = "") - @ConfigEditorKeybind(defaultKey = -100) - public int attack = -100; + @ConfigEditorKeybind(defaultKey = KeyboardManager.LEFT_MOUSE) + public Property attack = Property.of(KeyboardManager.LEFT_MOUSE); @Expose @ConfigOption(name = "Use Item", desc = "") - @ConfigEditorKeybind(defaultKey = -99) - public int useItem = -99; + @ConfigEditorKeybind(defaultKey = KeyboardManager.RIGHT_MOUSE) + public Property useItem = Property.of(KeyboardManager.RIGHT_MOUSE); @Expose @ConfigOption(name = "Move Left", desc = "") @ConfigEditorKeybind(defaultKey = Keyboard.KEY_A) - public int left = Keyboard.KEY_A; + public Property left = Property.of(Keyboard.KEY_A); @Expose @ConfigOption(name = "Move Right", desc = "") @ConfigEditorKeybind(defaultKey = Keyboard.KEY_D) - public int right = Keyboard.KEY_D; + public Property right = Property.of(Keyboard.KEY_D); @Expose @ConfigOption(name = "Move Forward", desc = "") @ConfigEditorKeybind(defaultKey = Keyboard.KEY_W) - public int forward = Keyboard.KEY_W; + public Property forward = Property.of(Keyboard.KEY_W); @Expose @ConfigOption(name = "Move Back", desc = "") @ConfigEditorKeybind(defaultKey = Keyboard.KEY_S) - public int back = Keyboard.KEY_S; + public Property back = Property.of(Keyboard.KEY_S); @Expose @ConfigOption(name = "Jump", desc = "") @ConfigEditorKeybind(defaultKey = Keyboard.KEY_SPACE) - public int jump = Keyboard.KEY_SPACE; + public Property jump = Property.of(Keyboard.KEY_SPACE); @Expose @ConfigOption(name = "Sneak", desc = "") @ConfigEditorKeybind(defaultKey = Keyboard.KEY_LSHIFT) - public int sneak = Keyboard.KEY_LSHIFT; + public Property sneak = Property.of(Keyboard.KEY_LSHIFT); } diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenCustomKeybinds.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenCustomKeybinds.kt index 529414a4eaba..75855d076466 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenCustomKeybinds.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenCustomKeybinds.kt @@ -1,20 +1,25 @@ package at.hannibal2.skyhanni.features.garden.farming import at.hannibal2.skyhanni.config.ConfigUpdaterMigrator +import at.hannibal2.skyhanni.events.ConfigLoadEvent +import at.hannibal2.skyhanni.events.LorenzTickEvent +import at.hannibal2.skyhanni.events.SecondPassedEvent import at.hannibal2.skyhanni.features.garden.GardenAPI import at.hannibal2.skyhanni.mixins.transformers.AccessorKeyBinding import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule +import at.hannibal2.skyhanni.test.command.ErrorManager import at.hannibal2.skyhanni.utils.ChatUtils -import at.hannibal2.skyhanni.utils.KeyboardManager.isKeyHeld +import at.hannibal2.skyhanni.utils.ConditionalUtils +import at.hannibal2.skyhanni.utils.KeyboardManager +import at.hannibal2.skyhanni.utils.KeyboardManager.isKeyClicked import at.hannibal2.skyhanni.utils.SimpleTimeMark +import io.github.notenoughupdates.moulconfig.observer.Property import net.minecraft.client.Minecraft import net.minecraft.client.gui.inventory.GuiEditSign import net.minecraft.client.settings.KeyBinding import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import org.lwjgl.input.Keyboard -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable -import java.util.IdentityHashMap import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.seconds @@ -24,71 +29,119 @@ object GardenCustomKeybinds { private val config get() = GardenAPI.config.keyBind private val mcSettings get() = Minecraft.getMinecraft().gameSettings - private val map: MutableMap Int> = IdentityHashMap() + private var map: Map = emptyMap() private var lastWindowOpenTime = SimpleTimeMark.farPast() private var lastDuplicateKeybindsWarnTime = SimpleTimeMark.farPast() + private var isDuplicate = false - init { - map[mcSettings.keyBindAttack] = { config.attack } - map[mcSettings.keyBindUseItem] = { config.useItem } - map[mcSettings.keyBindLeft] = { config.left } - map[mcSettings.keyBindRight] = { config.right } - map[mcSettings.keyBindForward] = { config.forward } - map[mcSettings.keyBindBack] = { config.back } - map[mcSettings.keyBindJump] = { config.jump } - map[mcSettings.keyBindSneak] = { config.sneak } + private fun Int.keybind() = (mcSettings.keyBindAttack as AccessorKeyBinding).hash_skyhanni.lookup(this) + ?: ErrorManager.skyHanniError("Keybind $this not found") + + @JvmStatic + fun isKeyDown(keyBinding: KeyBinding, cir: CallbackInfoReturnable) { + if (!isActive()) return + val override = map[keyBinding]?.keybind() ?: return + val accessor = override as AccessorKeyBinding + cir.returnValue = accessor.pressed_skyhanni } - private fun isEnabled() = GardenAPI.inGarden() && config.enabled && !(GardenAPI.onBarnPlot && config.excludeBarn) + @JvmStatic + fun isKeyPressed(keyBinding: KeyBinding, cir: CallbackInfoReturnable) { + if (!isActive()) return + val override = map[keyBinding] ?: return + cir.returnValue = override.isKeyClicked() + } + + @SubscribeEvent + fun onTick(event: LorenzTickEvent) { + if (!isEnabled()) return + val screen = Minecraft.getMinecraft().currentScreen ?: return + if (screen !is GuiEditSign) return + lastWindowOpenTime = SimpleTimeMark.now() + } - private fun isActive(): Boolean { - if (!isEnabled()) return false - if (GardenAPI.toolInHand == null) return false + @SubscribeEvent + fun onSecondPassed(event: SecondPassedEvent) { + if (!isEnabled()) return + if (!isDuplicate || lastDuplicateKeybindsWarnTime.passedSince() < 30.seconds) return + ChatUtils.chatAndOpenConfig( + "Duplicate Custom Keybinds aren't allowed!", + GardenAPI.config::keyBind, + ) + lastDuplicateKeybindsWarnTime = SimpleTimeMark.now() + } - if (Minecraft.getMinecraft().currentScreen != null) { - if (Minecraft.getMinecraft().currentScreen is GuiEditSign) { - lastWindowOpenTime = SimpleTimeMark.now() + @SubscribeEvent + fun onConfigLoad(event: ConfigLoadEvent) { + with(config) { + ConditionalUtils.onToggle(attack, useItem, left, right, forward, back, jump, sneak) { + update() } - return false + update() } + } - // TODO remove workaround - if (lastWindowOpenTime.passedSince() < 300.milliseconds) return false - - val areDuplicates = map.values - .map { it() } - .filter { it != Keyboard.KEY_NONE } - .let { values -> values.size != values.toSet().size } - if (areDuplicates) { - if (lastDuplicateKeybindsWarnTime.passedSince() > 30.seconds) { - ChatUtils.chatAndOpenConfig( - "Duplicate Custom Keybinds aren't allowed!", - GardenAPI.config::keyBind - ) - lastDuplicateKeybindsWarnTime = SimpleTimeMark.now() + private fun update() { + with(config) { + with(mcSettings) { + map = buildMap { + fun add(keyBinding: KeyBinding, property: Property) { + val value = property.get() + if (value != keyBinding.keyCode) put(keyBinding, value) + } + add(keyBindAttack, attack) + add(keyBindUseItem, useItem) + add(keyBindLeft, left) + add(keyBindRight, right) + add(keyBindForward, forward) + add(keyBindBack, back) + add(keyBindJump, jump) + add(keyBindSneak, sneak) + } } - return false } + calculateDuplicates() + lastDuplicateKeybindsWarnTime = SimpleTimeMark.farPast() + KeyBinding.unPressAllKeys() + } - return true + private fun calculateDuplicates() { + isDuplicate = map.values + .filter { it != Keyboard.KEY_NONE } + .let { values -> values.size != values.toSet().size } } + private fun isEnabled() = GardenAPI.inGarden() && config.enabled && !(GardenAPI.onBarnPlot && config.excludeBarn) + + private fun isActive(): Boolean = + isEnabled() && GardenAPI.toolInHand != null && !isDuplicate && lastWindowOpenTime.passedSince() > 300.milliseconds + @JvmStatic - fun isKeyDown(keyBinding: KeyBinding, cir: CallbackInfoReturnable) { - if (!isActive()) return - val override = map[keyBinding] ?: return - val keyCode = override() - cir.returnValue = keyCode.isKeyHeld() + fun disableAll() { + with(config) { + attack.set(Keyboard.KEY_NONE) + useItem.set(Keyboard.KEY_NONE) + left.set(Keyboard.KEY_NONE) + right.set(Keyboard.KEY_NONE) + forward.set(Keyboard.KEY_NONE) + back.set(Keyboard.KEY_NONE) + jump.set(Keyboard.KEY_NONE) + sneak.set(Keyboard.KEY_NONE) + } } @JvmStatic - fun onTick(keyCode: Int, ci: CallbackInfo) { - if (!isActive()) return - if (keyCode == 0) return - val keyBinding = map.entries.firstOrNull { it.value() == keyCode }?.key ?: return - ci.cancel() - keyBinding as AccessorKeyBinding - keyBinding.pressTime_skyhanni++ + fun defaultAll() { + with(config) { + attack.set(KeyboardManager.LEFT_MOUSE) + useItem.set(KeyboardManager.RIGHT_MOUSE) + left.set(Keyboard.KEY_A) + right.set(Keyboard.KEY_D) + forward.set(Keyboard.KEY_W) + back.set(Keyboard.KEY_S) + jump.set(Keyboard.KEY_SPACE) + sneak.set(Keyboard.KEY_LSHIFT) + } } @SubscribeEvent diff --git a/src/main/java/at/hannibal2/skyhanni/mixins/transformers/AccessorKeyBinding.java b/src/main/java/at/hannibal2/skyhanni/mixins/transformers/AccessorKeyBinding.java index e487ee73d7bd..7d3a9db4bcb6 100644 --- a/src/main/java/at/hannibal2/skyhanni/mixins/transformers/AccessorKeyBinding.java +++ b/src/main/java/at/hannibal2/skyhanni/mixins/transformers/AccessorKeyBinding.java @@ -1,15 +1,16 @@ package at.hannibal2.skyhanni.mixins.transformers; import net.minecraft.client.settings.KeyBinding; +import net.minecraft.util.IntHashMap; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; @Mixin(KeyBinding.class) public interface AccessorKeyBinding { - @Accessor("pressTime") - int getPressTime_skyhanni(); + @Accessor("pressed") + boolean getPressed_skyhanni(); - @Accessor("pressTime") - void setPressTime_skyhanni(int pressTime); + @Accessor("hash") + IntHashMap getHash_skyhanni(); } diff --git a/src/main/java/at/hannibal2/skyhanni/mixins/transformers/MixinKeyBinding.java b/src/main/java/at/hannibal2/skyhanni/mixins/transformers/MixinKeyBinding.java index 01efda5cebb8..8e73dc15d0f2 100644 --- a/src/main/java/at/hannibal2/skyhanni/mixins/transformers/MixinKeyBinding.java +++ b/src/main/java/at/hannibal2/skyhanni/mixins/transformers/MixinKeyBinding.java @@ -12,10 +12,6 @@ @Mixin(KeyBinding.class) public class MixinKeyBinding { - @Inject(method = "onTick", at = @At("HEAD"), cancellable = true) - private static void noOnTick(int keyCode, CallbackInfo ci) { - GardenCustomKeybinds.onTick(keyCode, ci); - } @Inject(method = "isKeyDown", at = @At("HEAD"), cancellable = true) public void noIsKeyDown(CallbackInfoReturnable cir) { @@ -26,6 +22,7 @@ public void noIsKeyDown(CallbackInfoReturnable cir) { @Inject(method = "isPressed", at = @At("HEAD"), cancellable = true) public void noIsPressed(CallbackInfoReturnable cir) { + GardenCustomKeybinds.isKeyPressed((KeyBinding) (Object) this, cir); TextInput.Companion.onMinecraftInput((KeyBinding) (Object) this, cir); GraphEditor.INSTANCE.onMinecraftInput((KeyBinding) (Object) this, cir); } diff --git a/src/main/java/at/hannibal2/skyhanni/utils/KeyboardManager.kt b/src/main/java/at/hannibal2/skyhanni/utils/KeyboardManager.kt index aa0dd8e7c405..b6767d4e4539 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/KeyboardManager.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/KeyboardManager.kt @@ -20,6 +20,9 @@ import org.lwjgl.input.Mouse @SkyHanniModule object KeyboardManager { + const val LEFT_MOUSE = -100 + const val RIGHT_MOUSE = -99 + private var lastClickedMouseButton = -1 // A mac-only key, represents Windows key on windows (but different key code)