From 28c994566a5d6cc1187015bd513226a785aa76b0 Mon Sep 17 00:00:00 2001 From: beanbag44 Date: Tue, 29 Jul 2025 14:23:19 +0100 Subject: [PATCH 1/3] use the players keybinds and use minecrafts bind handling to account for toggle binds --- .../lambda/mixin/MinecraftClientMixin.java | 15 ++++ .../com/lambda/mixin/input/KeyboardMixin.java | 14 ++++ .../module/modules/player/InventoryMove.kt | 74 ++++++------------- .../src/main/resources/lambda.accesswidener | 2 + 4 files changed, 53 insertions(+), 52 deletions(-) diff --git a/common/src/main/java/com/lambda/mixin/MinecraftClientMixin.java b/common/src/main/java/com/lambda/mixin/MinecraftClientMixin.java index 8e0d2bebd..8243ce532 100644 --- a/common/src/main/java/com/lambda/mixin/MinecraftClientMixin.java +++ b/common/src/main/java/com/lambda/mixin/MinecraftClientMixin.java @@ -23,10 +23,12 @@ import com.lambda.event.events.InventoryEvent; import com.lambda.event.events.TickEvent; import com.lambda.module.modules.player.Interact; +import com.lambda.module.modules.player.InventoryMove; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.ingame.ScreenHandlerProvider; import net.minecraft.client.network.ClientPlayerInteractionManager; +import net.minecraft.client.option.KeyBinding; import net.minecraft.util.thread.ThreadExecutor; import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; @@ -91,6 +93,19 @@ private void onScreenRemove(@Nullable Screen screen, CallbackInfo ci) { } } + @Redirect(method = "setScreen", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/option/KeyBinding;unpressAll()V")) + private void redirectUnPressAll() { + if (InventoryMove.INSTANCE.isDisabled() || InventoryMove.hasInputOrNull(currentScreen)) { + KeyBinding.unpressAll(); + return; + } + KeyBinding.KEYS_BY_ID.values().forEach(bind -> { + if (!InventoryMove.isKeyMovementRelated(bind.boundKey.getCode())) { + bind.reset(); + } + }); + } + @Redirect(method = "doItemUse", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerInteractionManager;isBreakingBlock()Z")) boolean injectMultiActon(ClientPlayerInteractionManager instance) { if (instance == null) return true; diff --git a/common/src/main/java/com/lambda/mixin/input/KeyboardMixin.java b/common/src/main/java/com/lambda/mixin/input/KeyboardMixin.java index 4f061e0ac..ed8d8c85e 100644 --- a/common/src/main/java/com/lambda/mixin/input/KeyboardMixin.java +++ b/common/src/main/java/com/lambda/mixin/input/KeyboardMixin.java @@ -19,12 +19,17 @@ import com.lambda.event.EventFlow; import com.lambda.event.events.KeyboardEvent; +import com.lambda.module.modules.player.InventoryMove; import net.minecraft.client.Keyboard; +import net.minecraft.client.option.KeyBinding; +import net.minecraft.client.util.InputUtil; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import static com.lambda.Lambda.getMc; + @Mixin(Keyboard.class) public class KeyboardMixin { @Inject(method = "onKey", at = @At("HEAD")) @@ -33,6 +38,15 @@ private void onKey(long window, int key, int scancode, int action, int modifiers EventFlow.post(new KeyboardEvent.Press(key, scancode, action, modifiers)); } + @Inject(method = "onKey", at = @At("RETURN")) + private void onKeyTail(long window, int key, int scancode, int action, int modifiers, CallbackInfo ci) { + if (InventoryMove.INSTANCE.isDisabled() || InventoryMove.hasInputOrNull(getMc().currentScreen)) return; + if (InventoryMove.isKeyMovementRelated(key)) { + InputUtil.Key fromCode = InputUtil.fromKeyCode(key, scancode); + KeyBinding.setKeyPressed(fromCode, action != 0); + } + } + @Inject(method = "onChar", at = @At("HEAD")) private void onChar(long window, int codePoint, int modifiers, CallbackInfo ci) { char[] chars = Character.toChars(codePoint); diff --git a/common/src/main/kotlin/com/lambda/module/modules/player/InventoryMove.kt b/common/src/main/kotlin/com/lambda/module/modules/player/InventoryMove.kt index ad4b2eb9c..522698b6a 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/player/InventoryMove.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/player/InventoryMove.kt @@ -17,29 +17,15 @@ package com.lambda.module.modules.player -import com.lambda.event.events.MovementEvent -import com.lambda.event.listener.SafeListener.Companion.listen +import com.lambda.Lambda.mc import com.lambda.gui.LambdaScreen -import com.lambda.interaction.request.rotation.Rotation -import com.lambda.interaction.request.rotation.RotationConfig -import com.lambda.interaction.request.rotation.RotationManager.onRotate -import com.lambda.interaction.request.rotation.RotationMode -import com.lambda.interaction.request.rotation.visibilty.lookAt import com.lambda.module.Module import com.lambda.module.tag.ModuleTag -import com.lambda.util.KeyboardUtils.isKeyPressed -import com.lambda.util.math.MathUtils.toDouble -import com.lambda.util.math.MathUtils.toFloatSign -import com.lambda.util.player.MovementUtils.buildMovementInput -import com.lambda.util.player.MovementUtils.mergeFrom import net.minecraft.client.gui.screen.ChatScreen import net.minecraft.client.gui.screen.Screen import net.minecraft.client.gui.screen.ingame.AnvilScreen import net.minecraft.client.gui.screen.ingame.CommandBlockScreen -import net.minecraft.client.gui.screen.ingame.CreativeInventoryScreen import net.minecraft.client.gui.screen.ingame.SignEditScreen -import net.minecraft.client.network.ClientPlayerEntity -import org.lwjgl.glfw.GLFW.* object InventoryMove : Module( name = "InventoryMove", @@ -47,47 +33,31 @@ object InventoryMove : Module( defaultTags = setOf(ModuleTag.PLAYER, ModuleTag.MOVEMENT) ) { private val speed by setting("Rotation Speed", 5, 1..20, 1, unit = "°/tick") - private val rotationConfig = RotationConfig.Instant(RotationMode.Lock) /** * Whether the current screen has text inputs or is null */ - val Screen?.hasInputOrNull: Boolean - get() = this is ChatScreen || - this is SignEditScreen || - this is AnvilScreen || - this is CommandBlockScreen || - this is LambdaScreen || - this == null - - init { - listen(20250415) { event -> - if (mc.currentScreen.hasInputOrNull) return@listen - - val forward = isKeyPressed(GLFW_KEY_W).toDouble() - - isKeyPressed(GLFW_KEY_S).toDouble() - - val strafe = isKeyPressed(GLFW_KEY_A).toDouble() - - isKeyPressed(GLFW_KEY_D).toDouble() - - val jump = isKeyPressed(GLFW_KEY_SPACE) - val sneak = isKeyPressed(GLFW_KEY_LEFT_SHIFT) - - player.isSprinting = isKeyPressed(GLFW_KEY_LEFT_CONTROL) - event.input.mergeFrom(buildMovementInput(forward, strafe, jump, sneak)) - } - - onRotate { - if (mc.currentScreen.hasInputOrNull) return@onRotate - - val pitch = (isKeyPressed(GLFW_KEY_DOWN, GLFW_KEY_KP_2).toFloatSign() - - isKeyPressed(GLFW_KEY_UP, GLFW_KEY_KP_8).toFloatSign()) * speed - val yaw = (isKeyPressed(GLFW_KEY_RIGHT, GLFW_KEY_KP_6).toFloatSign() - - isKeyPressed(GLFW_KEY_LEFT, GLFW_KEY_KP_4).toFloatSign()) * speed - - lookAt( - Rotation(player.yaw + yaw, (player.pitch + pitch).coerceIn(-90f, 90f)) - ).requestBy(rotationConfig) + @JvmStatic + fun hasInputOrNull(screen: Screen?) = + screen is ChatScreen || + screen is SignEditScreen || + screen is AnvilScreen || + screen is CommandBlockScreen || + screen is LambdaScreen || + screen == null + + @JvmStatic + fun isKeyMovementRelated(key: Int): Boolean { + val options = mc.options + return when (key) { + options.forwardKey.boundKey.code, + options.backKey.boundKey.code, + options.leftKey.boundKey.code, + options.rightKey.boundKey.code, + options.jumpKey.boundKey.code, + options.sprintKey.boundKey.code, + options.sneakKey.boundKey.code -> true + else -> false } } } diff --git a/common/src/main/resources/lambda.accesswidener b/common/src/main/resources/lambda.accesswidener index 31054ddb6..62d336f16 100644 --- a/common/src/main/resources/lambda.accesswidener +++ b/common/src/main/resources/lambda.accesswidener @@ -7,6 +7,8 @@ accessible field net/minecraft/client/MinecraftClient pausedTickDelta F accessible field net/minecraft/client/MinecraftClient thread Ljava/lang/Thread; accessible field net/minecraft/client/MinecraftClient uptimeInTicks J accessible field net/minecraft/client/option/KeyBinding boundKey Lnet/minecraft/client/util/InputUtil$Key; +accessible field net/minecraft/client/option/KeyBinding KEYS_BY_ID Ljava/util/Map; +accessible method net/minecraft/client/option/KeyBinding reset ()V # World accessible field net/minecraft/client/world/ClientWorld entityManager Lnet/minecraft/client/world/ClientEntityManager; From 1f3840b61d214f6420a08507c1d68ba60afc727f Mon Sep 17 00:00:00 2001 From: beanbag44 Date: Tue, 29 Jul 2025 16:16:03 +0100 Subject: [PATCH 2/3] use the players keybinds and use minecrafts bind handling to account for toggle binds --- .../lambda/mixin/MinecraftClientMixin.java | 15 ++++ .../com/lambda/mixin/input/KeyboardMixin.java | 14 ++++ .../module/modules/player/InventoryMove.kt | 76 ++++++++++--------- .../src/main/resources/lambda.accesswidener | 2 + 4 files changed, 70 insertions(+), 37 deletions(-) diff --git a/common/src/main/java/com/lambda/mixin/MinecraftClientMixin.java b/common/src/main/java/com/lambda/mixin/MinecraftClientMixin.java index 8e0d2bebd..8243ce532 100644 --- a/common/src/main/java/com/lambda/mixin/MinecraftClientMixin.java +++ b/common/src/main/java/com/lambda/mixin/MinecraftClientMixin.java @@ -23,10 +23,12 @@ import com.lambda.event.events.InventoryEvent; import com.lambda.event.events.TickEvent; import com.lambda.module.modules.player.Interact; +import com.lambda.module.modules.player.InventoryMove; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.ingame.ScreenHandlerProvider; import net.minecraft.client.network.ClientPlayerInteractionManager; +import net.minecraft.client.option.KeyBinding; import net.minecraft.util.thread.ThreadExecutor; import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; @@ -91,6 +93,19 @@ private void onScreenRemove(@Nullable Screen screen, CallbackInfo ci) { } } + @Redirect(method = "setScreen", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/option/KeyBinding;unpressAll()V")) + private void redirectUnPressAll() { + if (InventoryMove.INSTANCE.isDisabled() || InventoryMove.hasInputOrNull(currentScreen)) { + KeyBinding.unpressAll(); + return; + } + KeyBinding.KEYS_BY_ID.values().forEach(bind -> { + if (!InventoryMove.isKeyMovementRelated(bind.boundKey.getCode())) { + bind.reset(); + } + }); + } + @Redirect(method = "doItemUse", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerInteractionManager;isBreakingBlock()Z")) boolean injectMultiActon(ClientPlayerInteractionManager instance) { if (instance == null) return true; diff --git a/common/src/main/java/com/lambda/mixin/input/KeyboardMixin.java b/common/src/main/java/com/lambda/mixin/input/KeyboardMixin.java index 4f061e0ac..ed8d8c85e 100644 --- a/common/src/main/java/com/lambda/mixin/input/KeyboardMixin.java +++ b/common/src/main/java/com/lambda/mixin/input/KeyboardMixin.java @@ -19,12 +19,17 @@ import com.lambda.event.EventFlow; import com.lambda.event.events.KeyboardEvent; +import com.lambda.module.modules.player.InventoryMove; import net.minecraft.client.Keyboard; +import net.minecraft.client.option.KeyBinding; +import net.minecraft.client.util.InputUtil; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import static com.lambda.Lambda.getMc; + @Mixin(Keyboard.class) public class KeyboardMixin { @Inject(method = "onKey", at = @At("HEAD")) @@ -33,6 +38,15 @@ private void onKey(long window, int key, int scancode, int action, int modifiers EventFlow.post(new KeyboardEvent.Press(key, scancode, action, modifiers)); } + @Inject(method = "onKey", at = @At("RETURN")) + private void onKeyTail(long window, int key, int scancode, int action, int modifiers, CallbackInfo ci) { + if (InventoryMove.INSTANCE.isDisabled() || InventoryMove.hasInputOrNull(getMc().currentScreen)) return; + if (InventoryMove.isKeyMovementRelated(key)) { + InputUtil.Key fromCode = InputUtil.fromKeyCode(key, scancode); + KeyBinding.setKeyPressed(fromCode, action != 0); + } + } + @Inject(method = "onChar", at = @At("HEAD")) private void onChar(long window, int codePoint, int modifiers, CallbackInfo ci) { char[] chars = Character.toChars(codePoint); diff --git a/common/src/main/kotlin/com/lambda/module/modules/player/InventoryMove.kt b/common/src/main/kotlin/com/lambda/module/modules/player/InventoryMove.kt index ad4b2eb9c..d52ea6768 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/player/InventoryMove.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/player/InventoryMove.kt @@ -17,8 +17,7 @@ package com.lambda.module.modules.player -import com.lambda.event.events.MovementEvent -import com.lambda.event.listener.SafeListener.Companion.listen +import com.lambda.Lambda.mc import com.lambda.gui.LambdaScreen import com.lambda.interaction.request.rotation.Rotation import com.lambda.interaction.request.rotation.RotationConfig @@ -28,57 +27,33 @@ import com.lambda.interaction.request.rotation.visibilty.lookAt import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.util.KeyboardUtils.isKeyPressed -import com.lambda.util.math.MathUtils.toDouble import com.lambda.util.math.MathUtils.toFloatSign -import com.lambda.util.player.MovementUtils.buildMovementInput -import com.lambda.util.player.MovementUtils.mergeFrom import net.minecraft.client.gui.screen.ChatScreen import net.minecraft.client.gui.screen.Screen import net.minecraft.client.gui.screen.ingame.AnvilScreen import net.minecraft.client.gui.screen.ingame.CommandBlockScreen -import net.minecraft.client.gui.screen.ingame.CreativeInventoryScreen import net.minecraft.client.gui.screen.ingame.SignEditScreen -import net.minecraft.client.network.ClientPlayerEntity -import org.lwjgl.glfw.GLFW.* +import org.lwjgl.glfw.GLFW.GLFW_KEY_DOWN +import org.lwjgl.glfw.GLFW.GLFW_KEY_KP_2 +import org.lwjgl.glfw.GLFW.GLFW_KEY_KP_4 +import org.lwjgl.glfw.GLFW.GLFW_KEY_KP_6 +import org.lwjgl.glfw.GLFW.GLFW_KEY_KP_8 +import org.lwjgl.glfw.GLFW.GLFW_KEY_LEFT +import org.lwjgl.glfw.GLFW.GLFW_KEY_RIGHT +import org.lwjgl.glfw.GLFW.GLFW_KEY_UP object InventoryMove : Module( name = "InventoryMove", description = "Allows you to move with GUIs opened", defaultTags = setOf(ModuleTag.PLAYER, ModuleTag.MOVEMENT) ) { - private val speed by setting("Rotation Speed", 5, 1..20, 1, unit = "°/tick") + private val arrowKeys by setting("Arrow Keys", false, "Allows rotating the players camera using the arrow keys") + private val speed by setting("Rotation Speed", 5, 1..20, 1, unit = "°/tick") { arrowKeys } private val rotationConfig = RotationConfig.Instant(RotationMode.Lock) - /** - * Whether the current screen has text inputs or is null - */ - val Screen?.hasInputOrNull: Boolean - get() = this is ChatScreen || - this is SignEditScreen || - this is AnvilScreen || - this is CommandBlockScreen || - this is LambdaScreen || - this == null - init { - listen(20250415) { event -> - if (mc.currentScreen.hasInputOrNull) return@listen - - val forward = isKeyPressed(GLFW_KEY_W).toDouble() - - isKeyPressed(GLFW_KEY_S).toDouble() - - val strafe = isKeyPressed(GLFW_KEY_A).toDouble() - - isKeyPressed(GLFW_KEY_D).toDouble() - - val jump = isKeyPressed(GLFW_KEY_SPACE) - val sneak = isKeyPressed(GLFW_KEY_LEFT_SHIFT) - - player.isSprinting = isKeyPressed(GLFW_KEY_LEFT_CONTROL) - event.input.mergeFrom(buildMovementInput(forward, strafe, jump, sneak)) - } - onRotate { - if (mc.currentScreen.hasInputOrNull) return@onRotate + if (!arrowKeys || hasInputOrNull(mc.currentScreen)) return@onRotate val pitch = (isKeyPressed(GLFW_KEY_DOWN, GLFW_KEY_KP_2).toFloatSign() - isKeyPressed(GLFW_KEY_UP, GLFW_KEY_KP_8).toFloatSign()) * speed @@ -90,4 +65,31 @@ object InventoryMove : Module( ).requestBy(rotationConfig) } } + + /** + * Whether the current screen has text inputs or is null + */ + @JvmStatic + fun hasInputOrNull(screen: Screen?) = + screen is ChatScreen || + screen is SignEditScreen || + screen is AnvilScreen || + screen is CommandBlockScreen || + screen is LambdaScreen || + screen == null + + @JvmStatic + fun isKeyMovementRelated(key: Int): Boolean { + val options = mc.options + return when (key) { + options.forwardKey.boundKey.code, + options.backKey.boundKey.code, + options.leftKey.boundKey.code, + options.rightKey.boundKey.code, + options.jumpKey.boundKey.code, + options.sprintKey.boundKey.code, + options.sneakKey.boundKey.code -> true + else -> false + } + } } diff --git a/common/src/main/resources/lambda.accesswidener b/common/src/main/resources/lambda.accesswidener index 31054ddb6..62d336f16 100644 --- a/common/src/main/resources/lambda.accesswidener +++ b/common/src/main/resources/lambda.accesswidener @@ -7,6 +7,8 @@ accessible field net/minecraft/client/MinecraftClient pausedTickDelta F accessible field net/minecraft/client/MinecraftClient thread Ljava/lang/Thread; accessible field net/minecraft/client/MinecraftClient uptimeInTicks J accessible field net/minecraft/client/option/KeyBinding boundKey Lnet/minecraft/client/util/InputUtil$Key; +accessible field net/minecraft/client/option/KeyBinding KEYS_BY_ID Ljava/util/Map; +accessible method net/minecraft/client/option/KeyBinding reset ()V # World accessible field net/minecraft/client/world/ClientWorld entityManager Lnet/minecraft/client/world/ClientEntityManager; From f5b61e25c2f3b642c8a06566ea8df9730dd8ef28 Mon Sep 17 00:00:00 2001 From: beanbag44 Date: Tue, 29 Jul 2025 16:20:25 +0100 Subject: [PATCH 3/3] reintroduce rotating with the arrow keys --- .../lambda/module/modules/player/InventoryMove.kt | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/common/src/main/kotlin/com/lambda/module/modules/player/InventoryMove.kt b/common/src/main/kotlin/com/lambda/module/modules/player/InventoryMove.kt index e32c71089..d52ea6768 100644 --- a/common/src/main/kotlin/com/lambda/module/modules/player/InventoryMove.kt +++ b/common/src/main/kotlin/com/lambda/module/modules/player/InventoryMove.kt @@ -17,10 +17,22 @@ package com.lambda.module.modules.player -import com.lambda.event.events.MovementEvent import com.lambda.Lambda.mc +import com.lambda.gui.LambdaScreen +import com.lambda.interaction.request.rotation.Rotation +import com.lambda.interaction.request.rotation.RotationConfig +import com.lambda.interaction.request.rotation.RotationManager.onRotate +import com.lambda.interaction.request.rotation.RotationMode +import com.lambda.interaction.request.rotation.visibilty.lookAt +import com.lambda.module.Module +import com.lambda.module.tag.ModuleTag import com.lambda.util.KeyboardUtils.isKeyPressed import com.lambda.util.math.MathUtils.toFloatSign +import net.minecraft.client.gui.screen.ChatScreen +import net.minecraft.client.gui.screen.Screen +import net.minecraft.client.gui.screen.ingame.AnvilScreen +import net.minecraft.client.gui.screen.ingame.CommandBlockScreen +import net.minecraft.client.gui.screen.ingame.SignEditScreen import org.lwjgl.glfw.GLFW.GLFW_KEY_DOWN import org.lwjgl.glfw.GLFW.GLFW_KEY_KP_2 import org.lwjgl.glfw.GLFW.GLFW_KEY_KP_4