From 08189b93a69e772ba574593f26048821e094c51f Mon Sep 17 00:00:00 2001 From: UndercoverGoose <53491740+UndercoverGoose@users.noreply.github.com> Date: Fri, 3 Oct 2025 11:17:19 -0400 Subject: [PATCH 01/37] chore: move CigaretteScreen instance into Cigarette pkg --- src/main/java/dev/cigarette/Cigarette.java | 2 ++ src/main/java/dev/cigarette/gui/CigaretteScreen.java | 2 +- src/main/java/dev/cigarette/gui/KeyBinding.java | 6 ++---- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/dev/cigarette/Cigarette.java b/src/main/java/dev/cigarette/Cigarette.java index 1c27841c..a02cec91 100644 --- a/src/main/java/dev/cigarette/Cigarette.java +++ b/src/main/java/dev/cigarette/Cigarette.java @@ -7,6 +7,7 @@ import dev.cigarette.config.Config; import dev.cigarette.config.FileSystem; import dev.cigarette.events.Events; +import dev.cigarette.gui.CigaretteScreen; import dev.cigarette.gui.hud.notification.NotificationDisplay; import dev.cigarette.lib.ChatLogger; import net.fabricmc.api.ModInitializer; @@ -37,6 +38,7 @@ public class Cigarette implements ModInitializer { public static final Identifier LOGO_IDENTIFIER = Identifier.of("cigarette", "icon.png"); public static final boolean IN_DEV_ENVIRONMENT = FabricLoader.getInstance().isDevelopmentEnvironment(); public static Config CONFIG = Config.construct(); + public static CigaretteScreen SCREEN = new CigaretteScreen(); public static BedwarsAgent BEDWARS_AGENT = new BedwarsAgent(DevWidget.bedwarsAgent); public static MurderMysteryAgent MURDER_MYSTERY_AGENT = new MurderMysteryAgent(DevWidget.murderMysteryAgent); public static ZombiesAgent ZOMBIES_AGENT = new ZombiesAgent(DevWidget.zombiesAgent); diff --git a/src/main/java/dev/cigarette/gui/CigaretteScreen.java b/src/main/java/dev/cigarette/gui/CigaretteScreen.java index afaf6625..cd65e7e6 100644 --- a/src/main/java/dev/cigarette/gui/CigaretteScreen.java +++ b/src/main/java/dev/cigarette/gui/CigaretteScreen.java @@ -38,7 +38,7 @@ public class CigaretteScreen extends Screen { private int categoryCount = 0; public static @Nullable KeybindWidget bindingKey = null; - protected CigaretteScreen() { + public CigaretteScreen() { super(Text.literal("Cigarette Client")); } diff --git a/src/main/java/dev/cigarette/gui/KeyBinding.java b/src/main/java/dev/cigarette/gui/KeyBinding.java index 3745c97d..d18cae95 100644 --- a/src/main/java/dev/cigarette/gui/KeyBinding.java +++ b/src/main/java/dev/cigarette/gui/KeyBinding.java @@ -14,8 +14,6 @@ public class KeyBinding implements ClientModInitializer { private static net.minecraft.client.option.KeyBinding keyBinding; - private static final CigaretteScreen screen = new CigaretteScreen(); - @Override public void onInitializeClient() { keyBinding = KeyBindingHelper.registerKeyBinding(new net.minecraft.client.option.KeyBinding("Toggle GUI", InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_RIGHT_SHIFT, "Cigarette | User Interface")); @@ -25,8 +23,8 @@ public void onInitializeClient() { if (client.currentScreen instanceof CigaretteScreen) { client.currentScreen.close(); } else { - screen.setParent(client.currentScreen); - client.setScreen(screen); + Cigarette.SCREEN.setParent(client.currentScreen); + client.setScreen(Cigarette.SCREEN); } } }); From 4ebbd397a559fac5385b49dfba501653a76f0f1d Mon Sep 17 00:00:00 2001 From: UndercoverGoose <53491740+UndercoverGoose@users.noreply.github.com> Date: Fri, 3 Oct 2025 12:49:40 -0400 Subject: [PATCH 02/37] create keybinding helper --- .../dev/cigarette/helper/KeybindHelper.java | 132 ++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 src/main/java/dev/cigarette/helper/KeybindHelper.java diff --git a/src/main/java/dev/cigarette/helper/KeybindHelper.java b/src/main/java/dev/cigarette/helper/KeybindHelper.java new file mode 100644 index 00000000..8f99fa25 --- /dev/null +++ b/src/main/java/dev/cigarette/helper/KeybindHelper.java @@ -0,0 +1,132 @@ +package dev.cigarette.helper; + +import dev.cigarette.Cigarette; +import dev.cigarette.gui.CigaretteScreen; +import net.minecraft.client.MinecraftClient; +import org.lwjgl.glfw.GLFW; + +public class KeybindHelper { + /** + * Keybind to toggle {@code CigaretteScreen}. + */ + public static CigaretteKeyBind TOGGLE_GUI = new CigaretteKeyBind(GLFW.GLFW_KEY_RIGHT_SHIFT); + + /** + * Attempts to handle a key event inside the {@code CigaretteScreen} GUI. + *

{@code KeyboardMixin} checks this handler first.

+ * + * @param client The Minecraft client + * @param key The events key code + * @param scancode The events scan code + * @param action The events GLFW action + * @param modifiers The events modifier + * @return Whether the key event is handled and should be cancelled + */ + public static boolean handleByGUI(MinecraftClient client, int key, int scancode, int action, int modifiers) { + if (!(client.currentScreen instanceof CigaretteScreen)) return false; + if (CigaretteScreen.bindingKey != null) { + switch (action) { + case GLFW.GLFW_PRESS -> CigaretteScreen.bindingKey.keyPressed(key, scancode, modifiers); + case GLFW.GLFW_RELEASE -> CigaretteScreen.bindingKey.keyReleased(key, scancode, modifiers); + } + } else { + if (key == GLFW.GLFW_KEY_ESCAPE || (action == GLFW.GLFW_PRESS && TOGGLE_GUI.matches(key))) { + Cigarette.SCREEN.close(); + } + } + return true; + } + + /** + * Checks if the input should be cancelled because of modules blocking inputs. + *

{@code KeyboardMixin} checks this handler second, after {@code handleByGUI()}.

+ * + * @param client The Minecraft client + * @param key The events key code + * @param scancode The events scan code + * @param action The events GLFW action + * @param modifiers The events modifier + * @return Whether the key event should be cancelled + */ + public static boolean handleBlockedInputs(MinecraftClient client, int key, int scancode, int action, int modifiers) { + if (TOGGLE_GUI.matches(key)) return false; + return false; + } + + /** + * Attempts to handle a key event outside the {@code CigaretteScreen} GUI and after input blocking. + *

{@code KeyboardMixin} checks this handler last, after {@code handleBlockedInputs()}.

+ * + * @param client The Minecraft client + * @param key The events key code + * @param scancode The events scan code + * @param action The events GLFW action + * @param modifiers The events modifier + * @return Whether the key event is handled and should be cancelled + */ + public static boolean handleCustom(MinecraftClient client, int key, int scancode, int action, int modifiers) { + if (action != GLFW.GLFW_PRESS) return false; + if (TOGGLE_GUI.matches(key)) { + Cigarette.SCREEN.setParent(client.currentScreen); + client.setScreen(Cigarette.SCREEN); + return true; + } + return false; + } + + /** + * A custom key bind used instead of the native {@code KeyBinding} class. + */ + public static class CigaretteKeyBind { + /** + * The key code that triggers this keybind + */ + private int key; + /** + * The default key code set for this keybind + */ + private final int defaultKey; + + /** + * Creates a custom key bind. + * + * @param defaultKey The key and default key to use + */ + public CigaretteKeyBind(int defaultKey) { + this.key = defaultKey; + this.defaultKey = defaultKey; + } + + /** + * {@return whether the input key matches the saved key code} + * + * @param key The key code to compare + */ + public boolean matches(int key) { + return this.key == key; + } + + /** + * {@return the key code that should trigger this key bind} + */ + public int key() { + return this.key; + } + + /** + * Sets the saved key. + * + * @param key The key code to save to this key bind + */ + public void setKey(int key) { + this.key = key; + } + + /** + * Resets this key bind to the default key. + */ + public void reset() { + this.key = this.defaultKey; + } + } +} From 92b9185f4151676766e763df7c0b81c68683436b Mon Sep 17 00:00:00 2001 From: UndercoverGoose <53491740+UndercoverGoose@users.noreply.github.com> Date: Fri, 3 Oct 2025 12:50:45 -0400 Subject: [PATCH 03/37] create Minecraft Keyboard mixin --- .../dev/cigarette/mixin/KeyboardMixin.java | 25 +++++++++++++++++++ src/main/resources/cigarette.mixins.json | 4 +-- 2 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 src/main/java/dev/cigarette/mixin/KeyboardMixin.java diff --git a/src/main/java/dev/cigarette/mixin/KeyboardMixin.java b/src/main/java/dev/cigarette/mixin/KeyboardMixin.java new file mode 100644 index 00000000..e6d31ebc --- /dev/null +++ b/src/main/java/dev/cigarette/mixin/KeyboardMixin.java @@ -0,0 +1,25 @@ +package dev.cigarette.mixin; + +import dev.cigarette.helper.KeybindHelper; +import net.minecraft.client.Keyboard; +import net.minecraft.client.MinecraftClient; +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; + +@Mixin(Keyboard.class) +public class KeyboardMixin { + @Inject(method = "onKey", at = @At("HEAD"), cancellable = true) + private void onKey(long window, int key, int scancode, int action, int modifiers, CallbackInfo ci) { + MinecraftClient client = MinecraftClient.getInstance(); + if (window != client.getWindow().getHandle()) { + ci.cancel(); + return; + } + if (KeybindHelper.handleByGUI(client, key, scancode, action, modifiers) || KeybindHelper.handleBlockedInputs(client, key, scancode, action, modifiers) || KeybindHelper.handleCustom(client, key, scancode, action, modifiers)) { + ci.cancel(); + return; + } + } +} diff --git a/src/main/resources/cigarette.mixins.json b/src/main/resources/cigarette.mixins.json index 713f4a1b..b88ff572 100644 --- a/src/main/resources/cigarette.mixins.json +++ b/src/main/resources/cigarette.mixins.json @@ -10,14 +10,14 @@ "MinecraftClientInvoker", "PlayerEntityMixin", "PropertyMixin", - "ScoreboardMixin", - "ClientWorldAccessor" + "ScoreboardMixin" ], "injectors": { "defaultRequire": 1 }, "client": [ "KeyboardInputMixin", + "KeyboardMixin", "MouseMixin" ] } \ No newline at end of file From 63d944fe56f3c63282a975b604a7f1efdc7d61b7 Mon Sep 17 00:00:00 2001 From: UndercoverGoose <53491740+UndercoverGoose@users.noreply.github.com> Date: Fri, 3 Oct 2025 12:54:43 -0400 Subject: [PATCH 04/37] remove KeyBinding mod initializer --- .../java/dev/cigarette/gui/KeyBinding.java | 32 ------------------- src/main/resources/fabric.mod.json | 3 +- 2 files changed, 1 insertion(+), 34 deletions(-) delete mode 100644 src/main/java/dev/cigarette/gui/KeyBinding.java diff --git a/src/main/java/dev/cigarette/gui/KeyBinding.java b/src/main/java/dev/cigarette/gui/KeyBinding.java deleted file mode 100644 index d18cae95..00000000 --- a/src/main/java/dev/cigarette/gui/KeyBinding.java +++ /dev/null @@ -1,32 +0,0 @@ -package dev.cigarette.gui; - -import dev.cigarette.Cigarette; -import net.fabricmc.api.ClientModInitializer; -import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; -import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; -import net.minecraft.client.util.InputUtil; -import net.minecraft.util.Identifier; -import org.lwjgl.glfw.GLFW; - -public class KeyBinding implements ClientModInitializer { - @SuppressWarnings("unused") - private static final Identifier HUD_KEYBINDING_ID = Identifier.of(Cigarette.MOD_ID, "hud-keybinding"); - - private static net.minecraft.client.option.KeyBinding keyBinding; - - @Override - public void onInitializeClient() { - keyBinding = KeyBindingHelper.registerKeyBinding(new net.minecraft.client.option.KeyBinding("Toggle GUI", InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_RIGHT_SHIFT, "Cigarette | User Interface")); - - ClientTickEvents.END_CLIENT_TICK.register(client -> { - while (keyBinding.wasPressed()) { - if (client.currentScreen instanceof CigaretteScreen) { - client.currentScreen.close(); - } else { - Cigarette.SCREEN.setParent(client.currentScreen); - client.setScreen(Cigarette.SCREEN); - } - } - }); - } -} diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 4e915f3b..fb2073a2 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -18,8 +18,7 @@ "dev.cigarette.Cigarette" ], "client": [ - "dev.cigarette.Language", - "dev.cigarette.gui.KeyBinding" + "dev.cigarette.Language" ] }, "mixins": [ From c59418e28c22143796d8483a903de3eef40048bb Mon Sep 17 00:00:00 2001 From: UndercoverGoose <53491740+UndercoverGoose@users.noreply.github.com> Date: Fri, 3 Oct 2025 13:19:14 -0400 Subject: [PATCH 05/37] add binding and press checks --- .../dev/cigarette/helper/KeybindHelper.java | 55 ++++++++++++++++++- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/src/main/java/dev/cigarette/helper/KeybindHelper.java b/src/main/java/dev/cigarette/helper/KeybindHelper.java index 8f99fa25..638aa8e3 100644 --- a/src/main/java/dev/cigarette/helper/KeybindHelper.java +++ b/src/main/java/dev/cigarette/helper/KeybindHelper.java @@ -5,11 +5,15 @@ import net.minecraft.client.MinecraftClient; import org.lwjgl.glfw.GLFW; +import java.util.HashSet; + public class KeybindHelper { /** * Keybind to toggle {@code CigaretteScreen}. */ - public static CigaretteKeyBind TOGGLE_GUI = new CigaretteKeyBind(GLFW.GLFW_KEY_RIGHT_SHIFT); + public static final CigaretteKeyBind TOGGLE_GUI = new CigaretteKeyBind(GLFW.GLFW_KEY_RIGHT_SHIFT); + + private static final HashSet customBinds = new HashSet<>(); /** * Attempts to handle a key event inside the {@code CigaretteScreen} GUI. @@ -71,6 +75,11 @@ public static boolean handleCustom(MinecraftClient client, int key, int scancode client.setScreen(Cigarette.SCREEN); return true; } + for (CigaretteKeyBind binding : customBinds) { + if (!binding.matches(key)) continue; + binding.processAction(action); + return true; + } return false; } @@ -79,13 +88,21 @@ public static boolean handleCustom(MinecraftClient client, int key, int scancode */ public static class CigaretteKeyBind { /** - * The key code that triggers this keybind + * The key code that triggers this keybind. */ private int key; /** - * The default key code set for this keybind + * The default key code set for this keybind. */ private final int defaultKey; + /** + * Whether this key is currently pressed or not. + */ + private boolean pressed = false; + /** + * The number of times this key has been pressed. + */ + private int timesPressed = 0; /** * Creates a custom key bind. @@ -95,6 +112,38 @@ public static class CigaretteKeyBind { public CigaretteKeyBind(int defaultKey) { this.key = defaultKey; this.defaultKey = defaultKey; + customBinds.add(this); + } + + /** + * Updates {@code pressed} and {@code timesPressed} depending on the action that occurred on the key. + * + * @param glfwAction The key events action as defined by GLFW + */ + protected void processAction(int glfwAction) { + switch (glfwAction) { + case GLFW.GLFW_PRESS -> { + this.timesPressed++; + this.pressed = true; + } + case GLFW.GLFW_RELEASE -> this.pressed = false; + } + } + + /** + * {@return whether this keybind is currently pressed} + */ + public boolean isPressed() { + return this.pressed; + } + + /** + * {@return whether this keybind was pressed} + */ + public boolean wasPressed() { + if (this.timesPressed == 0) return false; + this.timesPressed--; + return true; } /** From 3aa146f46e9382595c343fcef3921cb55eda34fc Mon Sep 17 00:00:00 2001 From: UndercoverGoose <53491740+UndercoverGoose@users.noreply.github.com> Date: Fri, 3 Oct 2025 14:41:43 -0400 Subject: [PATCH 06/37] add input blocking methods --- .../dev/cigarette/helper/KeybindHelper.java | 54 ++++++++++++++++++- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/src/main/java/dev/cigarette/helper/KeybindHelper.java b/src/main/java/dev/cigarette/helper/KeybindHelper.java index 638aa8e3..1c80a494 100644 --- a/src/main/java/dev/cigarette/helper/KeybindHelper.java +++ b/src/main/java/dev/cigarette/helper/KeybindHelper.java @@ -3,18 +3,27 @@ import dev.cigarette.Cigarette; import dev.cigarette.gui.CigaretteScreen; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.option.KeyBinding; import org.lwjgl.glfw.GLFW; import java.util.HashSet; public class KeybindHelper { + /** + * Set of custom keybinds that can be triggered. + */ + private static final HashSet customBinds = new HashSet<>(); + + /** + * Set of keybinds that should be cancelled. + */ + private static final HashSet blockedInputs = new HashSet<>(); + /** * Keybind to toggle {@code CigaretteScreen}. */ public static final CigaretteKeyBind TOGGLE_GUI = new CigaretteKeyBind(GLFW.GLFW_KEY_RIGHT_SHIFT); - private static final HashSet customBinds = new HashSet<>(); - /** * Attempts to handle a key event inside the {@code CigaretteScreen} GUI. *

{@code KeyboardMixin} checks this handler first.

@@ -54,6 +63,11 @@ public static boolean handleByGUI(MinecraftClient client, int key, int scancode, */ public static boolean handleBlockedInputs(MinecraftClient client, int key, int scancode, int action, int modifiers) { if (TOGGLE_GUI.matches(key)) return false; + for (KeyBinding keybind : blockedInputs) { + if (keybind.matchesKey(key, scancode)) { + return true; + } + } return false; } @@ -83,6 +97,42 @@ public static boolean handleCustom(MinecraftClient client, int key, int scancode return false; } + /** + * Attempts to start input blocking. {@return false if input blocking is already running} Use {@code forceBlockInputs()} to bypass this check. + * + * @param keybindIds The keybind IDs to pass into {@code KeyBinding.byId()} + */ + public static boolean tryBlockInputs(String... keybindIds) { + if (!blockedInputs.isEmpty()) return false; + for (String id : keybindIds) { + KeyBinding keybind = KeyBinding.byId(id); + if (keybind == null) continue; + blockedInputs.add(keybind); + } + return true; + } + + /** + * Force starts input blocking with the provided configuration. Overrides any previously started configurations. + * + * @param keybindIds The keybind IDs to pass into {@code KeyBinding.byId()} + */ + public static void forceBlockInputs(String... keybindIds) { + blockedInputs.clear(); + for (String id : keybindIds) { + KeyBinding keybind = KeyBinding.byId(id); + if (keybind == null) continue; + blockedInputs.add(keybind); + } + } + + /** + * Disable input blocking. + */ + public static void unblock() { + blockedInputs.clear(); + } + /** * A custom key bind used instead of the native {@code KeyBinding} class. */ From 76ef306836dbd6f51c0734aba00c5cf1b36c2e1e Mon Sep 17 00:00:00 2001 From: UndercoverGoose <53491740+UndercoverGoose@users.noreply.github.com> Date: Fri, 3 Oct 2025 14:52:41 -0400 Subject: [PATCH 07/37] add mouse blocking enabled by default when keys are blocked --- .../dev/cigarette/helper/KeybindHelper.java | 36 +++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/src/main/java/dev/cigarette/helper/KeybindHelper.java b/src/main/java/dev/cigarette/helper/KeybindHelper.java index 1c80a494..1db64cdf 100644 --- a/src/main/java/dev/cigarette/helper/KeybindHelper.java +++ b/src/main/java/dev/cigarette/helper/KeybindHelper.java @@ -14,11 +14,21 @@ public class KeybindHelper { */ private static final HashSet customBinds = new HashSet<>(); + /** + * The module that is blocking inputs. + */ + private static Object blockingModule = null; + /** * Set of keybinds that should be cancelled. */ private static final HashSet blockedInputs = new HashSet<>(); + /** + * Whether to block mouse movements from updating the players yaw/pitch. + */ + private static boolean blockMouse = false; + /** * Keybind to toggle {@code CigaretteScreen}. */ @@ -102,13 +112,15 @@ public static boolean handleCustom(MinecraftClient client, int key, int scancode * * @param keybindIds The keybind IDs to pass into {@code KeyBinding.byId()} */ - public static boolean tryBlockInputs(String... keybindIds) { + public static boolean tryBlockInputs(Object module, String... keybindIds) { if (!blockedInputs.isEmpty()) return false; for (String id : keybindIds) { KeyBinding keybind = KeyBinding.byId(id); if (keybind == null) continue; blockedInputs.add(keybind); } + blockMouse = true; + blockingModule = module; return true; } @@ -117,13 +129,15 @@ public static boolean tryBlockInputs(String... keybindIds) { * * @param keybindIds The keybind IDs to pass into {@code KeyBinding.byId()} */ - public static void forceBlockInputs(String... keybindIds) { + public static void forceBlockInputs(Object module, String... keybindIds) { blockedInputs.clear(); for (String id : keybindIds) { KeyBinding keybind = KeyBinding.byId(id); if (keybind == null) continue; blockedInputs.add(keybind); } + blockMouse = true; + blockingModule = module; } /** @@ -131,6 +145,24 @@ public static void forceBlockInputs(String... keybindIds) { */ public static void unblock() { blockedInputs.clear(); + blockMouse = false; + blockingModule = null; + } + + /** + * {@return whether the provided module is blocking inputs} + * + * @param module The module to check + */ + public static boolean isBlocking(Object module) { + return blockingModule == module; + } + + /** + * {@return whether the mouse is being input blocked} + */ + public static boolean isMouseBlocked() { + return blockMouse; } /** From fe99bdf9ecc0da781ec2098bd16285310c81bfba Mon Sep 17 00:00:00 2001 From: UndercoverGoose <53491740+UndercoverGoose@users.noreply.github.com> Date: Sat, 4 Oct 2025 00:32:37 -0400 Subject: [PATCH 08/37] create keybind wrappers and InputBlocker class --- .../helper/keybind/InputBlocker.java | 37 ++++++++++++ .../helper/keybind/MinecraftKeybind.java | 58 +++++++++++++++++++ .../helper/keybind/VirtualKeybind.java | 50 ++++++++++++++++ 3 files changed, 145 insertions(+) create mode 100644 src/main/java/dev/cigarette/helper/keybind/InputBlocker.java create mode 100644 src/main/java/dev/cigarette/helper/keybind/MinecraftKeybind.java create mode 100644 src/main/java/dev/cigarette/helper/keybind/VirtualKeybind.java diff --git a/src/main/java/dev/cigarette/helper/keybind/InputBlocker.java b/src/main/java/dev/cigarette/helper/keybind/InputBlocker.java new file mode 100644 index 00000000..d239b00d --- /dev/null +++ b/src/main/java/dev/cigarette/helper/keybind/InputBlocker.java @@ -0,0 +1,37 @@ +package dev.cigarette.helper.keybind; + +public class InputBlocker { + private final MinecraftKeybind[] blockedBindings; + protected boolean complete = false; + + public InputBlocker(MinecraftKeybind... blockedBindings) { + this.blockedBindings = blockedBindings; + } + + /** + * Verifies that each keybind object is linked with their native Minecraft {@code KeyBinding}. + * + * @return whether all keybinds are linked or not + */ + private boolean complete() { + if (this.complete) return true; + int linked = 0; + for (MinecraftKeybind binding : this.blockedBindings) { + if (binding.isAttached() || binding.tryToAttach()) { + linked++; + } + } + this.complete = linked == this.blockedBindings.length; + return this.complete; + } + + public boolean process(int key, int scancode, int action, int modifiers) { + if (!this.complete()) return false; + for (MinecraftKeybind binding : blockedBindings) { + if (!binding.isOf(key, scancode)) continue; + binding.physicalAction(action); + return true; + } + return false; + } +} diff --git a/src/main/java/dev/cigarette/helper/keybind/MinecraftKeybind.java b/src/main/java/dev/cigarette/helper/keybind/MinecraftKeybind.java new file mode 100644 index 00000000..b61e0a54 --- /dev/null +++ b/src/main/java/dev/cigarette/helper/keybind/MinecraftKeybind.java @@ -0,0 +1,58 @@ +package dev.cigarette.helper.keybind; + +import net.minecraft.client.option.KeyBinding; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.lwjgl.glfw.GLFW; + +public class MinecraftKeybind extends VirtualKeybind { + private @Nullable KeyBinding minecraftBinding; + private final @NotNull String minecraftKeybindId; + + public MinecraftKeybind(@NotNull String keybindId) { + super(GLFW.GLFW_KEY_UNKNOWN); + this.minecraftBinding = KeyBinding.byId(keybindId); + this.minecraftKeybindId = keybindId; + } + + /** + * Attempts to link this object with the native {@code KeyBinding} from Minecraft. + * + * @return whether this object was linked successfully or not + */ + public boolean tryToAttach() { + this.minecraftBinding = KeyBinding.byId(this.minecraftKeybindId); + return this.isAttached(); + } + + /** + * Checks if this object is linked with the native {@code KeyBinding} from Minecraft. + * + * @return whether this object is linked or not + */ + public boolean isAttached() { + return this.minecraftBinding != null; + } + + /** + * {@return whether this key is being virtually held down or not} This can result from the key being physically held down or set to be held by other code. + */ + public boolean isVirtuallyPressed() { + if (this.minecraftBinding == null) return false; + return this.minecraftBinding.isPressed(); + } + + /** + * {@return whether this key was virtually pressed or not} This can result from the key being physically pressed or set to have been pressed by other code. + */ + public boolean wasVirtuallyPressed() { + if (this.minecraftBinding == null) return false; + return this.minecraftBinding.wasPressed(); + } + + @Override + public boolean isOf(int key, int scancode) { + if (this.minecraftBinding == null) return false; + return this.minecraftBinding.matchesKey(key, scancode); + } +} diff --git a/src/main/java/dev/cigarette/helper/keybind/VirtualKeybind.java b/src/main/java/dev/cigarette/helper/keybind/VirtualKeybind.java new file mode 100644 index 00000000..035e1745 --- /dev/null +++ b/src/main/java/dev/cigarette/helper/keybind/VirtualKeybind.java @@ -0,0 +1,50 @@ +package dev.cigarette.helper.keybind; + +import org.lwjgl.glfw.GLFW; + +public class VirtualKeybind { + protected int currentKey; + protected final int defaultKey; + protected boolean pressed = false; + protected int timesPressed = 0; + + public VirtualKeybind(int defaultKey) { + this.currentKey = defaultKey; + this.defaultKey = defaultKey; + } + + /** + * Processes a physical action on the key. + * + * @param glfwAction The GLFW action performed on this keybind + */ + public void physicalAction(int glfwAction) { + switch (glfwAction) { + case GLFW.GLFW_PRESS -> { + this.timesPressed++; + this.pressed = true; + } + case GLFW.GLFW_RELEASE -> this.pressed = false; + } + } + + /** + * {@return whether this key is being physically held down or not} + */ + public boolean isPhysicallyPressed() { + return this.pressed; + } + + /** + * {@return whether this key was physically pressed or not} + */ + public boolean wasPhysicallyPressed() { + if (this.timesPressed == 0) return false; + this.timesPressed--; + return true; + } + + public boolean isOf(int key, int scancode) { + return this.currentKey == key; + } +} From 16d039d31ccb2600531eb54a756e68a01563b860 Mon Sep 17 00:00:00 2001 From: UndercoverGoose <53491740+UndercoverGoose@users.noreply.github.com> Date: Sat, 4 Oct 2025 00:41:38 -0400 Subject: [PATCH 09/37] use new wrappers --- .../dev/cigarette/helper/KeybindHelper.java | 186 ++++-------------- 1 file changed, 36 insertions(+), 150 deletions(-) diff --git a/src/main/java/dev/cigarette/helper/KeybindHelper.java b/src/main/java/dev/cigarette/helper/KeybindHelper.java index 1db64cdf..00ff89ce 100644 --- a/src/main/java/dev/cigarette/helper/KeybindHelper.java +++ b/src/main/java/dev/cigarette/helper/KeybindHelper.java @@ -2,37 +2,41 @@ import dev.cigarette.Cigarette; import dev.cigarette.gui.CigaretteScreen; +import dev.cigarette.helper.keybind.InputBlocker; +import dev.cigarette.helper.keybind.MinecraftKeybind; +import dev.cigarette.helper.keybind.VirtualKeybind; import net.minecraft.client.MinecraftClient; -import net.minecraft.client.option.KeyBinding; +import org.jetbrains.annotations.Nullable; import org.lwjgl.glfw.GLFW; import java.util.HashSet; public class KeybindHelper { + public static final MinecraftKeybind KEY_SNEAK = new MinecraftKeybind("key.sneak"); + public static final MinecraftKeybind KEY_MOVE_BACK = new MinecraftKeybind("key.back"); + public static final MinecraftKeybind KEY_MOVE_LEFT = new MinecraftKeybind("key.left"); + public static final MinecraftKeybind KEY_MOVE_RIGHT = new MinecraftKeybind("key.right"); + public static final MinecraftKeybind KEY_RIGHT_CLICK = new MinecraftKeybind("key.use"); + public static final MinecraftKeybind KEY_JUMP = new MinecraftKeybind("key.jump"); /** - * Set of custom keybinds that can be triggered. + * Keybind to toggle {@code CigaretteScreen}. */ - private static final HashSet customBinds = new HashSet<>(); + public static final VirtualKeybind TOGGLE_GUI = new VirtualKeybind(GLFW.GLFW_KEY_RIGHT_SHIFT); /** - * The module that is blocking inputs. - */ - private static Object blockingModule = null; - - /** - * Set of keybinds that should be cancelled. + * Set of custom keybinds that can be triggered. */ - private static final HashSet blockedInputs = new HashSet<>(); + private static final HashSet customBinds = new HashSet<>(); /** - * Whether to block mouse movements from updating the players yaw/pitch. + * The module that is blocking inputs. */ - private static boolean blockMouse = false; + private static Object blockingModule = null; /** - * Keybind to toggle {@code CigaretteScreen}. + * The input blocker to pass events through. */ - public static final CigaretteKeyBind TOGGLE_GUI = new CigaretteKeyBind(GLFW.GLFW_KEY_RIGHT_SHIFT); + private static @Nullable InputBlocker blockedInputs = null; /** * Attempts to handle a key event inside the {@code CigaretteScreen} GUI. @@ -53,7 +57,7 @@ public static boolean handleByGUI(MinecraftClient client, int key, int scancode, case GLFW.GLFW_RELEASE -> CigaretteScreen.bindingKey.keyReleased(key, scancode, modifiers); } } else { - if (key == GLFW.GLFW_KEY_ESCAPE || (action == GLFW.GLFW_PRESS && TOGGLE_GUI.matches(key))) { + if (key == GLFW.GLFW_KEY_ESCAPE || (action == GLFW.GLFW_PRESS && TOGGLE_GUI.isOf(key, scancode))) { Cigarette.SCREEN.close(); } } @@ -72,13 +76,9 @@ public static boolean handleByGUI(MinecraftClient client, int key, int scancode, * @return Whether the key event should be cancelled */ public static boolean handleBlockedInputs(MinecraftClient client, int key, int scancode, int action, int modifiers) { - if (TOGGLE_GUI.matches(key)) return false; - for (KeyBinding keybind : blockedInputs) { - if (keybind.matchesKey(key, scancode)) { - return true; - } - } - return false; + if (TOGGLE_GUI.isOf(key, scancode)) return false; + if (blockedInputs == null) return false; + return blockedInputs.process(key, scancode, action, modifiers); } /** @@ -94,14 +94,14 @@ public static boolean handleBlockedInputs(MinecraftClient client, int key, int s */ public static boolean handleCustom(MinecraftClient client, int key, int scancode, int action, int modifiers) { if (action != GLFW.GLFW_PRESS) return false; - if (TOGGLE_GUI.matches(key)) { + if (TOGGLE_GUI.isOf(key, scancode)) { Cigarette.SCREEN.setParent(client.currentScreen); client.setScreen(Cigarette.SCREEN); return true; } - for (CigaretteKeyBind binding : customBinds) { - if (!binding.matches(key)) continue; - binding.processAction(action); + for (VirtualKeybind binding : customBinds) { + if (!binding.isOf(key, scancode)) continue; + binding.physicalAction(action); return true; } return false; @@ -110,33 +110,23 @@ public static boolean handleCustom(MinecraftClient client, int key, int scancode /** * Attempts to start input blocking. {@return false if input blocking is already running} Use {@code forceBlockInputs()} to bypass this check. * - * @param keybindIds The keybind IDs to pass into {@code KeyBinding.byId()} + * @param module + * @param blocker */ - public static boolean tryBlockInputs(Object module, String... keybindIds) { - if (!blockedInputs.isEmpty()) return false; - for (String id : keybindIds) { - KeyBinding keybind = KeyBinding.byId(id); - if (keybind == null) continue; - blockedInputs.add(keybind); - } - blockMouse = true; - blockingModule = module; + public static boolean tryBlockInputs(Object module, InputBlocker blocker) { + if (blockedInputs != null) return false; + forceBlockInputs(module, blocker); return true; } /** * Force starts input blocking with the provided configuration. Overrides any previously started configurations. * - * @param keybindIds The keybind IDs to pass into {@code KeyBinding.byId()} + * @param module + * @param blocker */ - public static void forceBlockInputs(Object module, String... keybindIds) { - blockedInputs.clear(); - for (String id : keybindIds) { - KeyBinding keybind = KeyBinding.byId(id); - if (keybind == null) continue; - blockedInputs.add(keybind); - } - blockMouse = true; + public static void forceBlockInputs(Object module, InputBlocker blocker) { + blockedInputs = blocker; blockingModule = module; } @@ -144,8 +134,7 @@ public static void forceBlockInputs(Object module, String... keybindIds) { * Disable input blocking. */ public static void unblock() { - blockedInputs.clear(); - blockMouse = false; + blockedInputs = null; blockingModule = null; } @@ -157,107 +146,4 @@ public static void unblock() { public static boolean isBlocking(Object module) { return blockingModule == module; } - - /** - * {@return whether the mouse is being input blocked} - */ - public static boolean isMouseBlocked() { - return blockMouse; - } - - /** - * A custom key bind used instead of the native {@code KeyBinding} class. - */ - public static class CigaretteKeyBind { - /** - * The key code that triggers this keybind. - */ - private int key; - /** - * The default key code set for this keybind. - */ - private final int defaultKey; - /** - * Whether this key is currently pressed or not. - */ - private boolean pressed = false; - /** - * The number of times this key has been pressed. - */ - private int timesPressed = 0; - - /** - * Creates a custom key bind. - * - * @param defaultKey The key and default key to use - */ - public CigaretteKeyBind(int defaultKey) { - this.key = defaultKey; - this.defaultKey = defaultKey; - customBinds.add(this); - } - - /** - * Updates {@code pressed} and {@code timesPressed} depending on the action that occurred on the key. - * - * @param glfwAction The key events action as defined by GLFW - */ - protected void processAction(int glfwAction) { - switch (glfwAction) { - case GLFW.GLFW_PRESS -> { - this.timesPressed++; - this.pressed = true; - } - case GLFW.GLFW_RELEASE -> this.pressed = false; - } - } - - /** - * {@return whether this keybind is currently pressed} - */ - public boolean isPressed() { - return this.pressed; - } - - /** - * {@return whether this keybind was pressed} - */ - public boolean wasPressed() { - if (this.timesPressed == 0) return false; - this.timesPressed--; - return true; - } - - /** - * {@return whether the input key matches the saved key code} - * - * @param key The key code to compare - */ - public boolean matches(int key) { - return this.key == key; - } - - /** - * {@return the key code that should trigger this key bind} - */ - public int key() { - return this.key; - } - - /** - * Sets the saved key. - * - * @param key The key code to save to this key bind - */ - public void setKey(int key) { - this.key = key; - } - - /** - * Resets this key bind to the default key. - */ - public void reset() { - this.key = this.defaultKey; - } - } } From 818e623b62ed27d6dcb15c5b3e235f43618be29d Mon Sep 17 00:00:00 2001 From: UndercoverGoose <53491740+UndercoverGoose@users.noreply.github.com> Date: Sat, 4 Oct 2025 00:43:48 -0400 Subject: [PATCH 10/37] add mouse blocking --- .../java/dev/cigarette/helper/KeybindHelper.java | 7 +++++++ .../cigarette/helper/keybind/InputBlocker.java | 15 +++++++++++++++ src/main/java/dev/cigarette/mixin/MouseMixin.java | 10 ++-------- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/main/java/dev/cigarette/helper/KeybindHelper.java b/src/main/java/dev/cigarette/helper/KeybindHelper.java index 00ff89ce..d8f2adf8 100644 --- a/src/main/java/dev/cigarette/helper/KeybindHelper.java +++ b/src/main/java/dev/cigarette/helper/KeybindHelper.java @@ -146,4 +146,11 @@ public static void unblock() { public static boolean isBlocking(Object module) { return blockingModule == module; } + + /** + * {@return whether an input blocker is applied that blocks mouse movement or not} + */ + public static boolean isMouseBlocked() { + return blockedInputs != null && blockedInputs.blocksCamera(); + } } diff --git a/src/main/java/dev/cigarette/helper/keybind/InputBlocker.java b/src/main/java/dev/cigarette/helper/keybind/InputBlocker.java index d239b00d..40f66745 100644 --- a/src/main/java/dev/cigarette/helper/keybind/InputBlocker.java +++ b/src/main/java/dev/cigarette/helper/keybind/InputBlocker.java @@ -2,12 +2,27 @@ public class InputBlocker { private final MinecraftKeybind[] blockedBindings; + private boolean blockCamera = false; protected boolean complete = false; public InputBlocker(MinecraftKeybind... blockedBindings) { this.blockedBindings = blockedBindings; } + /** + * Prevents the user from changing their yaw and pitch. + * + * @return This object for method chaining + */ + public InputBlocker preventCameraChanges() { + this.blockCamera = true; + return this; + } + + public boolean blocksCamera() { + return this.blockCamera; + } + /** * Verifies that each keybind object is linked with their native Minecraft {@code KeyBinding}. * diff --git a/src/main/java/dev/cigarette/mixin/MouseMixin.java b/src/main/java/dev/cigarette/mixin/MouseMixin.java index 8c7034de..f6ff6ff3 100644 --- a/src/main/java/dev/cigarette/mixin/MouseMixin.java +++ b/src/main/java/dev/cigarette/mixin/MouseMixin.java @@ -1,9 +1,7 @@ package dev.cigarette.mixin; -import dev.cigarette.lib.InputOverride; -import net.minecraft.client.MinecraftClient; +import dev.cigarette.helper.KeybindHelper; import net.minecraft.client.Mouse; -import net.minecraft.entity.Entity; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -13,11 +11,7 @@ public class MouseMixin { @Inject(method = "updateMouse", at = @At("HEAD"), cancellable = true) private void updateMouse(double timeDelta, CallbackInfo ci) { - if (!InputOverride.isActive) return; - Entity player = MinecraftClient.getInstance().player; - if (player != null) { - player.setAngles(InputOverride.yaw, InputOverride.pitch); - } + if (!KeybindHelper.isMouseBlocked()) return; ci.cancel(); } } From df444595f91ab6b397c952f54647f5c8975c6c34 Mon Sep 17 00:00:00 2001 From: UndercoverGoose <53491740+UndercoverGoose@users.noreply.github.com> Date: Sat, 4 Oct 2025 01:30:03 -0400 Subject: [PATCH 11/37] add method to trigger virtual key press --- .../dev/cigarette/helper/keybind/MinecraftKeybind.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/dev/cigarette/helper/keybind/MinecraftKeybind.java b/src/main/java/dev/cigarette/helper/keybind/MinecraftKeybind.java index b61e0a54..95b36575 100644 --- a/src/main/java/dev/cigarette/helper/keybind/MinecraftKeybind.java +++ b/src/main/java/dev/cigarette/helper/keybind/MinecraftKeybind.java @@ -1,6 +1,7 @@ package dev.cigarette.helper.keybind; import net.minecraft.client.option.KeyBinding; +import net.minecraft.client.util.InputUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.lwjgl.glfw.GLFW; @@ -50,6 +51,15 @@ public boolean wasVirtuallyPressed() { return this.minecraftBinding.wasPressed(); } + /** + * Virtually presses the key triggering any Minecraft related events. + */ + public void press() { + if (this.minecraftBinding == null) return; + InputUtil.Key key = InputUtil.fromTranslationKey(this.minecraftBinding.getBoundKeyTranslationKey()); + KeyBinding.onKeyPressed(key); + } + @Override public boolean isOf(int key, int scancode) { if (this.minecraftBinding == null) return false; From ef9ff9ffc0d4b5e89cef9abd579b25f397dbd57c Mon Sep 17 00:00:00 2001 From: UndercoverGoose <53491740+UndercoverGoose@users.noreply.github.com> Date: Sat, 4 Oct 2025 02:00:43 -0400 Subject: [PATCH 12/37] fix: wrapped keybinds do not receive events --- .../dev/cigarette/helper/KeybindHelper.java | 30 +++++++++++++++++++ .../helper/keybind/MinecraftKeybind.java | 11 +++++++ 2 files changed, 41 insertions(+) diff --git a/src/main/java/dev/cigarette/helper/KeybindHelper.java b/src/main/java/dev/cigarette/helper/KeybindHelper.java index d8f2adf8..56f139c6 100644 --- a/src/main/java/dev/cigarette/helper/KeybindHelper.java +++ b/src/main/java/dev/cigarette/helper/KeybindHelper.java @@ -18,6 +18,18 @@ public class KeybindHelper { public static final MinecraftKeybind KEY_MOVE_RIGHT = new MinecraftKeybind("key.right"); public static final MinecraftKeybind KEY_RIGHT_CLICK = new MinecraftKeybind("key.use"); public static final MinecraftKeybind KEY_JUMP = new MinecraftKeybind("key.jump"); + + private static final HashSet wrappedBindings = new HashSet<>(); + + static { + wrappedBindings.add(KEY_SNEAK); + wrappedBindings.add(KEY_MOVE_BACK); + wrappedBindings.add(KEY_MOVE_LEFT); + wrappedBindings.add(KEY_MOVE_RIGHT); + wrappedBindings.add(KEY_RIGHT_CLICK); + wrappedBindings.add(KEY_JUMP); + } + /** * Keybind to toggle {@code CigaretteScreen}. */ @@ -93,6 +105,11 @@ public static boolean handleBlockedInputs(MinecraftClient client, int key, int s * @return Whether the key event is handled and should be cancelled */ public static boolean handleCustom(MinecraftClient client, int key, int scancode, int action, int modifiers) { + for (MinecraftKeybind keybind : wrappedBindings) { + if (!keybind.isAttached() && !keybind.tryToAttach()) continue; + if (!keybind.isOf(key, scancode)) continue; + keybind.physicalAction(action); + } if (action != GLFW.GLFW_PRESS) return false; if (TOGGLE_GUI.isOf(key, scancode)) { Cigarette.SCREEN.setParent(client.currentScreen); @@ -107,6 +124,19 @@ public static boolean handleCustom(MinecraftClient client, int key, int scancode return false; } + /** + * Register a {@code MinecraftKeybind} wrapper so it can receive physical events. Wrappers from {@code KeybindHelper} are already registered. + *

Required to use {@code isPhysicallyPressed()} and {@code wasPhysicallyPressed()}.

+ * + * @param keybind The keybind wrapper register + */ + public static void registerWrapper(MinecraftKeybind keybind) { + for (MinecraftKeybind existing : wrappedBindings) { + if (existing.equals(keybind)) return; + } + wrappedBindings.add(keybind); + } + /** * Attempts to start input blocking. {@return false if input blocking is already running} Use {@code forceBlockInputs()} to bypass this check. * diff --git a/src/main/java/dev/cigarette/helper/keybind/MinecraftKeybind.java b/src/main/java/dev/cigarette/helper/keybind/MinecraftKeybind.java index 95b36575..ca142688 100644 --- a/src/main/java/dev/cigarette/helper/keybind/MinecraftKeybind.java +++ b/src/main/java/dev/cigarette/helper/keybind/MinecraftKeybind.java @@ -60,6 +60,17 @@ public void press() { KeyBinding.onKeyPressed(key); } + /** + * {@return whether the translation key name of both objects are identical} + * + * @param o the reference object with which to compare. + */ + public boolean equals(Object o) { + if (!(o instanceof MinecraftKeybind other) || this.minecraftBinding == null) return false; + if (other.minecraftBinding == null) return false; + return this.minecraftBinding.getTranslationKey().equals(other.minecraftBinding.getTranslationKey()); + } + @Override public boolean isOf(int key, int scancode) { if (this.minecraftBinding == null) return false; From 510e3f5914a3b45b4a7599485d55e2ac4fab726c Mon Sep 17 00:00:00 2001 From: UndercoverGoose <53491740+UndercoverGoose@users.noreply.github.com> Date: Sat, 4 Oct 2025 02:38:58 -0400 Subject: [PATCH 13/37] properly support mouse events (no scrolling) --- .../dev/cigarette/helper/KeybindHelper.java | 57 ++++++++++++++++--- .../helper/keybind/InputBlocker.java | 15 ++++- .../helper/keybind/MinecraftKeybind.java | 12 ++++ .../helper/keybind/VirtualKeybind.java | 22 +++++++ .../dev/cigarette/mixin/KeyboardMixin.java | 2 +- .../java/dev/cigarette/mixin/MouseMixin.java | 14 +++++ 6 files changed, 113 insertions(+), 9 deletions(-) diff --git a/src/main/java/dev/cigarette/helper/KeybindHelper.java b/src/main/java/dev/cigarette/helper/KeybindHelper.java index 56f139c6..46f3cd6e 100644 --- a/src/main/java/dev/cigarette/helper/KeybindHelper.java +++ b/src/main/java/dev/cigarette/helper/KeybindHelper.java @@ -16,7 +16,7 @@ public class KeybindHelper { public static final MinecraftKeybind KEY_MOVE_BACK = new MinecraftKeybind("key.back"); public static final MinecraftKeybind KEY_MOVE_LEFT = new MinecraftKeybind("key.left"); public static final MinecraftKeybind KEY_MOVE_RIGHT = new MinecraftKeybind("key.right"); - public static final MinecraftKeybind KEY_RIGHT_CLICK = new MinecraftKeybind("key.use"); + public static final MinecraftKeybind KEY_RIGHT_CLICK = new MinecraftKeybind("key.use").asMouse(); public static final MinecraftKeybind KEY_JUMP = new MinecraftKeybind("key.jump"); private static final HashSet wrappedBindings = new HashSet<>(); @@ -61,7 +61,7 @@ public class KeybindHelper { * @param modifiers The events modifier * @return Whether the key event is handled and should be cancelled */ - public static boolean handleByGUI(MinecraftClient client, int key, int scancode, int action, int modifiers) { + public static boolean handleKeyByGUI(MinecraftClient client, int key, int scancode, int action, int modifiers) { if (!(client.currentScreen instanceof CigaretteScreen)) return false; if (CigaretteScreen.bindingKey != null) { switch (action) { @@ -78,7 +78,7 @@ public static boolean handleByGUI(MinecraftClient client, int key, int scancode, /** * Checks if the input should be cancelled because of modules blocking inputs. - *

{@code KeyboardMixin} checks this handler second, after {@code handleByGUI()}.

+ *

{@code KeyboardMixin} checks this handler second, after {@code handleKeyByGUI()}.

* * @param client The Minecraft client * @param key The events key code @@ -87,15 +87,30 @@ public static boolean handleByGUI(MinecraftClient client, int key, int scancode, * @param modifiers The events modifier * @return Whether the key event should be cancelled */ - public static boolean handleBlockedInputs(MinecraftClient client, int key, int scancode, int action, int modifiers) { + public static boolean handleBlockedKeyInputs(MinecraftClient client, int key, int scancode, int action, int modifiers) { if (TOGGLE_GUI.isOf(key, scancode)) return false; if (blockedInputs == null) return false; - return blockedInputs.process(key, scancode, action, modifiers); + return blockedInputs.processKey(key, scancode, action, modifiers); + } + + /** + * Checks if the input should be cancelled because of modules blocking inputs. + *

{@code MouseMixin} checks this handler first.

+ * + * @param client The Minecraft client + * @param button The buttons key code + * @param action The events GLFW action + * @param mods The events modifier + * @return Whether the mouse event is handled and should be cancelled + */ + public static boolean handleBlockedMouseInputs(MinecraftClient client, int button, int action, int mods) { + if (blockedInputs == null) return false; + return blockedInputs.processMouse(button, action, mods); } /** * Attempts to handle a key event outside the {@code CigaretteScreen} GUI and after input blocking. - *

{@code KeyboardMixin} checks this handler last, after {@code handleBlockedInputs()}.

+ *

{@code KeyboardMixin} checks this handler last, after {@code handleBlockedKeyInputs()}.

* * @param client The Minecraft client * @param key The events key code @@ -104,9 +119,10 @@ public static boolean handleBlockedInputs(MinecraftClient client, int key, int s * @param modifiers The events modifier * @return Whether the key event is handled and should be cancelled */ - public static boolean handleCustom(MinecraftClient client, int key, int scancode, int action, int modifiers) { + public static boolean handleCustomKeys(MinecraftClient client, int key, int scancode, int action, int modifiers) { for (MinecraftKeybind keybind : wrappedBindings) { if (!keybind.isAttached() && !keybind.tryToAttach()) continue; + if (keybind.isMouse()) continue; if (!keybind.isOf(key, scancode)) continue; keybind.physicalAction(action); } @@ -117,6 +133,7 @@ public static boolean handleCustom(MinecraftClient client, int key, int scancode return true; } for (VirtualKeybind binding : customBinds) { + if (binding.isMouse()) continue; if (!binding.isOf(key, scancode)) continue; binding.physicalAction(action); return true; @@ -124,6 +141,32 @@ public static boolean handleCustom(MinecraftClient client, int key, int scancode return false; } + /** + * Attempts to handle a mouse event outside the {@code CigaretteScreen} GUI and after input blocking. + *

{@code MouseMixin} checks this handler last, after {@code handleBlocksMouseInputs()}

+ * + * @param client The Minecraft client + * @param button The buttons key code + * @param action The events GLFW action + * @param mods The events modifier + * @return Whether the mouse event is handled and should be cancelled + */ + public static boolean handleCustomMouse(MinecraftClient client, int button, int action, int mods) { + for (MinecraftKeybind keybind : wrappedBindings) { + if (!keybind.isAttached() && !keybind.tryToAttach()) continue; + if (!keybind.isMouse()) continue; + if (!keybind.isOfMouse(button)) continue; + keybind.physicalAction(action); + } + for (VirtualKeybind binding : customBinds) { + if (!binding.isMouse()) continue; + if (!binding.isOfMouse(button)) continue; + binding.physicalAction(action); + return true; + } + return false; + } + /** * Register a {@code MinecraftKeybind} wrapper so it can receive physical events. Wrappers from {@code KeybindHelper} are already registered. *

Required to use {@code isPhysicallyPressed()} and {@code wasPhysicallyPressed()}.

diff --git a/src/main/java/dev/cigarette/helper/keybind/InputBlocker.java b/src/main/java/dev/cigarette/helper/keybind/InputBlocker.java index 40f66745..3eac1cfc 100644 --- a/src/main/java/dev/cigarette/helper/keybind/InputBlocker.java +++ b/src/main/java/dev/cigarette/helper/keybind/InputBlocker.java @@ -40,13 +40,26 @@ private boolean complete() { return this.complete; } - public boolean process(int key, int scancode, int action, int modifiers) { + public boolean processKey(int key, int scancode, int action, int modifiers) { if (!this.complete()) return false; for (MinecraftKeybind binding : blockedBindings) { + if (binding.isMouse) continue; if (!binding.isOf(key, scancode)) continue; binding.physicalAction(action); return true; } return false; } + + public boolean processMouse(int button, int action, int modifiers) { + if (!this.complete()) return false; + for (MinecraftKeybind binding : blockedBindings) { + if (!binding.isMouse) continue; + if (!binding.isOfMouse(button)) continue; + System.out.println("Processing Mouse | button=" + button + " action=" + action); + binding.physicalAction(action); + return true; + } + return false; + } } diff --git a/src/main/java/dev/cigarette/helper/keybind/MinecraftKeybind.java b/src/main/java/dev/cigarette/helper/keybind/MinecraftKeybind.java index ca142688..6af1790c 100644 --- a/src/main/java/dev/cigarette/helper/keybind/MinecraftKeybind.java +++ b/src/main/java/dev/cigarette/helper/keybind/MinecraftKeybind.java @@ -71,9 +71,21 @@ public boolean equals(Object o) { return this.minecraftBinding.getTranslationKey().equals(other.minecraftBinding.getTranslationKey()); } + @Override + public MinecraftKeybind asMouse() { + this.isMouse = true; + return this; + } + @Override public boolean isOf(int key, int scancode) { if (this.minecraftBinding == null) return false; return this.minecraftBinding.matchesKey(key, scancode); } + + @Override + public boolean isOfMouse(int button) { + if (this.minecraftBinding == null) return false; + return this.minecraftBinding.matchesMouse(button); + } } diff --git a/src/main/java/dev/cigarette/helper/keybind/VirtualKeybind.java b/src/main/java/dev/cigarette/helper/keybind/VirtualKeybind.java index 035e1745..67b69754 100644 --- a/src/main/java/dev/cigarette/helper/keybind/VirtualKeybind.java +++ b/src/main/java/dev/cigarette/helper/keybind/VirtualKeybind.java @@ -7,12 +7,30 @@ public class VirtualKeybind { protected final int defaultKey; protected boolean pressed = false; protected int timesPressed = 0; + protected boolean isMouse = false; public VirtualKeybind(int defaultKey) { this.currentKey = defaultKey; this.defaultKey = defaultKey; } + /** + * Indicates that this keybind should receive events from the mouse instead of the keyboard. + * + * @return This object for method chaining + */ + public VirtualKeybind asMouse() { + this.isMouse = true; + return this; + } + + /** + * {@return whether this a mouse keybind or not} + */ + public boolean isMouse() { + return this.isMouse; + } + /** * Processes a physical action on the key. * @@ -47,4 +65,8 @@ public boolean wasPhysicallyPressed() { public boolean isOf(int key, int scancode) { return this.currentKey == key; } + + public boolean isOfMouse(int button) { + return this.currentKey == button; + } } diff --git a/src/main/java/dev/cigarette/mixin/KeyboardMixin.java b/src/main/java/dev/cigarette/mixin/KeyboardMixin.java index e6d31ebc..382ea92b 100644 --- a/src/main/java/dev/cigarette/mixin/KeyboardMixin.java +++ b/src/main/java/dev/cigarette/mixin/KeyboardMixin.java @@ -17,7 +17,7 @@ private void onKey(long window, int key, int scancode, int action, int modifiers ci.cancel(); return; } - if (KeybindHelper.handleByGUI(client, key, scancode, action, modifiers) || KeybindHelper.handleBlockedInputs(client, key, scancode, action, modifiers) || KeybindHelper.handleCustom(client, key, scancode, action, modifiers)) { + if (KeybindHelper.handleKeyByGUI(client, key, scancode, action, modifiers) || KeybindHelper.handleBlockedKeyInputs(client, key, scancode, action, modifiers) || KeybindHelper.handleCustomKeys(client, key, scancode, action, modifiers)) { ci.cancel(); return; } diff --git a/src/main/java/dev/cigarette/mixin/MouseMixin.java b/src/main/java/dev/cigarette/mixin/MouseMixin.java index f6ff6ff3..203b4c1e 100644 --- a/src/main/java/dev/cigarette/mixin/MouseMixin.java +++ b/src/main/java/dev/cigarette/mixin/MouseMixin.java @@ -1,6 +1,7 @@ package dev.cigarette.mixin; import dev.cigarette.helper.KeybindHelper; +import net.minecraft.client.MinecraftClient; import net.minecraft.client.Mouse; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -14,4 +15,17 @@ private void updateMouse(double timeDelta, CallbackInfo ci) { if (!KeybindHelper.isMouseBlocked()) return; ci.cancel(); } + + @Inject(method = "onMouseButton", at = @At("HEAD"), cancellable = true) + private void onMouseButton(long window, int button, int action, int mods, CallbackInfo ci) { + MinecraftClient client = MinecraftClient.getInstance(); + if (window != client.getWindow().getHandle()) { + ci.cancel(); + return; + } + if (KeybindHelper.handleBlockedMouseInputs(client, button, action, mods) || KeybindHelper.handleCustomMouse(client, button, action, mods)) { + ci.cancel(); + return; + } + } } From e85f5019c78d0b11e37ac3170bf9db86c1b7e6f9 Mon Sep 17 00:00:00 2001 From: UndercoverGoose <53491740+UndercoverGoose@users.noreply.github.com> Date: Sat, 4 Oct 2025 03:10:08 -0400 Subject: [PATCH 14/37] add virtual key holding and releasing --- .../helper/keybind/MinecraftKeybind.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/main/java/dev/cigarette/helper/keybind/MinecraftKeybind.java b/src/main/java/dev/cigarette/helper/keybind/MinecraftKeybind.java index 6af1790c..87535b76 100644 --- a/src/main/java/dev/cigarette/helper/keybind/MinecraftKeybind.java +++ b/src/main/java/dev/cigarette/helper/keybind/MinecraftKeybind.java @@ -60,6 +60,24 @@ public void press() { KeyBinding.onKeyPressed(key); } + /** + * Virtually holds the key triggering any Minecraft related events. + */ + public void hold() { + if (this.minecraftBinding == null) return; + InputUtil.Key key = InputUtil.fromTranslationKey(this.minecraftBinding.getBoundKeyTranslationKey()); + KeyBinding.setKeyPressed(key, true); + } + + /** + * Virtually releases the key. + */ + public void release() { + if (this.minecraftBinding == null) return; + InputUtil.Key key = InputUtil.fromTranslationKey(this.minecraftBinding.getBoundKeyTranslationKey()); + KeyBinding.setKeyPressed(key, false); + } + /** * {@return whether the translation key name of both objects are identical} * From c603665307d1ae3ac31141a49cbaaab1761d465d Mon Sep 17 00:00:00 2001 From: UndercoverGoose <53491740+UndercoverGoose@users.noreply.github.com> Date: Sat, 4 Oct 2025 03:28:05 -0400 Subject: [PATCH 15/37] fix: mouse virtual state desyncing from physical state after unblocking --- .../java/dev/cigarette/helper/KeybindHelper.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/java/dev/cigarette/helper/KeybindHelper.java b/src/main/java/dev/cigarette/helper/KeybindHelper.java index 46f3cd6e..762bd057 100644 --- a/src/main/java/dev/cigarette/helper/KeybindHelper.java +++ b/src/main/java/dev/cigarette/helper/KeybindHelper.java @@ -6,6 +6,8 @@ import dev.cigarette.helper.keybind.MinecraftKeybind; import dev.cigarette.helper.keybind.VirtualKeybind; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.option.KeyBinding; +import net.minecraft.client.util.InputUtil; import org.jetbrains.annotations.Nullable; import org.lwjgl.glfw.GLFW; @@ -209,6 +211,7 @@ public static void forceBlockInputs(Object module, InputBlocker blocker) { public static void unblock() { blockedInputs = null; blockingModule = null; + updateKeyStates(); } /** @@ -226,4 +229,15 @@ public static boolean isBlocking(Object module) { public static boolean isMouseBlocked() { return blockedInputs != null && blockedInputs.blocksCamera(); } + + public static void updateKeyStates() { + long window = MinecraftClient.getInstance().getWindow().getHandle(); + KeyBinding.updatePressedStates(); + + int[] buttons = {GLFW.GLFW_MOUSE_BUTTON_LEFT, GLFW.GLFW_MOUSE_BUTTON_MIDDLE, GLFW.GLFW_MOUSE_BUTTON_RIGHT}; + for (int j : buttons) { + InputUtil.Key button = InputUtil.Type.MOUSE.createFromCode(j); + KeyBinding.setKeyPressed(button, GLFW.glfwGetMouseButton(window, j) == GLFW.GLFW_PRESS); + } + } } From 6731f9dfdcd4ba5f7b00a91be59b8a41e6c17213 Mon Sep 17 00:00:00 2001 From: UndercoverGoose <53491740+UndercoverGoose@users.noreply.github.com> Date: Tue, 7 Oct 2025 15:07:12 -0400 Subject: [PATCH 16/37] create tick helper to schedule events to occur in X ticks --- .../java/dev/cigarette/helper/TickHelper.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 src/main/java/dev/cigarette/helper/TickHelper.java diff --git a/src/main/java/dev/cigarette/helper/TickHelper.java b/src/main/java/dev/cigarette/helper/TickHelper.java new file mode 100644 index 00000000..2cef7069 --- /dev/null +++ b/src/main/java/dev/cigarette/helper/TickHelper.java @@ -0,0 +1,39 @@ +package dev.cigarette.helper; + +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; +import net.minecraft.util.Pair; + +import java.util.HashMap; + +public class TickHelper { + private static final HashMap> onceActions = new HashMap<>(); + + public static void scheduleOnce(Object key, Runnable action, int ticks) { + onceActions.put(key, new Pair<>(ticks, action)); + } + + public static void unschedule(Object key) { + onceActions.remove(key); + } + + public static int whenOnce(Object key) { + if (!onceActions.containsKey(key)) return -1; + return onceActions.get(key).getLeft(); + } + + static { + ClientTickEvents.END_CLIENT_TICK.register(client -> { + if (onceActions.isEmpty()) return; + for (Object key : onceActions.keySet()) { + Pair action = onceActions.get(key); + int remainingTicks = action.getLeft() - 1; + if (remainingTicks <= 0) { + onceActions.remove(key); + action.getRight().run(); + continue; + } + action.setLeft(remainingTicks); + } + }); + } +} From ccd257fcf808ff3167444845d9ea9a116491dd0a Mon Sep 17 00:00:00 2001 From: UndercoverGoose <53491740+UndercoverGoose@users.noreply.github.com> Date: Tue, 7 Oct 2025 15:07:49 -0400 Subject: [PATCH 17/37] add hold/release for X ticks functionality --- .../helper/keybind/MinecraftKeybind.java | 41 ++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/src/main/java/dev/cigarette/helper/keybind/MinecraftKeybind.java b/src/main/java/dev/cigarette/helper/keybind/MinecraftKeybind.java index 87535b76..30cdd50d 100644 --- a/src/main/java/dev/cigarette/helper/keybind/MinecraftKeybind.java +++ b/src/main/java/dev/cigarette/helper/keybind/MinecraftKeybind.java @@ -1,5 +1,6 @@ package dev.cigarette.helper.keybind; +import dev.cigarette.helper.TickHelper; import net.minecraft.client.option.KeyBinding; import net.minecraft.client.util.InputUtil; import org.jetbrains.annotations.NotNull; @@ -52,7 +53,7 @@ public boolean wasVirtuallyPressed() { } /** - * Virtually presses the key triggering any Minecraft related events. + * Virtually presses the key triggering any Minecraft related events. For player movement, you must use {@code holdForTicks(1)} to simulate a key press because the client only uses {@code isPressed()} to process movement. */ public void press() { if (this.minecraftBinding == null) return; @@ -69,6 +70,28 @@ public void hold() { KeyBinding.setKeyPressed(key, true); } + /** + * Virtually sets the holding state of the key. + * + * @param state The state to set + */ + public void hold(boolean state) { + if (this.minecraftBinding == null) return; + if (state) this.hold(); + else this.release(); + } + + /** + * Virtually hold this key for a specific number of ticks. + * + * @param numOfTicks The number of ticks to hold the key for + */ + public void holdForTicks(int numOfTicks) { + if (this.minecraftBinding == null) return; + this.hold(); + TickHelper.scheduleOnce(this, this::release, numOfTicks); + } + /** * Virtually releases the key. */ @@ -76,6 +99,22 @@ public void release() { if (this.minecraftBinding == null) return; InputUtil.Key key = InputUtil.fromTranslationKey(this.minecraftBinding.getBoundKeyTranslationKey()); KeyBinding.setKeyPressed(key, false); + TickHelper.unschedule(this); + } + + /** + * Virtually releases this key for a specific number of ticks. + * + * @param numOfTicks The number of ticks to release the key for + */ + public void releaseForTicks(int numOfTicks) { + if (this.minecraftBinding == null) return; + this.release(); + TickHelper.scheduleOnce(this, this::hold, numOfTicks); + } + + public int ticksLeft() { + return TickHelper.whenOnce(this); } /** From 2a28257c268433a8f6f61197305272c51f5034e5 Mon Sep 17 00:00:00 2001 From: UndercoverGoose <53491740+UndercoverGoose@users.noreply.github.com> Date: Wed, 8 Oct 2025 08:56:09 -0400 Subject: [PATCH 18/37] chore: add javadocs to TickHelper --- .../java/dev/cigarette/helper/TickHelper.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/main/java/dev/cigarette/helper/TickHelper.java b/src/main/java/dev/cigarette/helper/TickHelper.java index 2cef7069..89a8a5a4 100644 --- a/src/main/java/dev/cigarette/helper/TickHelper.java +++ b/src/main/java/dev/cigarette/helper/TickHelper.java @@ -5,17 +5,41 @@ import java.util.HashMap; +/** + * Helper class for scheduling events to occur in the future. + */ public class TickHelper { + /** + * Actions that only occur once. + */ private static final HashMap> onceActions = new HashMap<>(); + /** + * Schedule an {@code action} to occur after {@code ticks} number of ticks. + * + * @param key A unique identifier to store this action. Usually {@code this} unless multiple actions are needed. + * @param action The action to perform once the number of ticks has passed. + * @param ticks The number of ticks to wait until triggered. + */ public static void scheduleOnce(Object key, Runnable action, int ticks) { onceActions.put(key, new Pair<>(ticks, action)); } + /** + * Unschedule an event that was already scheduled. + * + * @param key The unique identifier used in scheduling the event. + */ public static void unschedule(Object key) { onceActions.remove(key); } + /** + * Get the remaining ticks until a scheduled event triggers. + * + * @param key The unique identifier used in scheduling the event. + * @return Remaining ticks until event is triggered + */ public static int whenOnce(Object key) { if (!onceActions.containsKey(key)) return -1; return onceActions.get(key).getLeft(); From 3d8fb4a374ad56382a4319e0ee1e5e95534ea30e Mon Sep 17 00:00:00 2001 From: UndercoverGoose <53491740+UndercoverGoose@users.noreply.github.com> Date: Wed, 8 Oct 2025 09:02:17 -0400 Subject: [PATCH 19/37] chore: finish javadocs in KeybindHelper --- src/main/java/dev/cigarette/helper/KeybindHelper.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/dev/cigarette/helper/KeybindHelper.java b/src/main/java/dev/cigarette/helper/KeybindHelper.java index 762bd057..a72ef92e 100644 --- a/src/main/java/dev/cigarette/helper/KeybindHelper.java +++ b/src/main/java/dev/cigarette/helper/KeybindHelper.java @@ -13,6 +13,9 @@ import java.util.HashSet; +/** + * Helper class for handling the physical and virtual state of keybinds. Also supports input blocking via {@code InputBlocker}. + */ public class KeybindHelper { public static final MinecraftKeybind KEY_SNEAK = new MinecraftKeybind("key.sneak"); public static final MinecraftKeybind KEY_MOVE_BACK = new MinecraftKeybind("key.back"); @@ -21,6 +24,9 @@ public class KeybindHelper { public static final MinecraftKeybind KEY_RIGHT_CLICK = new MinecraftKeybind("key.use").asMouse(); public static final MinecraftKeybind KEY_JUMP = new MinecraftKeybind("key.jump"); + /** + * Set of bindings that wrap native Minecraft {@code KeyBinding}'s. + */ private static final HashSet wrappedBindings = new HashSet<>(); static { @@ -230,6 +236,9 @@ public static boolean isMouseBlocked() { return blockedInputs != null && blockedInputs.blocksCamera(); } + /** + * Reset the state of all key and mouse bindings to the last physical state reported by GLFW. Wraps {@code KeyBinding.updatePressedStates()} as that method does not reset mouse buttons. + */ public static void updateKeyStates() { long window = MinecraftClient.getInstance().getWindow().getHandle(); KeyBinding.updatePressedStates(); From f0feeed8469fcc91062ab46c2f05cfb5ca65b9a3 Mon Sep 17 00:00:00 2001 From: UndercoverGoose <53491740+UndercoverGoose@users.noreply.github.com> Date: Wed, 8 Oct 2025 09:06:19 -0400 Subject: [PATCH 20/37] chore: rename keys to make sense --- .../java/dev/cigarette/helper/KeybindHelper.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/dev/cigarette/helper/KeybindHelper.java b/src/main/java/dev/cigarette/helper/KeybindHelper.java index a72ef92e..ba72aca5 100644 --- a/src/main/java/dev/cigarette/helper/KeybindHelper.java +++ b/src/main/java/dev/cigarette/helper/KeybindHelper.java @@ -21,7 +21,7 @@ public class KeybindHelper { public static final MinecraftKeybind KEY_MOVE_BACK = new MinecraftKeybind("key.back"); public static final MinecraftKeybind KEY_MOVE_LEFT = new MinecraftKeybind("key.left"); public static final MinecraftKeybind KEY_MOVE_RIGHT = new MinecraftKeybind("key.right"); - public static final MinecraftKeybind KEY_RIGHT_CLICK = new MinecraftKeybind("key.use").asMouse(); + public static final MinecraftKeybind KEY_USE_ITEM = new MinecraftKeybind("key.use").asMouse(); public static final MinecraftKeybind KEY_JUMP = new MinecraftKeybind("key.jump"); /** @@ -34,14 +34,14 @@ public class KeybindHelper { wrappedBindings.add(KEY_MOVE_BACK); wrappedBindings.add(KEY_MOVE_LEFT); wrappedBindings.add(KEY_MOVE_RIGHT); - wrappedBindings.add(KEY_RIGHT_CLICK); + wrappedBindings.add(KEY_USE_ITEM); wrappedBindings.add(KEY_JUMP); } /** * Keybind to toggle {@code CigaretteScreen}. */ - public static final VirtualKeybind TOGGLE_GUI = new VirtualKeybind(GLFW.GLFW_KEY_RIGHT_SHIFT); + public static final VirtualKeybind KEY_TOGGLE_GUI = new VirtualKeybind(GLFW.GLFW_KEY_RIGHT_SHIFT); /** * Set of custom keybinds that can be triggered. @@ -77,7 +77,7 @@ public static boolean handleKeyByGUI(MinecraftClient client, int key, int scanco case GLFW.GLFW_RELEASE -> CigaretteScreen.bindingKey.keyReleased(key, scancode, modifiers); } } else { - if (key == GLFW.GLFW_KEY_ESCAPE || (action == GLFW.GLFW_PRESS && TOGGLE_GUI.isOf(key, scancode))) { + if (key == GLFW.GLFW_KEY_ESCAPE || (action == GLFW.GLFW_PRESS && KEY_TOGGLE_GUI.isOf(key, scancode))) { Cigarette.SCREEN.close(); } } @@ -96,7 +96,7 @@ public static boolean handleKeyByGUI(MinecraftClient client, int key, int scanco * @return Whether the key event should be cancelled */ public static boolean handleBlockedKeyInputs(MinecraftClient client, int key, int scancode, int action, int modifiers) { - if (TOGGLE_GUI.isOf(key, scancode)) return false; + if (KEY_TOGGLE_GUI.isOf(key, scancode)) return false; if (blockedInputs == null) return false; return blockedInputs.processKey(key, scancode, action, modifiers); } @@ -135,7 +135,7 @@ public static boolean handleCustomKeys(MinecraftClient client, int key, int scan keybind.physicalAction(action); } if (action != GLFW.GLFW_PRESS) return false; - if (TOGGLE_GUI.isOf(key, scancode)) { + if (KEY_TOGGLE_GUI.isOf(key, scancode)) { Cigarette.SCREEN.setParent(client.currentScreen); client.setScreen(Cigarette.SCREEN); return true; From 4f7aa600d233f30a641da4a66836aaa68d2c2c39 Mon Sep 17 00:00:00 2001 From: UndercoverGoose <53491740+UndercoverGoose@users.noreply.github.com> Date: Wed, 8 Oct 2025 09:12:59 -0400 Subject: [PATCH 21/37] add most other native keybinds --- .../dev/cigarette/helper/KeybindHelper.java | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/main/java/dev/cigarette/helper/KeybindHelper.java b/src/main/java/dev/cigarette/helper/KeybindHelper.java index ba72aca5..e97838ea 100644 --- a/src/main/java/dev/cigarette/helper/KeybindHelper.java +++ b/src/main/java/dev/cigarette/helper/KeybindHelper.java @@ -17,12 +17,27 @@ * Helper class for handling the physical and virtual state of keybinds. Also supports input blocking via {@code InputBlocker}. */ public class KeybindHelper { + public static final MinecraftKeybind KEY_SPRINT = new MinecraftKeybind("key.sprint"); public static final MinecraftKeybind KEY_SNEAK = new MinecraftKeybind("key.sneak"); + public static final MinecraftKeybind KEY_MOVE_FORWARD = new MinecraftKeybind("key.forward"); public static final MinecraftKeybind KEY_MOVE_BACK = new MinecraftKeybind("key.back"); public static final MinecraftKeybind KEY_MOVE_LEFT = new MinecraftKeybind("key.left"); public static final MinecraftKeybind KEY_MOVE_RIGHT = new MinecraftKeybind("key.right"); public static final MinecraftKeybind KEY_USE_ITEM = new MinecraftKeybind("key.use").asMouse(); + public static final MinecraftKeybind KEY_ATTACK = new MinecraftKeybind("key.attack").asMouse(); + public static final MinecraftKeybind KEY_PICK_ITEM = new MinecraftKeybind("key.pickItem").asMouse(); public static final MinecraftKeybind KEY_JUMP = new MinecraftKeybind("key.jump"); + public static final MinecraftKeybind KEY_DROP_ITEM = new MinecraftKeybind("key.drop"); + public static final MinecraftKeybind KEY_TOGGLE_INVENTORY = new MinecraftKeybind("key.inventory"); + public static final MinecraftKeybind KEY_SLOT_1 = new MinecraftKeybind("key.hotbar.1"); + public static final MinecraftKeybind KEY_SLOT_2 = new MinecraftKeybind("key.hotbar.2"); + public static final MinecraftKeybind KEY_SLOT_3 = new MinecraftKeybind("key.hotbar.3"); + public static final MinecraftKeybind KEY_SLOT_4 = new MinecraftKeybind("key.hotbar.4"); + public static final MinecraftKeybind KEY_SLOT_5 = new MinecraftKeybind("key.hotbar.5"); + public static final MinecraftKeybind KEY_SLOT_6 = new MinecraftKeybind("key.hotbar.6"); + public static final MinecraftKeybind KEY_SLOT_7 = new MinecraftKeybind("key.hotbar.7"); + public static final MinecraftKeybind KEY_SLOT_8 = new MinecraftKeybind("key.hotbar.8"); + public static final MinecraftKeybind KEY_SLOT_9 = new MinecraftKeybind("key.hotbar.9"); /** * Set of bindings that wrap native Minecraft {@code KeyBinding}'s. @@ -30,12 +45,27 @@ public class KeybindHelper { private static final HashSet wrappedBindings = new HashSet<>(); static { + wrappedBindings.add(KEY_SPRINT); wrappedBindings.add(KEY_SNEAK); + wrappedBindings.add(KEY_MOVE_FORWARD); wrappedBindings.add(KEY_MOVE_BACK); wrappedBindings.add(KEY_MOVE_LEFT); wrappedBindings.add(KEY_MOVE_RIGHT); wrappedBindings.add(KEY_USE_ITEM); + wrappedBindings.add(KEY_ATTACK); + wrappedBindings.add(KEY_PICK_ITEM); wrappedBindings.add(KEY_JUMP); + wrappedBindings.add(KEY_DROP_ITEM); + wrappedBindings.add(KEY_TOGGLE_INVENTORY); + wrappedBindings.add(KEY_SLOT_1); + wrappedBindings.add(KEY_SLOT_2); + wrappedBindings.add(KEY_SLOT_3); + wrappedBindings.add(KEY_SLOT_4); + wrappedBindings.add(KEY_SLOT_5); + wrappedBindings.add(KEY_SLOT_6); + wrappedBindings.add(KEY_SLOT_7); + wrappedBindings.add(KEY_SLOT_8); + wrappedBindings.add(KEY_SLOT_9); } /** From 3c68f3ee072e977d8346b8c41cd3fa868c8e8f48 Mon Sep 17 00:00:00 2001 From: UndercoverGoose <53491740+UndercoverGoose@users.noreply.github.com> Date: Wed, 8 Oct 2025 09:21:19 -0400 Subject: [PATCH 22/37] chore: finish javadocs in MinecraftKeybind --- .../helper/keybind/MinecraftKeybind.java | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/main/java/dev/cigarette/helper/keybind/MinecraftKeybind.java b/src/main/java/dev/cigarette/helper/keybind/MinecraftKeybind.java index 30cdd50d..b454ffb1 100644 --- a/src/main/java/dev/cigarette/helper/keybind/MinecraftKeybind.java +++ b/src/main/java/dev/cigarette/helper/keybind/MinecraftKeybind.java @@ -7,10 +7,24 @@ import org.jetbrains.annotations.Nullable; import org.lwjgl.glfw.GLFW; +/** + * A wrapper class for more precise control over a Minecraft {@code KeyBinding}. + */ public class MinecraftKeybind extends VirtualKeybind { + /** + * The reference to the actual {@code KeyBinding}. + */ private @Nullable KeyBinding minecraftBinding; + /** + * The keybind ID to support creation of keybinds before they exist. + */ private final @NotNull String minecraftKeybindId; + /** + * Create a new {@code KeyBinding} wrapper. + * + * @param keybindId The keybinds translation key + */ public MinecraftKeybind(@NotNull String keybindId) { super(GLFW.GLFW_KEY_UNKNOWN); this.minecraftBinding = KeyBinding.byId(keybindId); @@ -113,6 +127,11 @@ public void releaseForTicks(int numOfTicks) { TickHelper.scheduleOnce(this, this::hold, numOfTicks); } + /** + * The remaining ticks on the {@code holdForTicks()} or {@code releaseForTicks()}. + * + * @return The remaining ticks + */ public int ticksLeft() { return TickHelper.whenOnce(this); } @@ -134,12 +153,23 @@ public MinecraftKeybind asMouse() { return this; } + /** + * {@return if this keybind is currently bound to a specific key} + * + * @param key The key to check if bounded + * @param scancode The scancode for misc {@code GLFW_KEY_UNKNOWN} keys + */ @Override public boolean isOf(int key, int scancode) { if (this.minecraftBinding == null) return false; return this.minecraftBinding.matchesKey(key, scancode); } + /** + * {@return if this keybind is currently bound to a specific mouse button} + * + * @param button The mouse button to check if bounded + */ @Override public boolean isOfMouse(int button) { if (this.minecraftBinding == null) return false; From 778ce2eab0d68ae0f399ca05d101fc3a332096a1 Mon Sep 17 00:00:00 2001 From: UndercoverGoose <53491740+UndercoverGoose@users.noreply.github.com> Date: Wed, 8 Oct 2025 09:24:16 -0400 Subject: [PATCH 23/37] remove asMouse in favor of a constructor arg --- .../dev/cigarette/helper/KeybindHelper.java | 6 +++--- .../helper/keybind/MinecraftKeybind.java | 19 +++++++++++++------ .../helper/keybind/VirtualKeybind.java | 12 ++++-------- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/main/java/dev/cigarette/helper/KeybindHelper.java b/src/main/java/dev/cigarette/helper/KeybindHelper.java index e97838ea..459ba9b7 100644 --- a/src/main/java/dev/cigarette/helper/KeybindHelper.java +++ b/src/main/java/dev/cigarette/helper/KeybindHelper.java @@ -23,9 +23,9 @@ public class KeybindHelper { public static final MinecraftKeybind KEY_MOVE_BACK = new MinecraftKeybind("key.back"); public static final MinecraftKeybind KEY_MOVE_LEFT = new MinecraftKeybind("key.left"); public static final MinecraftKeybind KEY_MOVE_RIGHT = new MinecraftKeybind("key.right"); - public static final MinecraftKeybind KEY_USE_ITEM = new MinecraftKeybind("key.use").asMouse(); - public static final MinecraftKeybind KEY_ATTACK = new MinecraftKeybind("key.attack").asMouse(); - public static final MinecraftKeybind KEY_PICK_ITEM = new MinecraftKeybind("key.pickItem").asMouse(); + public static final MinecraftKeybind KEY_USE_ITEM = new MinecraftKeybind("key.use", true); + public static final MinecraftKeybind KEY_ATTACK = new MinecraftKeybind("key.attack", true); + public static final MinecraftKeybind KEY_PICK_ITEM = new MinecraftKeybind("key.pickItem", true); public static final MinecraftKeybind KEY_JUMP = new MinecraftKeybind("key.jump"); public static final MinecraftKeybind KEY_DROP_ITEM = new MinecraftKeybind("key.drop"); public static final MinecraftKeybind KEY_TOGGLE_INVENTORY = new MinecraftKeybind("key.inventory"); diff --git a/src/main/java/dev/cigarette/helper/keybind/MinecraftKeybind.java b/src/main/java/dev/cigarette/helper/keybind/MinecraftKeybind.java index b454ffb1..9093eed8 100644 --- a/src/main/java/dev/cigarette/helper/keybind/MinecraftKeybind.java +++ b/src/main/java/dev/cigarette/helper/keybind/MinecraftKeybind.java @@ -31,6 +31,19 @@ public MinecraftKeybind(@NotNull String keybindId) { this.minecraftKeybindId = keybindId; } + /** + * Create a new {@code KeyBinding} wrapper. + * + * @param keybindId The keybinds translation key + * @param isMouse Whether this is a mouse keybind or not + */ + public MinecraftKeybind(@NotNull String keybindId, boolean isMouse) { + super(GLFW.GLFW_KEY_UNKNOWN); + this.minecraftBinding = KeyBinding.byId(keybindId); + this.minecraftKeybindId = keybindId; + this.isMouse = isMouse; + } + /** * Attempts to link this object with the native {@code KeyBinding} from Minecraft. * @@ -147,12 +160,6 @@ public boolean equals(Object o) { return this.minecraftBinding.getTranslationKey().equals(other.minecraftBinding.getTranslationKey()); } - @Override - public MinecraftKeybind asMouse() { - this.isMouse = true; - return this; - } - /** * {@return if this keybind is currently bound to a specific key} * diff --git a/src/main/java/dev/cigarette/helper/keybind/VirtualKeybind.java b/src/main/java/dev/cigarette/helper/keybind/VirtualKeybind.java index 67b69754..ebc860fd 100644 --- a/src/main/java/dev/cigarette/helper/keybind/VirtualKeybind.java +++ b/src/main/java/dev/cigarette/helper/keybind/VirtualKeybind.java @@ -14,14 +14,10 @@ public VirtualKeybind(int defaultKey) { this.defaultKey = defaultKey; } - /** - * Indicates that this keybind should receive events from the mouse instead of the keyboard. - * - * @return This object for method chaining - */ - public VirtualKeybind asMouse() { - this.isMouse = true; - return this; + public VirtualKeybind(int defaultKey, boolean isMouse) { + this.currentKey = defaultKey; + this.defaultKey = defaultKey; + this.isMouse = isMouse; } /** From 7f4c4d712f29a17fcc1fdafcbd87545cfcbfd0ef Mon Sep 17 00:00:00 2001 From: UndercoverGoose <53491740+UndercoverGoose@users.noreply.github.com> Date: Wed, 8 Oct 2025 09:30:25 -0400 Subject: [PATCH 24/37] chore: finish javadocs in VirtualKeybind --- .../helper/keybind/MinecraftKeybind.java | 11 ----- .../helper/keybind/VirtualKeybind.java | 40 +++++++++++++++++++ 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/src/main/java/dev/cigarette/helper/keybind/MinecraftKeybind.java b/src/main/java/dev/cigarette/helper/keybind/MinecraftKeybind.java index 9093eed8..85e6cf47 100644 --- a/src/main/java/dev/cigarette/helper/keybind/MinecraftKeybind.java +++ b/src/main/java/dev/cigarette/helper/keybind/MinecraftKeybind.java @@ -160,23 +160,12 @@ public boolean equals(Object o) { return this.minecraftBinding.getTranslationKey().equals(other.minecraftBinding.getTranslationKey()); } - /** - * {@return if this keybind is currently bound to a specific key} - * - * @param key The key to check if bounded - * @param scancode The scancode for misc {@code GLFW_KEY_UNKNOWN} keys - */ @Override public boolean isOf(int key, int scancode) { if (this.minecraftBinding == null) return false; return this.minecraftBinding.matchesKey(key, scancode); } - /** - * {@return if this keybind is currently bound to a specific mouse button} - * - * @param button The mouse button to check if bounded - */ @Override public boolean isOfMouse(int button) { if (this.minecraftBinding == null) return false; diff --git a/src/main/java/dev/cigarette/helper/keybind/VirtualKeybind.java b/src/main/java/dev/cigarette/helper/keybind/VirtualKeybind.java index ebc860fd..9ffee3d1 100644 --- a/src/main/java/dev/cigarette/helper/keybind/VirtualKeybind.java +++ b/src/main/java/dev/cigarette/helper/keybind/VirtualKeybind.java @@ -2,18 +2,47 @@ import org.lwjgl.glfw.GLFW; +/** + * A fake {@code KeyBinding} which handles the physical state of a key. + */ public class VirtualKeybind { + /** + * The key currently bounded to. + */ protected int currentKey; + /** + * The original key that was bounded to. + */ protected final int defaultKey; + /** + * Whether the bounded key is physically pressed. + */ protected boolean pressed = false; + /** + * Times the bounded key was pressed. + */ protected int timesPressed = 0; + /** + * Whether this is a mouse keybind or not. + */ protected boolean isMouse = false; + /** + * Creates a virtual keybind. Does not create any {@code KeyBinding}'s or register to any Minecraft events. + * + * @param defaultKey The keycode of the key to monitor + */ public VirtualKeybind(int defaultKey) { this.currentKey = defaultKey; this.defaultKey = defaultKey; } + /** + * Creates a virtual keybind. Does not create any {@code KeyBinding}'s or register to any Minecraft events. + * + * @param defaultKey The keycode of the key to monitor + * @param isMouse Whether this is a mouse keybind or not + */ public VirtualKeybind(int defaultKey, boolean isMouse) { this.currentKey = defaultKey; this.defaultKey = defaultKey; @@ -58,10 +87,21 @@ public boolean wasPhysicallyPressed() { return true; } + /** + * {@return if the key is bounded to this keybind} + * + * @param key The key to check if bounded + * @param scancode The scancode for misc {@code GLFW_KEY_UNKNOWN} keys + */ public boolean isOf(int key, int scancode) { return this.currentKey == key; } + /** + * {@return if mouse button is bounded to this keybind} + * + * @param button The mouse button to check if bounded + */ public boolean isOfMouse(int button) { return this.currentKey == button; } From ff2d0ce0790cc8d195884ddd9ed000cfd512defd Mon Sep 17 00:00:00 2001 From: UndercoverGoose <53491740+UndercoverGoose@users.noreply.github.com> Date: Wed, 8 Oct 2025 09:31:33 -0400 Subject: [PATCH 25/37] fix: missing checks on whether keybind is a mouse binding when comparing against mouse inputs --- .../java/dev/cigarette/helper/keybind/VirtualKeybind.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/dev/cigarette/helper/keybind/VirtualKeybind.java b/src/main/java/dev/cigarette/helper/keybind/VirtualKeybind.java index 9ffee3d1..8143b63d 100644 --- a/src/main/java/dev/cigarette/helper/keybind/VirtualKeybind.java +++ b/src/main/java/dev/cigarette/helper/keybind/VirtualKeybind.java @@ -94,7 +94,7 @@ public boolean wasPhysicallyPressed() { * @param scancode The scancode for misc {@code GLFW_KEY_UNKNOWN} keys */ public boolean isOf(int key, int scancode) { - return this.currentKey == key; + return !this.isMouse && this.currentKey == key; } /** @@ -103,6 +103,6 @@ public boolean isOf(int key, int scancode) { * @param button The mouse button to check if bounded */ public boolean isOfMouse(int button) { - return this.currentKey == button; + return this.isMouse && this.currentKey == button; } } From 4ef63927bb6148025b17b06d76580dcdfea02aae Mon Sep 17 00:00:00 2001 From: UndercoverGoose <53491740+UndercoverGoose@users.noreply.github.com> Date: Wed, 8 Oct 2025 09:38:37 -0400 Subject: [PATCH 26/37] chore: add javadocs to InputBlocker --- .../helper/keybind/InputBlocker.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/main/java/dev/cigarette/helper/keybind/InputBlocker.java b/src/main/java/dev/cigarette/helper/keybind/InputBlocker.java index 3eac1cfc..72063cc6 100644 --- a/src/main/java/dev/cigarette/helper/keybind/InputBlocker.java +++ b/src/main/java/dev/cigarette/helper/keybind/InputBlocker.java @@ -1,10 +1,27 @@ package dev.cigarette.helper.keybind; +/** + * A grouping of keybinds and event handlers for deciding when to block inputs or let events propagate. + */ public class InputBlocker { + /** + * The keybindings blocked when this blocker is activated. + */ private final MinecraftKeybind[] blockedBindings; + /** + * Whether this blocker also prevents changes in player perspective by the mouse. + */ private boolean blockCamera = false; + /** + * Whether all keybindings attached have been linked with their native Minecraft {@code KeyBinding}. + */ protected boolean complete = false; + /** + * Creates a new input blocker. + * + * @param blockedBindings The keybinds to block + */ public InputBlocker(MinecraftKeybind... blockedBindings) { this.blockedBindings = blockedBindings; } @@ -19,6 +36,9 @@ public InputBlocker preventCameraChanges() { return this; } + /** + * {@return whether this input blocker prevents perspective changes from the mouse} + */ public boolean blocksCamera() { return this.blockCamera; } @@ -40,6 +60,15 @@ private boolean complete() { return this.complete; } + /** + * Processes a non-mouse key event through this blocker. + * + * @param key The key of the event + * @param scancode The scancode of the event + * @param action The action performed on the key + * @param modifiers The modifiers of the event + * @return Whether the event should be considered handled and no longer propagate or not + */ public boolean processKey(int key, int scancode, int action, int modifiers) { if (!this.complete()) return false; for (MinecraftKeybind binding : blockedBindings) { @@ -51,6 +80,14 @@ public boolean processKey(int key, int scancode, int action, int modifiers) { return false; } + /** + * Processes a mouse key event through this blocker. + * + * @param button The mouse button of the event + * @param action The action performed on the mouse button + * @param modifiers The modifiers of the event + * @return Whether the event should be considered handled and no longer propagate or not + */ public boolean processMouse(int button, int action, int modifiers) { if (!this.complete()) return false; for (MinecraftKeybind binding : blockedBindings) { From e0eb92fc9c707660ef6fbeb476204e58bb5fc3e3 Mon Sep 17 00:00:00 2001 From: UndercoverGoose <53491740+UndercoverGoose@users.noreply.github.com> Date: Wed, 8 Oct 2025 09:51:11 -0400 Subject: [PATCH 27/37] add methods for setting the default and current bounded key --- .../helper/keybind/MinecraftKeybind.java | 14 +++++++++++++ .../helper/keybind/VirtualKeybind.java | 20 ++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/main/java/dev/cigarette/helper/keybind/MinecraftKeybind.java b/src/main/java/dev/cigarette/helper/keybind/MinecraftKeybind.java index 85e6cf47..0a51c97b 100644 --- a/src/main/java/dev/cigarette/helper/keybind/MinecraftKeybind.java +++ b/src/main/java/dev/cigarette/helper/keybind/MinecraftKeybind.java @@ -44,6 +44,20 @@ public MinecraftKeybind(@NotNull String keybindId, boolean isMouse) { this.isMouse = isMouse; } + @Override + public void setDefaultKey(int defaultKey) { + } + + @Override + public void setKey(int key) { + if (this.minecraftBinding == null) return; + if (this.isMouse) { + this.minecraftBinding.setBoundKey(InputUtil.Type.MOUSE.createFromCode(key)); + } else { + this.minecraftBinding.setBoundKey(InputUtil.Type.KEYSYM.createFromCode(key)); + } + } + /** * Attempts to link this object with the native {@code KeyBinding} from Minecraft. * diff --git a/src/main/java/dev/cigarette/helper/keybind/VirtualKeybind.java b/src/main/java/dev/cigarette/helper/keybind/VirtualKeybind.java index 8143b63d..ff149415 100644 --- a/src/main/java/dev/cigarette/helper/keybind/VirtualKeybind.java +++ b/src/main/java/dev/cigarette/helper/keybind/VirtualKeybind.java @@ -13,7 +13,7 @@ public class VirtualKeybind { /** * The original key that was bounded to. */ - protected final int defaultKey; + protected int defaultKey; /** * Whether the bounded key is physically pressed. */ @@ -49,6 +49,24 @@ public VirtualKeybind(int defaultKey, boolean isMouse) { this.isMouse = isMouse; } + /** + * Set the default key for this keybinding. Does not update the currently bounded key. + * + * @param defaultKey The key to set as default + */ + public void setDefaultKey(int defaultKey) { + this.defaultKey = defaultKey; + } + + /** + * Sets the current key for this keybinding. + * + * @param key The key to set as currently bounded + */ + public void setKey(int key) { + this.currentKey = key; + } + /** * {@return whether this a mouse keybind or not} */ From ad862be6b66374e26010815b4de99580fc86486a Mon Sep 17 00:00:00 2001 From: UndercoverGoose <53491740+UndercoverGoose@users.noreply.github.com> Date: Wed, 8 Oct 2025 10:07:19 -0400 Subject: [PATCH 28/37] add registering method for virtual keybinds --- src/main/java/dev/cigarette/helper/KeybindHelper.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/java/dev/cigarette/helper/KeybindHelper.java b/src/main/java/dev/cigarette/helper/KeybindHelper.java index 459ba9b7..51e81a5a 100644 --- a/src/main/java/dev/cigarette/helper/KeybindHelper.java +++ b/src/main/java/dev/cigarette/helper/KeybindHelper.java @@ -209,7 +209,7 @@ public static boolean handleCustomMouse(MinecraftClient client, int button, int * Register a {@code MinecraftKeybind} wrapper so it can receive physical events. Wrappers from {@code KeybindHelper} are already registered. *

Required to use {@code isPhysicallyPressed()} and {@code wasPhysicallyPressed()}.

* - * @param keybind The keybind wrapper register + * @param keybind The keybind wrapper to register */ public static void registerWrapper(MinecraftKeybind keybind) { for (MinecraftKeybind existing : wrappedBindings) { @@ -218,6 +218,15 @@ public static void registerWrapper(MinecraftKeybind keybind) { wrappedBindings.add(keybind); } + /** + * Register a {@code VirtualKeybind} so it can receive physical events. + * + * @param keybind The keybind to register + */ + public static void registerVirtualKey(VirtualKeybind keybind) { + customBinds.add(keybind); + } + /** * Attempts to start input blocking. {@return false if input blocking is already running} Use {@code forceBlockInputs()} to bypass this check. * From 2cc9d6ee4d6e56cdc603f68184699eb0a7578fc0 Mon Sep 17 00:00:00 2001 From: UndercoverGoose <53491740+UndercoverGoose@users.noreply.github.com> Date: Wed, 8 Oct 2025 10:08:30 -0400 Subject: [PATCH 29/37] update KeybindWidget to use VirtualKeybind --- .../cigarette/gui/widget/KeybindWidget.java | 29 +++++++++---------- .../gui/widget/ToggleKeybindWidget.java | 5 ---- .../cigarette/module/bedwars/AutoBlockIn.java | 2 +- .../module/bedwars/DefenseViewer.java | 4 +-- .../module/keybind/AddGlassBlock.java | 2 +- .../cigarette/module/keybind/BreakBlock.java | 2 +- .../dev/cigarette/module/keybind/VClip.java | 2 +- 7 files changed, 19 insertions(+), 27 deletions(-) diff --git a/src/main/java/dev/cigarette/gui/widget/KeybindWidget.java b/src/main/java/dev/cigarette/gui/widget/KeybindWidget.java index a0222d6e..8fea2870 100644 --- a/src/main/java/dev/cigarette/gui/widget/KeybindWidget.java +++ b/src/main/java/dev/cigarette/gui/widget/KeybindWidget.java @@ -2,45 +2,42 @@ import dev.cigarette.Cigarette; import dev.cigarette.gui.CigaretteScreen; -import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; +import dev.cigarette.helper.KeybindHelper; +import dev.cigarette.helper.keybind.VirtualKeybind; import net.minecraft.client.MinecraftClient; import net.minecraft.client.font.TextRenderer; import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.option.KeyBinding; import net.minecraft.client.util.InputUtil; import net.minecraft.text.Text; import org.jetbrains.annotations.Nullable; import org.lwjgl.glfw.GLFW; import java.util.Objects; -import java.util.UUID; import java.util.function.Consumer; public class KeybindWidget extends BaseWidget { - private final KeyBinding keyBinding; - private InputUtil.Key utilKey; + private final VirtualKeybind keyBinding = new VirtualKeybind(GLFW.GLFW_KEY_UNKNOWN); + private InputUtil.Key utilKey = InputUtil.UNKNOWN_KEY; public KeybindWidget(String message, @Nullable String tooltip) { super(message, tooltip); - this.utilKey = InputUtil.UNKNOWN_KEY; - this.keyBinding = new KeyBinding(UUID.randomUUID().toString(), GLFW.GLFW_KEY_UNKNOWN, "cigarette.null"); - KeyBindingHelper.registerKeyBinding(this.keyBinding); + KeybindHelper.registerVirtualKey(this.keyBinding); } public KeybindWidget withDefaultKey(int key) { utilKey = InputUtil.fromKeyCode(key, 0); - keyBinding.setBoundKey(utilKey); + keyBinding.setDefaultKey(key); super.withDefault(key); return this; } - public void setBoundKey(@Nullable InputUtil.Key key) { - utilKey = key == null ? InputUtil.UNKNOWN_KEY : key; - keyBinding.setBoundKey(utilKey); - this.setRawState(utilKey.getCode()); + public void setBoundKey(int key) { + utilKey = key == GLFW.GLFW_KEY_UNKNOWN ? InputUtil.UNKNOWN_KEY : InputUtil.fromKeyCode(key, 0); + keyBinding.setKey(key); + this.setRawState(key); } - public KeyBinding getKeybind() { + public VirtualKeybind getKeybind() { return this.keyBinding; } @@ -89,12 +86,12 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { public boolean keyPressed(int keyCode, int scanCode, int modifiers) { if (!isBinding()) return false; if (keyCode == GLFW.GLFW_KEY_ESCAPE || keyCode == GLFW.GLFW_KEY_RIGHT_SHIFT) { - this.setBoundKey(null); + this.setBoundKey(GLFW.GLFW_KEY_UNKNOWN); } else { InputUtil.Key key = InputUtil.fromKeyCode(keyCode, scanCode); String keyName = key.getLocalizedText().getLiteralString(); if (keyName == null) return true; - this.setBoundKey(key); + this.setBoundKey(keyCode); } clearBinding(); return true; diff --git a/src/main/java/dev/cigarette/gui/widget/ToggleKeybindWidget.java b/src/main/java/dev/cigarette/gui/widget/ToggleKeybindWidget.java index 6be151b3..0037d1f5 100644 --- a/src/main/java/dev/cigarette/gui/widget/ToggleKeybindWidget.java +++ b/src/main/java/dev/cigarette/gui/widget/ToggleKeybindWidget.java @@ -2,7 +2,6 @@ import dev.cigarette.module.BaseModule; import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.option.KeyBinding; import org.jetbrains.annotations.Nullable; import org.lwjgl.glfw.GLFW; @@ -26,10 +25,6 @@ public ToggleKeybindWidget withDefaultKey(int keyCode) { return this; } - public KeyBinding getKeybind() { - return this.widget.getKeybind(); - } - public static BaseModule.GeneratedWidgets keybindModule(String displayName, @Nullable String tooltip) { ToggleKeybindWidget widget = new ToggleKeybindWidget(displayName, tooltip); return new BaseModule.GeneratedWidgets<>(null, widget); diff --git a/src/main/java/dev/cigarette/module/bedwars/AutoBlockIn.java b/src/main/java/dev/cigarette/module/bedwars/AutoBlockIn.java index ee538958..1bfe5bf4 100644 --- a/src/main/java/dev/cigarette/module/bedwars/AutoBlockIn.java +++ b/src/main/java/dev/cigarette/module/bedwars/AutoBlockIn.java @@ -131,7 +131,7 @@ protected void onEnabledTick(MinecraftClient client, @NotNull ClientWorld world, return; } if (!running) { - if (!keybind.getKeybind().isPressed()) return; + if (!keybind.getKeybind().wasPhysicallyPressed()) return; BlockPos pos = player.getBlockPos(); for (BedwarsAgent.PersistentBed bed : BedwarsAgent.getVisibleBeds()) { if (bed.head().isWithinDistance(pos, proximityToBeds.getRawState()) || bed.foot().isWithinDistance(pos, proximityToBeds.getRawState())) { diff --git a/src/main/java/dev/cigarette/module/bedwars/DefenseViewer.java b/src/main/java/dev/cigarette/module/bedwars/DefenseViewer.java index 910354d6..ed299615 100644 --- a/src/main/java/dev/cigarette/module/bedwars/DefenseViewer.java +++ b/src/main/java/dev/cigarette/module/bedwars/DefenseViewer.java @@ -136,10 +136,10 @@ protected void onEnabledTick(MinecraftClient client, @NotNull ClientWorld world, if (color != 0) defensiveBlocks.put(pos, color); } } - while (increaseKey.getKeybind().wasPressed()) { + while (increaseKey.getKeybind().wasPhysicallyPressed()) { this.layer = Math.min(this.layer + 1, PyramidQuadrant.MAX_LAYER); } - while (decreaseKey.getKeybind().wasPressed()) { + while (decreaseKey.getKeybind().wasPhysicallyPressed()) { this.layer = Math.max(this.layer - 1, 0); } } diff --git a/src/main/java/dev/cigarette/module/keybind/AddGlassBlock.java b/src/main/java/dev/cigarette/module/keybind/AddGlassBlock.java index 69be35eb..a06f2722 100644 --- a/src/main/java/dev/cigarette/module/keybind/AddGlassBlock.java +++ b/src/main/java/dev/cigarette/module/keybind/AddGlassBlock.java @@ -25,7 +25,7 @@ private AddGlassBlock(String id, String name, String tooltip) { @Override protected void onEnabledTick(MinecraftClient client, @NotNull ClientWorld world, @NotNull ClientPlayerEntity player) { - while (keybind.getKeybind().wasPressed()) { + while (keybind.getKeybind().wasPhysicallyPressed()) { HitResult target = client.crosshairTarget; if (target == null) break; if (target.getType() != HitResult.Type.BLOCK) break; diff --git a/src/main/java/dev/cigarette/module/keybind/BreakBlock.java b/src/main/java/dev/cigarette/module/keybind/BreakBlock.java index 94d4ec64..82b12146 100644 --- a/src/main/java/dev/cigarette/module/keybind/BreakBlock.java +++ b/src/main/java/dev/cigarette/module/keybind/BreakBlock.java @@ -23,7 +23,7 @@ private BreakBlock(String id, String name, String tooltip) { @Override protected void onEnabledTick(MinecraftClient client, @NotNull ClientWorld world, @NotNull ClientPlayerEntity player) { - while (keybind.getKeybind().wasPressed()) { + while (keybind.getKeybind().wasPhysicallyPressed()) { HitResult target = client.crosshairTarget; if (target == null) break; if (target.getType() != HitResult.Type.BLOCK) break; diff --git a/src/main/java/dev/cigarette/module/keybind/VClip.java b/src/main/java/dev/cigarette/module/keybind/VClip.java index b409236d..e272542f 100644 --- a/src/main/java/dev/cigarette/module/keybind/VClip.java +++ b/src/main/java/dev/cigarette/module/keybind/VClip.java @@ -23,7 +23,7 @@ private VClip(String id, String name, String tooltip) { @Override protected void onEnabledTick(MinecraftClient client, @NotNull ClientWorld world, @NotNull ClientPlayerEntity player) { - while (keybind.getKeybind().wasPressed()) { + while (keybind.getKeybind().wasPhysicallyPressed()) { Vec3d pos = player.getPos(); BlockPos blockPos = player.getBlockPos(); for (int offset = 3; offset < 6; offset++) { From 96c2bea83c744ea67633987248fd0e4bb99d4021 Mon Sep 17 00:00:00 2001 From: UndercoverGoose <53491740+UndercoverGoose@users.noreply.github.com> Date: Wed, 8 Oct 2025 10:11:41 -0400 Subject: [PATCH 30/37] fix: pressing escape to unbind keybind closes GUI afterwards --- src/main/java/dev/cigarette/helper/KeybindHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/dev/cigarette/helper/KeybindHelper.java b/src/main/java/dev/cigarette/helper/KeybindHelper.java index 51e81a5a..b14ca720 100644 --- a/src/main/java/dev/cigarette/helper/KeybindHelper.java +++ b/src/main/java/dev/cigarette/helper/KeybindHelper.java @@ -107,7 +107,7 @@ public static boolean handleKeyByGUI(MinecraftClient client, int key, int scanco case GLFW.GLFW_RELEASE -> CigaretteScreen.bindingKey.keyReleased(key, scancode, modifiers); } } else { - if (key == GLFW.GLFW_KEY_ESCAPE || (action == GLFW.GLFW_PRESS && KEY_TOGGLE_GUI.isOf(key, scancode))) { + if (action == GLFW.GLFW_PRESS && (key == GLFW.GLFW_KEY_ESCAPE || KEY_TOGGLE_GUI.isOf(key, scancode))) { Cigarette.SCREEN.close(); } } From 577a69d5f003db09f4470b056e4634560ad0eff5 Mon Sep 17 00:00:00 2001 From: UndercoverGoose <53491740+UndercoverGoose@users.noreply.github.com> Date: Wed, 8 Oct 2025 10:13:40 -0400 Subject: [PATCH 31/37] fix: keybinds loaded from config do not work --- src/main/java/dev/cigarette/gui/widget/KeybindWidget.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/dev/cigarette/gui/widget/KeybindWidget.java b/src/main/java/dev/cigarette/gui/widget/KeybindWidget.java index 8fea2870..0d67847d 100644 --- a/src/main/java/dev/cigarette/gui/widget/KeybindWidget.java +++ b/src/main/java/dev/cigarette/gui/widget/KeybindWidget.java @@ -27,6 +27,7 @@ public KeybindWidget(String message, @Nullable String tooltip) { public KeybindWidget withDefaultKey(int key) { utilKey = InputUtil.fromKeyCode(key, 0); keyBinding.setDefaultKey(key); + keyBinding.setKey(key); super.withDefault(key); return this; } From 64e1a8534ec07ef30d4b8cfe7e2600a9ae7ef9eb Mon Sep 17 00:00:00 2001 From: UndercoverGoose <53491740+UndercoverGoose@users.noreply.github.com> Date: Wed, 8 Oct 2025 10:59:51 -0400 Subject: [PATCH 32/37] remove KeyBindingAccessor and KeyboardInputMixin and update modules that used those --- .../cigarette/mixin/KeyBindingAccessor.java | 14 -- .../cigarette/mixin/KeyboardInputMixin.java | 39 ---- .../cigarette/module/bedwars/AutoBlockIn.java | 15 +- .../dev/cigarette/module/bedwars/Bridger.java | 166 +++++++----------- .../cigarette/module/combat/AutoClicker.java | 9 +- .../cigarette/module/combat/PerfectHit.java | 9 +- src/main/resources/cigarette.mixins.json | 2 - 7 files changed, 68 insertions(+), 186 deletions(-) delete mode 100644 src/main/java/dev/cigarette/mixin/KeyBindingAccessor.java delete mode 100644 src/main/java/dev/cigarette/mixin/KeyboardInputMixin.java diff --git a/src/main/java/dev/cigarette/mixin/KeyBindingAccessor.java b/src/main/java/dev/cigarette/mixin/KeyBindingAccessor.java deleted file mode 100644 index 726af328..00000000 --- a/src/main/java/dev/cigarette/mixin/KeyBindingAccessor.java +++ /dev/null @@ -1,14 +0,0 @@ -package dev.cigarette.mixin; - -import net.minecraft.client.option.KeyBinding; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; - -@Mixin(KeyBinding.class) -public interface KeyBindingAccessor { - @Accessor("timesPressed") - public void setTimesPressed(int timesPressed); - - @Accessor - int getTimesPressed(); -} diff --git a/src/main/java/dev/cigarette/mixin/KeyboardInputMixin.java b/src/main/java/dev/cigarette/mixin/KeyboardInputMixin.java deleted file mode 100644 index 21894dd8..00000000 --- a/src/main/java/dev/cigarette/mixin/KeyboardInputMixin.java +++ /dev/null @@ -1,39 +0,0 @@ -package dev.cigarette.mixin; - -import dev.cigarette.lib.InputOverride; -import net.minecraft.client.input.Input; -import net.minecraft.client.input.KeyboardInput; -import net.minecraft.util.PlayerInput; -import net.minecraft.util.math.Vec2f; -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; - -@Mixin(KeyboardInput.class) -public abstract class KeyboardInputMixin extends Input { - @Shadow - private static float getMovementMultiplier(boolean positive, boolean negative) { - // dummy body - return 0; - } - - @Inject(method = "tick()V", at = @At("HEAD"), cancellable = true) - private void tick(CallbackInfo ci) { - if (!InputOverride.isActive) return; - ci.cancel(); - this.playerInput = new PlayerInput( - InputOverride.forwardKey, - InputOverride.backKey, - InputOverride.leftKey, - InputOverride.rightKey, - InputOverride.jumpKey, - InputOverride.sneakKey, - InputOverride.sprintKey - ); - float f = getMovementMultiplier(this.playerInput.forward(), this.playerInput.backward()); - float g = getMovementMultiplier(this.playerInput.left(), this.playerInput.right()); - this.movementVector = new Vec2f(g, f).normalize(); - } -} diff --git a/src/main/java/dev/cigarette/module/bedwars/AutoBlockIn.java b/src/main/java/dev/cigarette/module/bedwars/AutoBlockIn.java index 1bfe5bf4..d1f25523 100644 --- a/src/main/java/dev/cigarette/module/bedwars/AutoBlockIn.java +++ b/src/main/java/dev/cigarette/module/bedwars/AutoBlockIn.java @@ -5,13 +5,12 @@ import dev.cigarette.gui.widget.KeybindWidget; import dev.cigarette.gui.widget.SliderWidget; import dev.cigarette.gui.widget.ToggleWidget; +import dev.cigarette.helper.KeybindHelper; import dev.cigarette.lib.PlayerEntityL; -import dev.cigarette.mixin.KeyBindingAccessor; import dev.cigarette.module.TickModule; import dev.cigarette.precomputed.BlockIn; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientPlayerEntity; -import net.minecraft.client.option.KeyBinding; import net.minecraft.client.world.ClientWorld; import net.minecraft.item.ItemStack; import net.minecraft.util.math.BlockPos; @@ -31,7 +30,6 @@ public class AutoBlockIn extends TickModule { private final ToggleWidget switchToTool = new ToggleWidget("Switch to Tools", "Automatically switches to a tool once finished.").withDefaultState(true); private final SliderWidget variation = new SliderWidget("Variation", "Applies randomness to the delay between block places.").withBounds(0, 1, 4); - private KeyBinding rightClickKey = null; private boolean running = false; private BlockPos originalPos = null; private float originalYaw = 0; @@ -119,17 +117,8 @@ private void disableAndSwitch(@NotNull ClientPlayerEntity player) { return null; } - private void rightClick() { - KeyBindingAccessor useAccessor = (KeyBindingAccessor) rightClickKey; - useAccessor.setTimesPressed(useAccessor.getTimesPressed() + 1); - } - @Override protected void onEnabledTick(MinecraftClient client, @NotNull ClientWorld world, @NotNull ClientPlayerEntity player) { - if (rightClickKey == null) { - rightClickKey = KeyBinding.byId("key.use"); - return; - } if (!running) { if (!keybind.getKeybind().wasPhysicallyPressed()) return; BlockPos pos = player.getBlockPos(); @@ -156,7 +145,7 @@ protected void onEnabledTick(MinecraftClient client, @NotNull ClientWorld world, previousVector = nextLookVector; PlayerEntityL.setRotationVector(player, nextLookVector); - rightClick(); + KeybindHelper.KEY_USE_ITEM.press(); int rand = variation.getRawState().intValue() > 0 ? (int) (Math.random() * variation.getRawState().intValue()) : 0; cooldownTicks = 16 - speed.getRawState().intValue() + rand; diff --git a/src/main/java/dev/cigarette/module/bedwars/Bridger.java b/src/main/java/dev/cigarette/module/bedwars/Bridger.java index 6d3415b8..4b64ac15 100644 --- a/src/main/java/dev/cigarette/module/bedwars/Bridger.java +++ b/src/main/java/dev/cigarette/module/bedwars/Bridger.java @@ -5,12 +5,10 @@ import dev.cigarette.gui.widget.SliderWidget; import dev.cigarette.gui.widget.TextWidget; import dev.cigarette.gui.widget.ToggleWidget; -import dev.cigarette.lib.InputOverride; -import dev.cigarette.mixin.KeyBindingAccessor; +import dev.cigarette.helper.keybind.InputBlocker; import dev.cigarette.module.TickModule; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientPlayerEntity; -import net.minecraft.client.option.KeyBinding; import net.minecraft.client.world.ClientWorld; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.hit.HitResult; @@ -18,8 +16,12 @@ import net.minecraft.util.math.Direction; import org.jetbrains.annotations.NotNull; +import static dev.cigarette.helper.KeybindHelper.*; + public class Bridger extends TickModule { public static final Bridger INSTANCE = new Bridger("bedwars.bridger", "Bridger", "Automatically bridges."); + public static final InputBlocker INPUT_BLOCKER = new InputBlocker(KEY_JUMP, KEY_MOVE_BACK, KEY_MOVE_LEFT, KEY_MOVE_RIGHT, + KEY_USE_ITEM, KEY_SNEAK).preventCameraChanges(); private final SliderWidget speed = new SliderWidget("Speed", "The higher the speed, the less time spent shifting. To look more legit or improve consistency, lower the speed. Setting to 3 will naturally god bridge straight & diagonally inconsistently.").withBounds(0, 2, 3); private final ToggleWidget blockSwap = new ToggleWidget("Auto Swap Blocks", "Automatically swap to the next available slot with placeable blocks when current stack runs out.").withDefaultState(true); @@ -27,16 +29,8 @@ public class Bridger extends TickModule { private final ToggleWidget toggleDiagonal = new ToggleWidget("Diagonal", "Toggles automatic diagonal bridging.").withDefaultState(true); private final ToggleWidget toggleDiagonalGod = new ToggleWidget("God Bridging", "Toggles diagonal god bridging when positioning yourself half a block from the corner.").withDefaultState(false); - private KeyBinding sneakKey = null; - private KeyBinding backwardsKey = null; - private KeyBinding leftKey = null; - private KeyBinding rightKey = null; - private KeyBinding rightClickKey = null; - private KeyBinding jumpKey = null; private int runningTicks = 0; - private int shiftDiabledTicks = 0; - - protected BridgeType bridgeType = BridgeType.NONE; + private BridgeType bridgingMode = BridgeType.NONE; private Bridger(String id, String name, String tooltip) { super(ToggleWidget::module, id, name, tooltip); @@ -49,14 +43,8 @@ private Bridger(String id, String name, String tooltip) { toggleDiagonalGod.registerConfigKey(id + ".diagonal.god"); } - private boolean isStraightBridge() { - if (!leftKey.isPressed() && !rightKey.isPressed()) return false; - if (leftKey.isPressed() && rightKey.isPressed()) return false; - return true; - } - private float straightBridgeYaw(Direction placingFace) { - boolean right = rightKey.isPressed(); + boolean right = KEY_MOVE_RIGHT.isPhysicallyPressed(); switch (placingFace) { case NORTH -> { return right ? 45f : -45f; @@ -76,10 +64,6 @@ private float straightBridgeYaw(Direction placingFace) { } } - private boolean isDiagonalBridge() { - return !leftKey.isPressed() && !rightKey.isPressed(); - } - private float getBoundedYaw(ClientPlayerEntity player) { float yaw = player.getYaw(); if (yaw < -180) { @@ -105,10 +89,6 @@ private float diagonalBridgeYaw(ClientPlayerEntity player) { return player.getYaw(); } - private boolean isDiagonalGodBridge(BlockPos playerPos, BlockPos blockPos) { - return playerPos.getX() == blockPos.getX() || playerPos.getZ() == blockPos.getZ(); - } - private void cycleIfNoBlocks(ClientPlayerEntity player) { if (!blockSwap.getRawState()) return; if (!BedwarsAgent.isBlock(player.getMainHandStack())) { @@ -119,46 +99,27 @@ private void cycleIfNoBlocks(ClientPlayerEntity player) { } } - private void rightClick(int times) { - KeyBindingAccessor useAccessor = (KeyBindingAccessor) rightClickKey; - useAccessor.setTimesPressed(useAccessor.getTimesPressed() + times); - } - - private void enable(BridgeType type, float yaw) { - this.bridgeType = type; - InputOverride.isActive = true; - InputOverride.pitch = 77.0f; - InputOverride.yaw = yaw; - InputOverride.sneakKey = true; - InputOverride.backKey = true; - InputOverride.leftKey = leftKey.isPressed(); - InputOverride.rightKey = rightKey.isPressed(); - InputOverride.jumpKey = false; + private void enable(@NotNull ClientPlayerEntity player, BridgeType mode, float yaw) { + this.bridgingMode = mode; + tryBlockInputs(this, INPUT_BLOCKER); + player.setPitch(77.0f); + player.setYaw(yaw); + KEY_SNEAK.hold(); } private void disable() { - this.bridgeType = BridgeType.NONE; - InputOverride.isActive = false; + unblock(); } @Override protected void onEnabledTick(MinecraftClient client, @NotNull ClientWorld world, @NotNull ClientPlayerEntity player) { - if (sneakKey == null || backwardsKey == null || leftKey == null || rightKey == null || rightClickKey == null || jumpKey == null) { - this.sneakKey = KeyBinding.byId("key.sneak"); - this.backwardsKey = KeyBinding.byId("key.back"); - this.leftKey = KeyBinding.byId("key.left"); - this.rightKey = KeyBinding.byId("key.right"); - this.rightClickKey = KeyBinding.byId("key.use"); - this.jumpKey = KeyBinding.byId("key.jump"); - return; - } - if (bridgeType == BridgeType.NONE) { - if (!sneakKey.isPressed() || !backwardsKey.isPressed() || !rightClickKey.isPressed()) return; + if (this.bridgingMode == BridgeType.NONE) { + if (!KEY_SNEAK.isPhysicallyPressed() || !KEY_MOVE_BACK.isPhysicallyPressed() || !KEY_USE_ITEM.isPhysicallyPressed()) return; HitResult hitResult = client.crosshairTarget; if (hitResult == null || hitResult.getType() != HitResult.Type.BLOCK) return; - BlockHitResult blockHitResult = (BlockHitResult) hitResult; + BlockHitResult blockHitResult = (BlockHitResult) hitResult; Direction placingFace = blockHitResult.getSide(); if (placingFace == Direction.UP || placingFace == Direction.DOWN) return; @@ -167,16 +128,18 @@ protected void onEnabledTick(MinecraftClient client, @NotNull ClientWorld world, if (playerPos.getY() - blockPos.getY() != 1) return; if (Math.abs(playerPos.getX() - blockPos.getX()) > 1 || Math.abs(playerPos.getZ() - blockPos.getZ()) > 1) return; - if (isStraightBridge()) { - if (!toggleStraight.getRawState()) return; - enable(BridgeType.STRAIGHT, straightBridgeYaw(placingFace)); - } else if (isDiagonalBridge()) { - if (!toggleDiagonal.getRawState()) return; - boolean godBridge = toggleDiagonalGod.getRawState() && isDiagonalGodBridge(playerPos, blockPos); - enable(godBridge ? BridgeType.DIAGONAL_GOD : BridgeType.DIAGONAL, diagonalBridgeYaw(player)); + BridgeType mode = BridgeType.get(blockPos, playerPos, toggleStraight.getRawState(), toggleDiagonal.getRawState(), toggleDiagonalGod.getRawState()); + float yaw = 0; + switch (mode) { + case STRAIGHT -> yaw = straightBridgeYaw(placingFace); + case DIAGONAL, DIAGONAL_GOD -> yaw = diagonalBridgeYaw(player); + case NONE -> throw new IllegalStateException("no bridging mode set"); } + + enable(player, mode, yaw); } else { - if (!sneakKey.isPressed() || !backwardsKey.isPressed() || !rightClickKey.isPressed()) { + if (!KEY_SNEAK.isPhysicallyPressed() || !KEY_MOVE_BACK.isPhysicallyPressed() || !KEY_USE_ITEM.isPhysicallyPressed()) { + bridgingMode = BridgeType.NONE; disable(); return; } @@ -186,57 +149,41 @@ protected void onEnabledTick(MinecraftClient client, @NotNull ClientWorld world, BlockHitResult blockHitResult = (BlockHitResult) hitResult; BlockPos blockPos = blockHitResult.getBlockPos(); - switch (bridgeType) { + boolean facingTop = blockHitResult.getSide() == Direction.UP; + boolean facingSide = !facingTop && blockPos.getY() < player.getY(); + + switch (bridgingMode) { case STRAIGHT -> { - if (!rightKey.isPressed() && !leftKey.isPressed()) { + if (!KEY_MOVE_RIGHT.isPhysicallyPressed() && !KEY_MOVE_LEFT.isPhysicallyPressed()) { disable(); return; } - InputOverride.jumpKey = jumpKey.isPressed(); - InputOverride.sneakKey = shiftDiabledTicks-- <= 0; - - cycleIfNoBlocks(player); - - if (blockHitResult.getSide() == Direction.UP) { - rightClick(1); - } else { - if (blockPos.getY() >= player.getY()) { - disable(); - return; - } - rightClick(1); - shiftDiabledTicks = 2 + speed.getRawState().intValue(); + KEY_JUMP.hold(KEY_JUMP.isPhysicallyPressed()); + KEY_USE_ITEM.press(); + if (facingSide) { + KEY_SNEAK.releaseForTicks(2 + speed.getRawState().intValue()); } } case DIAGONAL -> { - InputOverride.jumpKey = shiftDiabledTicks == 1 && jumpKey.isPressed(); - InputOverride.sneakKey = shiftDiabledTicks-- <= 0; - - if (blockHitResult.getSide() == Direction.UP) { - rightClick(1); - } else { - rightClick(2); - shiftDiabledTicks = 3 + speed.getRawState().intValue(); + KEY_JUMP.hold(KEY_JUMP.isPhysicallyPressed() && KEY_SNEAK.ticksLeft() == 1); + KEY_USE_ITEM.press(); + if (facingSide) { + KEY_USE_ITEM.press(); + KEY_SNEAK.releaseForTicks(3 + speed.getRawState().intValue()); } } case DIAGONAL_GOD -> { - InputOverride.jumpKey = shiftDiabledTicks == 1 && jumpKey.isPressed(); - InputOverride.sneakKey = runningTicks++ == 2; - - if (blockHitResult.getSide() == Direction.UP) { - rightClick(1); - } else { - rightClick(2); + KEY_JUMP.hold(KEY_JUMP.isPhysicallyPressed() && KEY_SNEAK.ticksLeft() == 1); + KEY_SNEAK.hold(runningTicks++ == 2); + KEY_USE_ITEM.press(); + if (facingSide) { + KEY_USE_ITEM.press(); if (runningTicks >= 80) { runningTicks = 0; } } } - case NONE -> { - InputOverride.jumpKey = jumpKey.isPressed(); - InputOverride.sneakKey = sneakKey.isPressed(); - } } cycleIfNoBlocks(player); @@ -251,16 +198,23 @@ public boolean inValidGame() { protected enum BridgeType { NONE(0), STRAIGHT(1), DIAGONAL(2), DIAGONAL_GOD(3); + protected static BridgeType get(BlockPos blockPos, BlockPos playerPos, boolean straight, boolean diagonal, boolean diagonalGod) { + boolean left = KEY_MOVE_LEFT.isPhysicallyPressed(); + boolean right = KEY_MOVE_RIGHT.isPhysicallyPressed(); + if (diagonal && !left && !right) { + if (diagonalGod && (playerPos.getX() == blockPos.getX() || playerPos.getZ() == blockPos.getZ())) { + return BridgeType.DIAGONAL_GOD; + } + return BridgeType.DIAGONAL; + } + if (straight && left != right) return BridgeType.STRAIGHT; + return BridgeType.NONE; + } + private final int id; BridgeType(int id) { this.id = id; } - - /* - public int getId() { - return this.id; - } - */ } -} \ No newline at end of file +} diff --git a/src/main/java/dev/cigarette/module/combat/AutoClicker.java b/src/main/java/dev/cigarette/module/combat/AutoClicker.java index 87f27547..260c508b 100644 --- a/src/main/java/dev/cigarette/module/combat/AutoClicker.java +++ b/src/main/java/dev/cigarette/module/combat/AutoClicker.java @@ -2,11 +2,10 @@ import dev.cigarette.gui.widget.SliderWidget; import dev.cigarette.gui.widget.ToggleWidget; -import dev.cigarette.mixin.KeyBindingAccessor; +import dev.cigarette.helper.KeybindHelper; import dev.cigarette.module.TickModule; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientPlayerEntity; -import net.minecraft.client.option.KeyBinding; import net.minecraft.client.world.ClientWorld; import net.minecraft.util.hit.HitResult; import org.jetbrains.annotations.NotNull; @@ -26,12 +25,10 @@ private AutoClicker(String id, String name, String tooltip) { protected void onEnabledTick(MinecraftClient client, @NotNull ClientWorld world, @NotNull ClientPlayerEntity player) { client.attackCooldown = 0; HitResult hitResult = client.crosshairTarget; - KeyBinding attackKey = KeyBinding.byId("key.attack"); - KeyBindingAccessor attackKeyAccessor = (KeyBindingAccessor) attackKey; - if (hitResult == null || attackKey == null || !attackKey.isPressed()) return; + if (hitResult == null || !KeybindHelper.KEY_ATTACK.isPhysicallyPressed()) return; if (Math.random() > clickPercent.getRawState()) return; if (hitResult.getType() != HitResult.Type.BLOCK) { - attackKeyAccessor.setTimesPressed(attackKeyAccessor.getTimesPressed() + 1); + KeybindHelper.KEY_ATTACK.press(); } } diff --git a/src/main/java/dev/cigarette/module/combat/PerfectHit.java b/src/main/java/dev/cigarette/module/combat/PerfectHit.java index fa04bbfc..a14a06d1 100644 --- a/src/main/java/dev/cigarette/module/combat/PerfectHit.java +++ b/src/main/java/dev/cigarette/module/combat/PerfectHit.java @@ -2,11 +2,10 @@ import dev.cigarette.gui.widget.SliderWidget; import dev.cigarette.gui.widget.ToggleWidget; -import dev.cigarette.mixin.KeyBindingAccessor; +import dev.cigarette.helper.KeybindHelper; import dev.cigarette.module.TickModule; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientPlayerEntity; -import net.minecraft.client.option.KeyBinding; import net.minecraft.client.world.ClientWorld; import net.minecraft.entity.Entity; import net.minecraft.entity.LivingEntity; @@ -30,16 +29,14 @@ private PerfectHit(String id, String name, String tooltip) { protected void onEnabledTick(MinecraftClient client, @NotNull ClientWorld world, @NotNull ClientPlayerEntity player) { client.attackCooldown = 0; HitResult hitResult = client.crosshairTarget; - KeyBinding attackKey = KeyBinding.byId("key.attack"); - KeyBindingAccessor attackKeyAccessor = (KeyBindingAccessor) attackKey; - if (hitResult == null || attackKey == null || !attackKey.isPressed()) return; + if (hitResult == null || !KeybindHelper.KEY_ATTACK.isPhysicallyPressed()) return; if (hitResult.getType() == HitResult.Type.ENTITY) { EntityHitResult entityHitResult = (EntityHitResult) hitResult; Entity entity = entityHitResult.getEntity(); if (!(entity instanceof LivingEntity livingEntity)) return; if (livingEntity.hurtTime > 1) return; if (Math.random() > clickPercent.getRawState()) return; - attackKeyAccessor.setTimesPressed(attackKeyAccessor.getTimesPressed() + 1); + KeybindHelper.KEY_ATTACK.press(); } } diff --git a/src/main/resources/cigarette.mixins.json b/src/main/resources/cigarette.mixins.json index b88ff572..a01f8ee0 100644 --- a/src/main/resources/cigarette.mixins.json +++ b/src/main/resources/cigarette.mixins.json @@ -6,7 +6,6 @@ "BedBlockEntityMixin", "ClientWorldAccessor", "EntityMixin", - "KeyBindingAccessor", "MinecraftClientInvoker", "PlayerEntityMixin", "PropertyMixin", @@ -16,7 +15,6 @@ "defaultRequire": 1 }, "client": [ - "KeyboardInputMixin", "KeyboardMixin", "MouseMixin" ] From 9bfd16eaf878e0ab7cc508a0f1275c9e5f9943e3 Mon Sep 17 00:00:00 2001 From: UndercoverGoose <53491740+UndercoverGoose@users.noreply.github.com> Date: Wed, 8 Oct 2025 11:10:30 -0400 Subject: [PATCH 33/37] fix: virtual keybinds trigger inside of GUIs --- src/main/java/dev/cigarette/mixin/KeyboardMixin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/dev/cigarette/mixin/KeyboardMixin.java b/src/main/java/dev/cigarette/mixin/KeyboardMixin.java index 382ea92b..98aba9b1 100644 --- a/src/main/java/dev/cigarette/mixin/KeyboardMixin.java +++ b/src/main/java/dev/cigarette/mixin/KeyboardMixin.java @@ -17,7 +17,7 @@ private void onKey(long window, int key, int scancode, int action, int modifiers ci.cancel(); return; } - if (KeybindHelper.handleKeyByGUI(client, key, scancode, action, modifiers) || KeybindHelper.handleBlockedKeyInputs(client, key, scancode, action, modifiers) || KeybindHelper.handleCustomKeys(client, key, scancode, action, modifiers)) { + if (client.currentScreen == null && (KeybindHelper.handleKeyByGUI(client, key, scancode, action, modifiers) || KeybindHelper.handleBlockedKeyInputs(client, key, scancode, action, modifiers) || KeybindHelper.handleCustomKeys(client, key, scancode, action, modifiers))) { ci.cancel(); return; } From cb1bcd5203b5f91b534ab45471a9dcc5eabfefeb Mon Sep 17 00:00:00 2001 From: UndercoverGoose <53491740+UndercoverGoose@users.noreply.github.com> Date: Thu, 9 Oct 2025 20:21:30 -0400 Subject: [PATCH 34/37] fix crash when attempting to bridge on a mode that is disabled --- src/main/java/dev/cigarette/module/bedwars/Bridger.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/dev/cigarette/module/bedwars/Bridger.java b/src/main/java/dev/cigarette/module/bedwars/Bridger.java index 4b64ac15..41e772b1 100644 --- a/src/main/java/dev/cigarette/module/bedwars/Bridger.java +++ b/src/main/java/dev/cigarette/module/bedwars/Bridger.java @@ -133,10 +133,10 @@ protected void onEnabledTick(MinecraftClient client, @NotNull ClientWorld world, switch (mode) { case STRAIGHT -> yaw = straightBridgeYaw(placingFace); case DIAGONAL, DIAGONAL_GOD -> yaw = diagonalBridgeYaw(player); - case NONE -> throw new IllegalStateException("no bridging mode set"); } - - enable(player, mode, yaw); + if (mode != BridgeType.NONE) { + enable(player, mode, yaw); + } } else { if (!KEY_SNEAK.isPhysicallyPressed() || !KEY_MOVE_BACK.isPhysicallyPressed() || !KEY_USE_ITEM.isPhysicallyPressed()) { bridgingMode = BridgeType.NONE; From f10b0228c572839ec73166e1556c93e827dcee92 Mon Sep 17 00:00:00 2001 From: UndercoverGoose <53491740+UndercoverGoose@users.noreply.github.com> Date: Thu, 9 Oct 2025 20:29:23 -0400 Subject: [PATCH 35/37] remove restriction on keys that can be bound --- src/main/java/dev/cigarette/gui/widget/KeybindWidget.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/dev/cigarette/gui/widget/KeybindWidget.java b/src/main/java/dev/cigarette/gui/widget/KeybindWidget.java index 0d67847d..cfa5a6e2 100644 --- a/src/main/java/dev/cigarette/gui/widget/KeybindWidget.java +++ b/src/main/java/dev/cigarette/gui/widget/KeybindWidget.java @@ -89,9 +89,6 @@ public boolean keyPressed(int keyCode, int scanCode, int modifiers) { if (keyCode == GLFW.GLFW_KEY_ESCAPE || keyCode == GLFW.GLFW_KEY_RIGHT_SHIFT) { this.setBoundKey(GLFW.GLFW_KEY_UNKNOWN); } else { - InputUtil.Key key = InputUtil.fromKeyCode(keyCode, scanCode); - String keyName = key.getLocalizedText().getLiteralString(); - if (keyName == null) return true; this.setBoundKey(keyCode); } clearBinding(); From 2ddda7463ab19a24090f19e65795224a369872e0 Mon Sep 17 00:00:00 2001 From: UndercoverGoose <53491740+UndercoverGoose@users.noreply.github.com> Date: Thu, 9 Oct 2025 20:29:37 -0400 Subject: [PATCH 36/37] fix virtual keybinds queueing events when modules are disabled --- .../dev/cigarette/helper/KeybindHelper.java | 27 ++++++++++++------- .../helper/keybind/VirtualKeybind.java | 7 +++++ 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/main/java/dev/cigarette/helper/KeybindHelper.java b/src/main/java/dev/cigarette/helper/KeybindHelper.java index b14ca720..9b600260 100644 --- a/src/main/java/dev/cigarette/helper/KeybindHelper.java +++ b/src/main/java/dev/cigarette/helper/KeybindHelper.java @@ -5,6 +5,7 @@ import dev.cigarette.helper.keybind.InputBlocker; import dev.cigarette.helper.keybind.MinecraftKeybind; import dev.cigarette.helper.keybind.VirtualKeybind; +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.minecraft.client.MinecraftClient; import net.minecraft.client.option.KeyBinding; import net.minecraft.client.util.InputUtil; @@ -44,6 +45,16 @@ public class KeybindHelper { */ private static final HashSet wrappedBindings = new HashSet<>(); + /** + * Keybind to toggle {@code CigaretteScreen}. + */ + public static final VirtualKeybind KEY_TOGGLE_GUI = new VirtualKeybind(GLFW.GLFW_KEY_RIGHT_SHIFT); + + /** + * Set of custom keybinds that can be triggered. + */ + private static final HashSet customBinds = new HashSet<>(); + static { wrappedBindings.add(KEY_SPRINT); wrappedBindings.add(KEY_SNEAK); @@ -66,17 +77,13 @@ public class KeybindHelper { wrappedBindings.add(KEY_SLOT_7); wrappedBindings.add(KEY_SLOT_8); wrappedBindings.add(KEY_SLOT_9); - } - /** - * Keybind to toggle {@code CigaretteScreen}. - */ - public static final VirtualKeybind KEY_TOGGLE_GUI = new VirtualKeybind(GLFW.GLFW_KEY_RIGHT_SHIFT); - - /** - * Set of custom keybinds that can be triggered. - */ - private static final HashSet customBinds = new HashSet<>(); + ClientTickEvents.END_CLIENT_TICK.register(client -> { + for (VirtualKeybind bind : customBinds) { + bind.unset(); + } + }); + } /** * The module that is blocking inputs. diff --git a/src/main/java/dev/cigarette/helper/keybind/VirtualKeybind.java b/src/main/java/dev/cigarette/helper/keybind/VirtualKeybind.java index ff149415..17d75f13 100644 --- a/src/main/java/dev/cigarette/helper/keybind/VirtualKeybind.java +++ b/src/main/java/dev/cigarette/helper/keybind/VirtualKeybind.java @@ -123,4 +123,11 @@ public boolean isOf(int key, int scancode) { public boolean isOfMouse(int button) { return this.isMouse && this.currentKey == button; } + + /** + * Resets the {@link #timesPressed} property. Should be triggered at the end of every client tick to prevent queueing of events. + */ + public void unset() { + this.timesPressed = 0; + } } From e12e133855aa9837af345336b29b440ebb54f824 Mon Sep 17 00:00:00 2001 From: UndercoverGoose <53491740+UndercoverGoose@users.noreply.github.com> Date: Thu, 9 Oct 2025 21:28:49 -0400 Subject: [PATCH 37/37] fix: mouse events duplicate when in GUIs --- src/main/java/dev/cigarette/mixin/MouseMixin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/dev/cigarette/mixin/MouseMixin.java b/src/main/java/dev/cigarette/mixin/MouseMixin.java index 203b4c1e..52409a3e 100644 --- a/src/main/java/dev/cigarette/mixin/MouseMixin.java +++ b/src/main/java/dev/cigarette/mixin/MouseMixin.java @@ -23,7 +23,7 @@ private void onMouseButton(long window, int button, int action, int mods, Callba ci.cancel(); return; } - if (KeybindHelper.handleBlockedMouseInputs(client, button, action, mods) || KeybindHelper.handleCustomMouse(client, button, action, mods)) { + if (client.currentScreen == null && (KeybindHelper.handleBlockedMouseInputs(client, button, action, mods) || KeybindHelper.handleCustomMouse(client, button, action, mods))) { ci.cancel(); return; }