diff --git a/build.gradle.kts b/build.gradle.kts index 2582080..a587424 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -13,7 +13,7 @@ plugins { } group = "dev.isxander" -version = "1.0.0+1.19.4" +version = "0.1.0+1.19.4" repositories { mavenCentral() diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f462a88..b761d51 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,12 +7,12 @@ github_release = "2.+" machete = "1.+" grgit = "5.0.+" -minecraft = "23w05a" -quilt_mappings = "1" +minecraft = "23w06a" +quilt_mappings = "4" fabric_loader = "0.14.14" -fabric_api = "0.73.4+1.19.4" +fabric_api = "0.73.5+1.19.4" mixin_extras = "0.2.0-beta.1" -yet_another_config_lib = "2.2.0+update.1.19.4-SNAPSHOT" +yet_another_config_lib = "2.3.0+beta.2+update.1.19.4-SNAPSHOT" mod_menu = "6.0.0-beta.1" hid4java = "0.7.0" diff --git a/src/main/java/dev/isxander/controlify/Controlify.java b/src/main/java/dev/isxander/controlify/Controlify.java index 55ae038..45f6575 100644 --- a/src/main/java/dev/isxander/controlify/Controlify.java +++ b/src/main/java/dev/isxander/controlify/Controlify.java @@ -151,7 +151,7 @@ public class Controlify { var minecraft = Minecraft.getInstance(); if (!minecraft.mouseHandler.isMouseGrabbed()) - hideMouse(currentInputMode == InputMode.CONTROLLER); + hideMouse(currentInputMode == InputMode.CONTROLLER, true); if (minecraft.screen != null) { ScreenProcessorProvider.provide(minecraft.screen).onInputModeChanged(currentInputMode); } @@ -159,7 +159,7 @@ public class Controlify { ControlifyEvents.INPUT_MODE_CHANGED.invoker().onInputModeChanged(currentInputMode); } - public void hideMouse(boolean hide) { + public void hideMouse(boolean hide, boolean moveMouse) { var minecraft = Minecraft.getInstance(); GLFW.glfwSetInputMode( minecraft.getWindow().getWindow(), @@ -170,7 +170,7 @@ public class Controlify { ); if (minecraft.screen != null) { var mouseHandlerAccessor = (MouseHandlerAccessor) minecraft.mouseHandler; - if (hide && !virtualMouseHandler().isVirtualMouseEnabled()) { + if (hide && !virtualMouseHandler().isVirtualMouseEnabled() && moveMouse) { // stop mouse hovering over last element before hiding cursor but don't actually move it // so when the user switches back to mouse it will be in the same place mouseHandlerAccessor.invokeOnMove(minecraft.getWindow().getWindow(), -50, -50); diff --git a/src/main/java/dev/isxander/controlify/bindings/ControllerBinding.java b/src/main/java/dev/isxander/controlify/bindings/ControllerBinding.java index 9c0d085..4f1e7c8 100644 --- a/src/main/java/dev/isxander/controlify/bindings/ControllerBinding.java +++ b/src/main/java/dev/isxander/controlify/bindings/ControllerBinding.java @@ -11,6 +11,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.function.BooleanSupplier; public class ControllerBinding { private final Controller controller; @@ -18,18 +19,22 @@ public class ControllerBinding { private final IBind defaultBind; private final ResourceLocation id; private final Component name, description; - private final KeyMapping override; + private final KeyMappingOverride override; private static final Map> pressedBinds = new HashMap<>(); - public ControllerBinding(Controller controller, IBind defaultBind, ResourceLocation id, KeyMapping override) { + public ControllerBinding(Controller controller, IBind defaultBind, ResourceLocation id, KeyMapping override, BooleanSupplier toggleOverride) { this.controller = controller; this.bind = this.defaultBind = defaultBind; this.id = id; this.name = Component.translatable("controlify.binding." + id.getNamespace() + "." + id.getPath()); var descKey = "controlify.binding." + id.getNamespace() + "." + id.getPath() + ".desc"; this.description = Language.getInstance().has(descKey) ? Component.translatable(descKey) : Component.empty(); - this.override = override; + this.override = override != null ? new KeyMappingOverride(override, toggleOverride) : null; + } + + public ControllerBinding(Controller controller, IBind defaultBind, ResourceLocation id) { + this(controller, defaultBind, id, null, () -> false); } public float state() { @@ -86,7 +91,7 @@ public class ControllerBinding { return description; } - public KeyMapping override() { + public KeyMappingOverride override() { return override; } @@ -114,4 +119,7 @@ public class ControllerBinding { return Set.of((Bind) bind); } } + + public record KeyMappingOverride(KeyMapping keyMapping, BooleanSupplier toggleable) { + } } diff --git a/src/main/java/dev/isxander/controlify/bindings/ControllerBindings.java b/src/main/java/dev/isxander/controlify/bindings/ControllerBindings.java index 97771f3..f41b244 100644 --- a/src/main/java/dev/isxander/controlify/bindings/ControllerBindings.java +++ b/src/main/java/dev/isxander/controlify/bindings/ControllerBindings.java @@ -26,45 +26,50 @@ public class ControllerBindings { OPEN_CHAT, GUI_PRESS, GUI_BACK, GUI_NEXT_TAB, GUI_PREV_TAB, - VMOUSE_LCLICK, VMOUSE_RCLICK, VMOUSE_MCLICK, VMOUSE_ESCAPE, VMOUSE_SHIFT, VMOUSE_TOGGLE, - TOGGLE_DEBUG_MENU; + VMOUSE_LCLICK, VMOUSE_RCLICK, VMOUSE_MCLICK, VMOUSE_SCROLL_UP, VMOUSE_SCROLL_DOWN, VMOUSE_ESCAPE, VMOUSE_SHIFT, VMOUSE_TOGGLE, + PICK_BLOCK; private final Map registry = new LinkedHashMap<>(); + private final Controller controller; + public ControllerBindings(Controller controller) { + this.controller = controller; var options = Minecraft.getInstance().options; - register(WALK_FORWARD = new ControllerBinding(controller, Bind.LEFT_STICK_FORWARD, new ResourceLocation("controlify", "walk_forward"), null)); - register(WALK_BACKWARD = new ControllerBinding(controller, Bind.LEFT_STICK_BACKWARD, new ResourceLocation("controlify", "walk_backward"), null)); - register(WALK_LEFT = new ControllerBinding(controller, Bind.LEFT_STICK_LEFT, new ResourceLocation("controlify", "strafe_left"), null)); - register(WALK_RIGHT = new ControllerBinding(controller, Bind.LEFT_STICK_RIGHT, new ResourceLocation("controlify", "strafe_right"), null)); - register(JUMP = new ControllerBinding(controller, Bind.A_BUTTON, new ResourceLocation("controlify", "jump"), options.keyJump)); - register(SNEAK = new ControllerBinding(controller, Bind.RIGHT_STICK_PRESS, new ResourceLocation("controlify", "sneak"), options.keyShift)); - register(ATTACK = new ControllerBinding(controller, Bind.RIGHT_TRIGGER, new ResourceLocation("controlify", "attack"), options.keyAttack)); - register(USE = new ControllerBinding(controller, Bind.LEFT_TRIGGER, new ResourceLocation("controlify", "use"), options.keyUse)); - register(SPRINT = new ControllerBinding(controller, Bind.LEFT_STICK_PRESS, new ResourceLocation("controlify", "sprint"), options.keySprint)); - register(DROP = new ControllerBinding(controller, Bind.DPAD_DOWN, new ResourceLocation("controlify", "drop"), options.keyDrop)); - register(NEXT_SLOT = new ControllerBinding(controller, Bind.RIGHT_BUMPER, new ResourceLocation("controlify", "next_slot"), null)); - register(PREV_SLOT = new ControllerBinding(controller, Bind.LEFT_BUMPER, new ResourceLocation("controlify", "prev_slot"), null)); - register(PAUSE = new ControllerBinding(controller, Bind.START, new ResourceLocation("controlify", "pause"), null)); - register(INVENTORY = new ControllerBinding(controller, Bind.Y_BUTTON, new ResourceLocation("controlify", "inventory"), options.keyInventory)); - register(CHANGE_PERSPECTIVE = new ControllerBinding(controller, Bind.BACK, new ResourceLocation("controlify", "change_perspective"), options.keyTogglePerspective)); - register(OPEN_CHAT = new ControllerBinding(controller, Bind.DPAD_UP, new ResourceLocation("controlify", "open_chat"), options.keyChat)); - register(GUI_PRESS = new ControllerBinding(controller, Bind.A_BUTTON, new ResourceLocation("controlify", "gui_press"), null)); - register(GUI_BACK = new ControllerBinding(controller, Bind.B_BUTTON, new ResourceLocation("controlify", "gui_back"), null)); - register(GUI_NEXT_TAB = new ControllerBinding(controller, Bind.RIGHT_BUMPER, new ResourceLocation("controlify", "gui_next_tab"), null)); - register(GUI_PREV_TAB = new ControllerBinding(controller, Bind.LEFT_BUMPER, new ResourceLocation("controlify", "gui_prev_tab"), null)); - register(VMOUSE_LCLICK = new ControllerBinding(controller, Bind.A_BUTTON, new ResourceLocation("controlify", "vmouse_lclick"), null)); - register(VMOUSE_RCLICK = new ControllerBinding(controller, Bind.X_BUTTON, new ResourceLocation("controlify", "vmouse_rclick"), null)); - register(VMOUSE_MCLICK = new ControllerBinding(controller, Bind.Y_BUTTON, new ResourceLocation("controlify", "vmouse_mclick"), null)); - register(VMOUSE_ESCAPE = new ControllerBinding(controller, Bind.B_BUTTON, new ResourceLocation("controlify", "vmouse_escape"), null)); - register(VMOUSE_SHIFT = new ControllerBinding(controller, Bind.LEFT_STICK_PRESS, new ResourceLocation("controlify", "vmouse_shift"), null)); - register(VMOUSE_TOGGLE = new ControllerBinding(controller, Bind.BACK, new ResourceLocation("controlify", "vmouse_toggle"), null)); - register(TOGGLE_DEBUG_MENU = new ControllerBinding(controller, new CompoundBind(Bind.BACK, Bind.START), new ResourceLocation("controlify", "toggle_debug_menu"), null)); + register(WALK_FORWARD = new ControllerBinding(controller, Bind.LEFT_STICK_FORWARD, new ResourceLocation("controlify", "walk_forward"))); + register(WALK_BACKWARD = new ControllerBinding(controller, Bind.LEFT_STICK_BACKWARD, new ResourceLocation("controlify", "walk_backward"))); + register(WALK_LEFT = new ControllerBinding(controller, Bind.LEFT_STICK_LEFT, new ResourceLocation("controlify", "strafe_left"))); + register(WALK_RIGHT = new ControllerBinding(controller, Bind.LEFT_STICK_RIGHT, new ResourceLocation("controlify", "strafe_right"))); + register(JUMP = new ControllerBinding(controller, Bind.A_BUTTON, new ResourceLocation("controlify", "jump"), options.keyJump, () -> false)); + register(SNEAK = new ControllerBinding(controller, Bind.RIGHT_STICK_PRESS, new ResourceLocation("controlify", "sneak"), options.keyShift, () -> controller.config().toggleSneak)); + register(ATTACK = new ControllerBinding(controller, Bind.RIGHT_TRIGGER, new ResourceLocation("controlify", "attack"), options.keyAttack, () -> false)); + register(USE = new ControllerBinding(controller, Bind.LEFT_TRIGGER, new ResourceLocation("controlify", "use"), options.keyUse, () -> false)); + register(SPRINT = new ControllerBinding(controller, Bind.LEFT_STICK_PRESS, new ResourceLocation("controlify", "sprint"), options.keySprint, () -> controller.config().toggleSprint)); + register(DROP = new ControllerBinding(controller, Bind.DPAD_DOWN, new ResourceLocation("controlify", "drop"), options.keyDrop, () -> false)); + register(NEXT_SLOT = new ControllerBinding(controller, Bind.RIGHT_BUMPER, new ResourceLocation("controlify", "next_slot"))); + register(PREV_SLOT = new ControllerBinding(controller, Bind.LEFT_BUMPER, new ResourceLocation("controlify", "prev_slot"))); + register(PAUSE = new ControllerBinding(controller, Bind.START, new ResourceLocation("controlify", "pause"))); + register(INVENTORY = new ControllerBinding(controller, Bind.Y_BUTTON, new ResourceLocation("controlify", "inventory"), options.keyInventory, () -> false)); + register(CHANGE_PERSPECTIVE = new ControllerBinding(controller, Bind.BACK, new ResourceLocation("controlify", "change_perspective"), options.keyTogglePerspective, () -> false)); + register(OPEN_CHAT = new ControllerBinding(controller, Bind.DPAD_UP, new ResourceLocation("controlify", "open_chat"), options.keyChat, () -> false)); + register(GUI_PRESS = new ControllerBinding(controller, Bind.A_BUTTON, new ResourceLocation("controlify", "gui_press"))); + register(GUI_BACK = new ControllerBinding(controller, Bind.B_BUTTON, new ResourceLocation("controlify", "gui_back"))); + register(GUI_NEXT_TAB = new ControllerBinding(controller, Bind.RIGHT_BUMPER, new ResourceLocation("controlify", "gui_next_tab"))); + register(GUI_PREV_TAB = new ControllerBinding(controller, Bind.LEFT_BUMPER, new ResourceLocation("controlify", "gui_prev_tab"))); + register(VMOUSE_LCLICK = new ControllerBinding(controller, Bind.A_BUTTON, new ResourceLocation("controlify", "vmouse_lclick"))); + register(VMOUSE_RCLICK = new ControllerBinding(controller, Bind.X_BUTTON, new ResourceLocation("controlify", "vmouse_rclick"))); + register(VMOUSE_MCLICK = new ControllerBinding(controller, Bind.Y_BUTTON, new ResourceLocation("controlify", "vmouse_mclick"))); + register(VMOUSE_SCROLL_UP = new ControllerBinding(controller, Bind.RIGHT_STICK_FORWARD, new ResourceLocation("controlify", "vmouse_scroll_up"))); + register(VMOUSE_SCROLL_DOWN = new ControllerBinding(controller, Bind.RIGHT_STICK_BACKWARD, new ResourceLocation("controlify", "vmouse_scroll_down"))); + register(VMOUSE_ESCAPE = new ControllerBinding(controller, Bind.B_BUTTON, new ResourceLocation("controlify", "vmouse_escape"))); + register(VMOUSE_SHIFT = new ControllerBinding(controller, Bind.LEFT_STICK_PRESS, new ResourceLocation("controlify", "vmouse_shift"))); + register(VMOUSE_TOGGLE = new ControllerBinding(controller, Bind.BACK, new ResourceLocation("controlify", "vmouse_toggle"))); + register(PICK_BLOCK = new ControllerBinding(controller, Bind.DPAD_LEFT, new ResourceLocation("controlify", "pick_block"), options.keyPickItem, () -> false)); ControlifyEvents.CONTROLLER_BIND_REGISTRY.invoker().onRegisterControllerBinds(this, controller); - ControlifyEvents.CONTROLLER_STATE_UPDATED.register(this::imitateVanillaClick); + ControlifyEvents.CONTROLLER_STATE_UPDATED.register(this::onControllerUpdate); ControlifyEvents.INPUT_MODE_CHANGED.register(mode -> KeyMapping.releaseAll()); } @@ -97,7 +102,13 @@ public class ControllerBindings { } } - private void imitateVanillaClick(Controller controller) { + public void onControllerUpdate(Controller controller) { + if (controller != this.controller) return; + + imitateVanillaClick(); + } + + private void imitateVanillaClick() { ControllerBinding.clearPressedBinds(controller); if (Controlify.instance().currentInputMode() != InputMode.CONTROLLER) @@ -106,12 +117,20 @@ public class ControllerBindings { return; for (var binding : registry().values()) { - KeyMapping vanillaKey = binding.override(); - if (vanillaKey == null) continue; + var override = binding.override(); + if (override == null) continue; - var vanillaKeyCode = ((KeyMappingAccessor) vanillaKey).getKey(); + var accessor = (KeyMappingAccessor) override.keyMapping(); + var vanillaKeyCode = accessor.getKey(); - KeyMapping.set(vanillaKeyCode, binding.held()); + if (override.toggleable().getAsBoolean()) { + if (binding.justPressed()) { + // must set field directly to avoid ToggleKeyMapping breaking things + accessor.setIsDown(!accessor.getIsDown()); + } + } else { + KeyMapping.set(vanillaKeyCode, binding.held()); + } if (binding.justPressed()) KeyMapping.click(vanillaKeyCode); } } diff --git a/src/main/java/dev/isxander/controlify/compatibility/screen/ScreenProcessor.java b/src/main/java/dev/isxander/controlify/compatibility/screen/ScreenProcessor.java index 247594b..8c814c9 100644 --- a/src/main/java/dev/isxander/controlify/compatibility/screen/ScreenProcessor.java +++ b/src/main/java/dev/isxander/controlify/compatibility/screen/ScreenProcessor.java @@ -19,7 +19,7 @@ import java.util.*; public class ScreenProcessor { public final T screen; - private int lastMoved = 0; + protected int lastMoved = 0; public ScreenProcessor(T screen) { this.screen = screen; @@ -51,6 +51,7 @@ public class ScreenProcessor { setInitialFocus(); var focusTree = getFocusTree(); + var focuses = List.copyOf(focusTree); while (!focusTree.isEmpty()) { var focused = focusTree.poll(); var processor = ComponentProcessorProvider.provide(focused); @@ -89,8 +90,12 @@ public class ScreenProcessor { ComponentPath path = screen.nextFocusPath(event); if (path != null) { accessor.invokeChangeFocus(path); - ComponentProcessorProvider.provide(path.component()).onNavigateTo(this, controller); lastMoved = 0; + + var newFocusTree = getFocusTree(); + while (!newFocusTree.isEmpty() && !focuses.contains(newFocusTree.peek())) { + ComponentProcessorProvider.provide(newFocusTree.poll()).onFocusGained(this, controller); + } } } } diff --git a/src/main/java/dev/isxander/controlify/compatibility/screen/component/ComponentProcessor.java b/src/main/java/dev/isxander/controlify/compatibility/screen/component/ComponentProcessor.java index 6bf3f3c..6230bea 100644 --- a/src/main/java/dev/isxander/controlify/compatibility/screen/component/ComponentProcessor.java +++ b/src/main/java/dev/isxander/controlify/compatibility/screen/component/ComponentProcessor.java @@ -1,11 +1,7 @@ package dev.isxander.controlify.compatibility.screen.component; import dev.isxander.controlify.compatibility.screen.ScreenProcessor; -import dev.isxander.controlify.controller.AxesState; -import dev.isxander.controlify.controller.ButtonState; import dev.isxander.controlify.controller.Controller; -import dev.isxander.controlify.controller.ControllerState; -import net.minecraft.client.gui.components.events.GuiEventListener; public interface ComponentProcessor { ComponentProcessor EMPTY = new ComponentProcessor(){}; @@ -18,6 +14,6 @@ public interface ComponentProcessor { return false; } - default void onNavigateTo(ScreenProcessor screen, Controller controller) { + default void onFocusGained(ScreenProcessor screen, Controller controller) { } } diff --git a/src/main/java/dev/isxander/controlify/compatibility/vanilla/AbstractButtonComponentProcessor.java b/src/main/java/dev/isxander/controlify/compatibility/vanilla/AbstractButtonComponentProcessor.java new file mode 100644 index 0000000..e6beea0 --- /dev/null +++ b/src/main/java/dev/isxander/controlify/compatibility/vanilla/AbstractButtonComponentProcessor.java @@ -0,0 +1,26 @@ +package dev.isxander.controlify.compatibility.vanilla; + +import dev.isxander.controlify.compatibility.screen.ScreenProcessor; +import dev.isxander.controlify.compatibility.screen.component.ComponentProcessor; +import dev.isxander.controlify.controller.Controller; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.components.AbstractButton; + +public class AbstractButtonComponentProcessor implements ComponentProcessor { + private final AbstractButton button; + + public AbstractButtonComponentProcessor(AbstractButton button) { + this.button = button; + } + + @Override + public boolean overrideControllerButtons(ScreenProcessor screen, Controller controller) { + if (controller.bindings().GUI_PRESS.justPressed()) { + button.playDownSound(Minecraft.getInstance().getSoundManager()); + button.onPress(); + return true; + } + + return false; + } +} diff --git a/src/main/java/dev/isxander/controlify/compatibility/vanilla/SliderComponentProcessor.java b/src/main/java/dev/isxander/controlify/compatibility/vanilla/SliderComponentProcessor.java index d0ba925..6f46aea 100644 --- a/src/main/java/dev/isxander/controlify/compatibility/vanilla/SliderComponentProcessor.java +++ b/src/main/java/dev/isxander/controlify/compatibility/vanilla/SliderComponentProcessor.java @@ -64,7 +64,7 @@ public class SliderComponentProcessor implements ComponentProcessor { } @Override - public void onNavigateTo(ScreenProcessor screen, Controller controller) { + public void onFocusGained(ScreenProcessor screen, Controller controller) { System.out.println("navigated!"); this.canChangeValueSetter.accept(false); } diff --git a/src/main/java/dev/isxander/controlify/compatibility/yacl/CyclingControllerElementComponentProcessor.java b/src/main/java/dev/isxander/controlify/compatibility/yacl/CyclingControllerElementComponentProcessor.java new file mode 100644 index 0000000..f232e46 --- /dev/null +++ b/src/main/java/dev/isxander/controlify/compatibility/yacl/CyclingControllerElementComponentProcessor.java @@ -0,0 +1,33 @@ +package dev.isxander.controlify.compatibility.yacl; + +import dev.isxander.controlify.compatibility.screen.ScreenProcessor; +import dev.isxander.controlify.compatibility.screen.component.ComponentProcessor; +import dev.isxander.controlify.controller.Controller; +import dev.isxander.yacl.gui.controllers.cycling.CyclingControllerElement; + +public class CyclingControllerElementComponentProcessor implements ComponentProcessor { + private final CyclingControllerElement cyclingController; + private int lastInput = 0; + + public CyclingControllerElementComponentProcessor(CyclingControllerElement cyclingController) { + this.cyclingController = cyclingController; + } + + @Override + public boolean overrideControllerNavigation(ScreenProcessor screen, Controller controller) { + var rightStickX = controller.state().axes().rightStickX(); + var rightStickY = controller.state().axes().rightStickY(); + var input = Math.abs(rightStickX) > Math.abs(rightStickY) ? rightStickX : rightStickY; + + var inputI = Math.abs(input) < controller.config().buttonActivationThreshold ? 0 : input > 0 ? 1 : -1; + if (inputI != 0 && inputI != lastInput) { + cyclingController.cycleValue(input > 0 ? 1 : -1); + + lastInput = inputI; + return true; + } + lastInput = inputI; + + return false; + } +} diff --git a/src/main/java/dev/isxander/controlify/compatibility/yacl/SliderControllerElementComponentProcessor.java b/src/main/java/dev/isxander/controlify/compatibility/yacl/SliderControllerElementComponentProcessor.java new file mode 100644 index 0000000..beb21be --- /dev/null +++ b/src/main/java/dev/isxander/controlify/compatibility/yacl/SliderControllerElementComponentProcessor.java @@ -0,0 +1,37 @@ +package dev.isxander.controlify.compatibility.yacl; + +import dev.isxander.controlify.compatibility.screen.ScreenProcessor; +import dev.isxander.controlify.compatibility.screen.component.ComponentProcessor; +import dev.isxander.controlify.controller.Controller; +import dev.isxander.yacl.gui.controllers.slider.SliderControllerElement; + +public class SliderControllerElementComponentProcessor implements ComponentProcessor { + private final SliderControllerElement slider; + private int ticksSinceIncrement = 0; + private int lastInput = 0; + + public SliderControllerElementComponentProcessor(SliderControllerElement element) { + this.slider = element; + } + + @Override + public boolean overrideControllerButtons(ScreenProcessor screen, Controller controller) { + ticksSinceIncrement++; + + var rightStickX = controller.state().axes().rightStickX(); + var rightStickY = controller.state().axes().rightStickY(); + var input = Math.abs(rightStickX) > Math.abs(rightStickY) ? rightStickX : rightStickY; + + if (Math.abs(input) > controller.config().buttonActivationThreshold) { + if (ticksSinceIncrement > controller.config().screenRepeatNavigationDelay || input != lastInput) { + slider.incrementValue(lastInput = input > 0 ? 1 : -1); + ticksSinceIncrement = 0; + return true; + } + } else { + this.lastInput = 0; + } + + return false; + } +} diff --git a/src/main/java/dev/isxander/controlify/compatibility/yacl/YACLScreenProcessor.java b/src/main/java/dev/isxander/controlify/compatibility/yacl/YACLScreenProcessor.java new file mode 100644 index 0000000..bc799f4 --- /dev/null +++ b/src/main/java/dev/isxander/controlify/compatibility/yacl/YACLScreenProcessor.java @@ -0,0 +1,32 @@ +package dev.isxander.controlify.compatibility.yacl; + +import dev.isxander.controlify.compatibility.screen.ScreenProcessor; +import dev.isxander.controlify.controller.Controller; +import dev.isxander.yacl.gui.YACLScreen; + +public class YACLScreenProcessor extends ScreenProcessor { + public YACLScreenProcessor(YACLScreen screen) { + super(screen); + } + + @Override + protected void handleComponentNavigation(Controller controller) { + if (controller.bindings().GUI_NEXT_TAB.justPressed()) { + var idx = screen.getCurrentCategoryIdx() + 1; + if (idx >= screen.config.categories().size()) idx = 0; + screen.changeCategory(idx); + } + if (controller.bindings().GUI_PREV_TAB.justPressed()) { + var idx = screen.getCurrentCategoryIdx() - 1; + if (idx < 0) idx = screen.config.categories().size() - 1; + screen.changeCategory(idx); + } + + super.handleComponentNavigation(controller); + } + + @Override + protected void setInitialFocus() { + screen.setFocused(screen.optionList); + } +} diff --git a/src/main/java/dev/isxander/controlify/config/gui/BindButtonController.java b/src/main/java/dev/isxander/controlify/config/gui/BindButtonController.java index be8e4cd..9e3f19a 100644 --- a/src/main/java/dev/isxander/controlify/config/gui/BindButtonController.java +++ b/src/main/java/dev/isxander/controlify/config/gui/BindButtonController.java @@ -47,7 +47,7 @@ public class BindButtonController implements Controller { } public static class BindButtonWidget extends ControllerWidget implements ComponentProcessorProvider, ComponentProcessor { - private boolean awaitingControllerInput = false, skipFirstTickInput = false; + private boolean awaitingControllerInput = false; private final Component awaitingText = Component.translatable("controlify.gui.bind_input_awaiting").withStyle(ChatFormatting.ITALIC); private final Set pressedBinds = new LinkedHashSet<>(); diff --git a/src/main/java/dev/isxander/controlify/config/gui/YACLHelper.java b/src/main/java/dev/isxander/controlify/config/gui/YACLHelper.java index a7a42db..e4fd1fd 100644 --- a/src/main/java/dev/isxander/controlify/config/gui/YACLHelper.java +++ b/src/main/java/dev/isxander/controlify/config/gui/YACLHelper.java @@ -7,11 +7,13 @@ import dev.isxander.controlify.controller.ControllerTheme; import dev.isxander.controlify.controller.Controller; import dev.isxander.yacl.api.*; import dev.isxander.yacl.gui.controllers.ActionController; +import dev.isxander.yacl.gui.controllers.BooleanController; import dev.isxander.yacl.gui.controllers.TickBoxController; import dev.isxander.yacl.gui.controllers.cycling.CyclingListController; import dev.isxander.yacl.gui.controllers.cycling.EnumController; import dev.isxander.yacl.gui.controllers.slider.FloatSliderController; import dev.isxander.yacl.gui.controllers.slider.IntegerSliderController; +import dev.isxander.yacl.gui.controllers.string.StringController; import net.minecraft.ChatFormatting; import net.minecraft.Util; import net.minecraft.client.Minecraft; @@ -62,14 +64,14 @@ public class YACLHelper { for (var controller : Controller.CONTROLLERS.values()) { var category = ConfigCategory.createBuilder(); - var customName = controller.config().customName; - category.name(Component.literal(customName == null ? controller.name() : customName)); + category.name(Component.literal(controller.name())); var config = controller.config(); var def = controller.defaultConfig(); - var configGroup = OptionGroup.createBuilder() - .name(Component.translatable("controlify.gui.group.config")) - .tooltip(Component.translatable("controlify.gui.group.config.tooltip")) + + var basicGroup = OptionGroup.createBuilder() + .name(Component.translatable("controlify.gui.group.basic")) + .tooltip(Component.translatable("controlify.gui.group.basic.tooltip")) .option(Option.createBuilder(float.class) .name(Component.translatable("controlify.gui.horizontal_look_sensitivity")) .tooltip(Component.translatable("controlify.gui.horizontal_look_sensitivity.tooltip")) @@ -82,12 +84,43 @@ public class YACLHelper { .binding(def.verticalLookSensitivity, () -> config.verticalLookSensitivity, v -> config.verticalLookSensitivity = v) .controller(opt -> new FloatSliderController(opt, 0.1f, 2f, 0.05f, v -> Component.literal(String.format("%.0f%%", v*100)))) .build()) + .option(Option.createBuilder(boolean.class) + .name(Component.translatable("controlify.gui.toggle_sprint")) + .tooltip(Component.translatable("controlify.gui.toggle_sprint.tooltip")) + .binding(def.toggleSprint, () -> config.toggleSprint, v -> config.toggleSprint = v) + .controller(opt -> new BooleanController(opt, v -> Component.translatable("controlify.gui.format.hold_toggle." + (v ? "toggle" : "hold")), false)) + .build()) + .option(Option.createBuilder(boolean.class) + .name(Component.translatable("controlify.gui.toggle_sneak")) + .tooltip(Component.translatable("controlify.gui.toggle_sneak.tooltip")) + .binding(def.toggleSneak, () -> config.toggleSneak, v -> config.toggleSneak = v) + .controller(opt -> new BooleanController(opt, v -> Component.translatable("controlify.gui.format.hold_toggle." + (v ? "toggle" : "hold")), false)) + .build()) .option(Option.createBuilder(float.class) .name(Component.translatable("controlify.gui.vmouse_sensitivity")) .tooltip(Component.translatable("controlify.gui.vmouse_sensitivity.tooltip")) .binding(def.virtualMouseSensitivity, () -> config.virtualMouseSensitivity, v -> config.virtualMouseSensitivity = v) .controller(opt -> new FloatSliderController(opt, 0.1f, 2f, 0.05f, v -> Component.literal(String.format("%.0f%%", v*100)))) .build()) + .option(Option.createBuilder(ControllerTheme.class) + .name(Component.translatable("controlify.gui.controller_theme")) + .tooltip(Component.translatable("controlify.gui.controller_theme.tooltip")) + .binding(controller.type().theme(), () -> config.theme, v -> config.theme = v) + .controller(EnumController::new) + .instant(true) + .build()) + .option(Option.createBuilder(String.class) + .name(Component.translatable("controlify.gui.custom_name")) + .tooltip(Component.translatable("controlify.gui.custom_name.tooltip")) + .binding(def.customName == null ? "" : def.customName, () -> config.customName == null ? "" : config.customName, v -> config.customName = (v.equals("") ? null : v)) + .controller(StringController::new) + .build()); + category.group(basicGroup.build()); + + var advancedGroup = OptionGroup.createBuilder() + .name(Component.translatable("controlify.gui.group.advanced")) + .tooltip(Component.translatable("controlify.gui.group.advanced.tooltip")) + .collapsed(true) .option(Option.createBuilder(int.class) .name(Component.translatable("controlify.gui.screen_repeat_navi_delay")) .tooltip(Component.translatable("controlify.gui.screen_repeat_navi_delay.tooltip")) @@ -113,15 +146,8 @@ public class YACLHelper { .tooltip(Component.translatable("controlify.gui.button_activation_threshold.tooltip")) .binding(def.buttonActivationThreshold, () -> config.buttonActivationThreshold, v -> config.buttonActivationThreshold = v) .controller(opt -> new FloatSliderController(opt, 0, 1, 0.05f, v -> Component.literal(String.format("%.0f%%", v*100)))) - .build()) - .option(Option.createBuilder(ControllerTheme.class) - .name(Component.translatable("controlify.gui.controller_theme")) - .tooltip(Component.translatable("controlify.gui.controller_theme.tooltip")) - .binding(controller.type().theme(), () -> config.theme, v -> config.theme = v) - .controller(EnumController::new) - .instant(true) .build()); - category.group(configGroup.build()); + category.group(advancedGroup.build()); var controlsGroup = OptionGroup.createBuilder() .name(Component.translatable("controlify.gui.group.controls")); diff --git a/src/main/java/dev/isxander/controlify/controller/Controller.java b/src/main/java/dev/isxander/controlify/controller/Controller.java index 32dbc95..9ae1b35 100644 --- a/src/main/java/dev/isxander/controlify/controller/Controller.java +++ b/src/main/java/dev/isxander/controlify/controller/Controller.java @@ -178,6 +178,9 @@ public final class Controller { public ControllerTheme theme = type().theme(); + public boolean toggleSprint = true; + public boolean toggleSneak = true; + public String customName = null; } } diff --git a/src/main/java/dev/isxander/controlify/ingame/ControllerPlayerMovement.java b/src/main/java/dev/isxander/controlify/ingame/ControllerPlayerMovement.java index 1d87458..c3dc089 100644 --- a/src/main/java/dev/isxander/controlify/ingame/ControllerPlayerMovement.java +++ b/src/main/java/dev/isxander/controlify/ingame/ControllerPlayerMovement.java @@ -3,12 +3,15 @@ package dev.isxander.controlify.ingame; import dev.isxander.controlify.controller.Controller; import net.minecraft.client.Minecraft; import net.minecraft.client.player.Input; +import net.minecraft.client.player.LocalPlayer; public class ControllerPlayerMovement extends Input { private final Controller controller; + private final LocalPlayer player; - public ControllerPlayerMovement(Controller controller) { + public ControllerPlayerMovement(Controller controller, LocalPlayer player) { this.controller = controller; + this.player = player; } @Override @@ -42,6 +45,13 @@ public class ControllerPlayerMovement extends Input { } this.jumping = bindings.JUMP.held(); - this.shiftKeyDown = bindings.SNEAK.held(); + + if (player.getAbilities().flying || !controller.config().toggleSneak) { + this.shiftKeyDown = bindings.SNEAK.held(); + } else { + if (bindings.SNEAK.justPressed()) { + this.shiftKeyDown = !this.shiftKeyDown; + } + } } } diff --git a/src/main/java/dev/isxander/controlify/ingame/InGameInputHandler.java b/src/main/java/dev/isxander/controlify/ingame/InGameInputHandler.java index 6e8a677..52d05e6 100644 --- a/src/main/java/dev/isxander/controlify/ingame/InGameInputHandler.java +++ b/src/main/java/dev/isxander/controlify/ingame/InGameInputHandler.java @@ -21,7 +21,7 @@ public class InGameInputHandler { this.controller = controller; this.minecraft = Minecraft.getInstance(); - this.controllerInput = new ControllerPlayerMovement(controller); + this.controllerInput = new ControllerPlayerMovement(controller, minecraft.player); this.keyboardInput = new KeyboardInput(minecraft.options); ControlifyEvents.INPUT_MODE_CHANGED.register(mode -> { @@ -45,9 +45,6 @@ public class InGameInputHandler { if (controller.bindings().PAUSE.justPressed()) { minecraft.pauseGame(false); } - if (controller.bindings().TOGGLE_DEBUG_MENU.justPressed()) { - minecraft.options.renderDebug = !minecraft.options.renderDebug; - } if (minecraft.player != null) { if (controller.bindings().NEXT_SLOT.justPressed()) { minecraft.player.getInventory().swapPaint(-1); @@ -73,9 +70,9 @@ public class InGameInputHandler { var delta = time - deltaTime; deltaTime = time; - var hsensitivity = controller.config().horizontalLookSensitivity * 8.0 + 2.0; + var hsensitivity = controller.config().horizontalLookSensitivity * 9.6 + 2.0; var hsensCubed = hsensitivity * hsensitivity * hsensitivity; - var vsensitivity = controller.config().verticalLookSensitivity * 8.0 + 2.0; + var vsensitivity = controller.config().verticalLookSensitivity * 9.6 + 2.0; var vsensCubed = vsensitivity * vsensitivity * vsensitivity; var dx = accumulatedDX * delta; @@ -93,7 +90,6 @@ public class InGameInputHandler { accumulatedDY -= Math.max(dy * 20, accumulatedDY); } - if (minecraft.player != null) minecraft.player.turn(dx * hsensCubed, dy * vsensCubed); } diff --git a/src/main/java/dev/isxander/controlify/mixins/compat/screen/vanilla/AbstractButtonMixin.java b/src/main/java/dev/isxander/controlify/mixins/compat/screen/vanilla/AbstractButtonMixin.java new file mode 100644 index 0000000..8145df0 --- /dev/null +++ b/src/main/java/dev/isxander/controlify/mixins/compat/screen/vanilla/AbstractButtonMixin.java @@ -0,0 +1,19 @@ +package dev.isxander.controlify.mixins.compat.screen.vanilla; + +import dev.isxander.controlify.compatibility.screen.component.ComponentProcessor; +import dev.isxander.controlify.compatibility.screen.component.ComponentProcessorProvider; +import dev.isxander.controlify.compatibility.vanilla.AbstractButtonComponentProcessor; +import net.minecraft.client.gui.components.AbstractButton; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; + +@Mixin(AbstractButton.class) +public class AbstractButtonMixin implements ComponentProcessorProvider { + @Unique private final AbstractButtonComponentProcessor controlify$processor + = new AbstractButtonComponentProcessor((AbstractButton) (Object) this); + + @Override + public ComponentProcessor componentProcessor() { + return controlify$processor; + } +} diff --git a/src/main/java/dev/isxander/controlify/mixins/compat/screen/yacl/CyclingControllerElementMixin.java b/src/main/java/dev/isxander/controlify/mixins/compat/screen/yacl/CyclingControllerElementMixin.java new file mode 100644 index 0000000..e7c47e1 --- /dev/null +++ b/src/main/java/dev/isxander/controlify/mixins/compat/screen/yacl/CyclingControllerElementMixin.java @@ -0,0 +1,19 @@ +package dev.isxander.controlify.mixins.compat.screen.yacl; + +import dev.isxander.controlify.compatibility.screen.component.ComponentProcessor; +import dev.isxander.controlify.compatibility.screen.component.ComponentProcessorProvider; +import dev.isxander.controlify.compatibility.yacl.CyclingControllerElementComponentProcessor; +import dev.isxander.yacl.gui.controllers.cycling.CyclingControllerElement; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; + +@Mixin(CyclingControllerElement.class) +public class CyclingControllerElementMixin implements ComponentProcessorProvider { + @Unique private final CyclingControllerElementComponentProcessor controlify$processor + = new CyclingControllerElementComponentProcessor((CyclingControllerElement) (Object) this); + + @Override + public ComponentProcessor componentProcessor() { + return controlify$processor; + } +} diff --git a/src/main/java/dev/isxander/controlify/mixins/compat/screen/yacl/SliderControllerElementMixin.java b/src/main/java/dev/isxander/controlify/mixins/compat/screen/yacl/SliderControllerElementMixin.java new file mode 100644 index 0000000..0d3f5d1 --- /dev/null +++ b/src/main/java/dev/isxander/controlify/mixins/compat/screen/yacl/SliderControllerElementMixin.java @@ -0,0 +1,19 @@ +package dev.isxander.controlify.mixins.compat.screen.yacl; + +import dev.isxander.controlify.compatibility.screen.component.ComponentProcessor; +import dev.isxander.controlify.compatibility.screen.component.ComponentProcessorProvider; +import dev.isxander.controlify.compatibility.yacl.SliderControllerElementComponentProcessor; +import dev.isxander.yacl.gui.controllers.slider.SliderControllerElement; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; + +@Mixin(SliderControllerElement.class) +public class SliderControllerElementMixin implements ComponentProcessorProvider { + @Unique private final SliderControllerElementComponentProcessor controlify$processor + = new SliderControllerElementComponentProcessor((SliderControllerElement) (Object) this); + + @Override + public ComponentProcessor componentProcessor() { + return controlify$processor; + } +} diff --git a/src/main/java/dev/isxander/controlify/mixins/compat/screen/yacl/YACLScreenMixin.java b/src/main/java/dev/isxander/controlify/mixins/compat/screen/yacl/YACLScreenMixin.java new file mode 100644 index 0000000..5009348 --- /dev/null +++ b/src/main/java/dev/isxander/controlify/mixins/compat/screen/yacl/YACLScreenMixin.java @@ -0,0 +1,18 @@ +package dev.isxander.controlify.mixins.compat.screen.yacl; + +import dev.isxander.controlify.compatibility.screen.ScreenProcessor; +import dev.isxander.controlify.compatibility.screen.ScreenProcessorProvider; +import dev.isxander.controlify.compatibility.yacl.YACLScreenProcessor; +import dev.isxander.yacl.gui.YACLScreen; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; + +@Mixin(YACLScreen.class) +public class YACLScreenMixin implements ScreenProcessorProvider { + @Unique private final YACLScreenProcessor controlify$processor = new YACLScreenProcessor((YACLScreen) (Object) this); + + @Override + public ScreenProcessor screenProcessor() { + return controlify$processor; + } +} diff --git a/src/main/java/dev/isxander/controlify/mixins/core/ClientPacketListenerMixin.java b/src/main/java/dev/isxander/controlify/mixins/core/ClientPacketListenerMixin.java index 3803931..e532a46 100644 --- a/src/main/java/dev/isxander/controlify/mixins/core/ClientPacketListenerMixin.java +++ b/src/main/java/dev/isxander/controlify/mixins/core/ClientPacketListenerMixin.java @@ -24,6 +24,6 @@ public class ClientPacketListenerMixin { @Inject(method = "handleLogin", at = @At(value = "FIELD", target = "Lnet/minecraft/client/player/LocalPlayer;input:Lnet/minecraft/client/player/Input;", opcode = Opcodes.ASTORE, shift = At.Shift.AFTER)) private void useControllerInput(ClientboundLoginPacket packet, CallbackInfo ci) { if (Controlify.instance().currentInputMode() == InputMode.CONTROLLER && minecraft.player != null) - minecraft.player.input = new ControllerPlayerMovement(Controlify.instance().currentController()); + minecraft.player.input = new ControllerPlayerMovement(Controlify.instance().currentController(), minecraft.player); } } diff --git a/src/main/java/dev/isxander/controlify/mixins/feature/bind/KeyMappingAccessor.java b/src/main/java/dev/isxander/controlify/mixins/feature/bind/KeyMappingAccessor.java index a06b5a7..ccb48b6 100644 --- a/src/main/java/dev/isxander/controlify/mixins/feature/bind/KeyMappingAccessor.java +++ b/src/main/java/dev/isxander/controlify/mixins/feature/bind/KeyMappingAccessor.java @@ -9,4 +9,10 @@ import org.spongepowered.asm.mixin.gen.Accessor; public interface KeyMappingAccessor { @Accessor InputConstants.Key getKey(); + + @Accessor + void setIsDown(boolean down); + + @Accessor + boolean getIsDown(); } diff --git a/src/main/java/dev/isxander/controlify/virtualmouse/VirtualMouseHandler.java b/src/main/java/dev/isxander/controlify/virtualmouse/VirtualMouseHandler.java index 3203edd..f5556f8 100644 --- a/src/main/java/dev/isxander/controlify/virtualmouse/VirtualMouseHandler.java +++ b/src/main/java/dev/isxander/controlify/virtualmouse/VirtualMouseHandler.java @@ -22,6 +22,9 @@ public class VirtualMouseHandler { private double targetX, targetY; private double currentX, currentY; + + private double scrollX, scrollY; + private final Minecraft minecraft; private boolean virtualMouseEnabled; @@ -51,6 +54,8 @@ public class VirtualMouseHandler { targetX = Mth.clamp(targetX, 0, minecraft.getWindow().getWidth()); targetY = Mth.clamp(targetY, 0, minecraft.getWindow().getHeight()); + scrollY += controller.bindings().VMOUSE_SCROLL_UP.state() - controller.bindings().VMOUSE_SCROLL_DOWN.state(); + var mouseHandler = (MouseHandlerAccessor) minecraft.mouseHandler; var keyboardHandler = (KeyboardHandlerAccessor) minecraft.keyboardHandler; @@ -83,12 +88,27 @@ public class VirtualMouseHandler { public void updateMouse() { if (!virtualMouseEnabled) return; - if (targetX == currentX && targetY == currentY) return; // don't need to needlessly update mouse position - currentX = Mth.lerp(minecraft.getDeltaFrameTime(), currentX, targetX); - currentY = Mth.lerp(minecraft.getDeltaFrameTime(), currentY, targetY); + if (Math.round(targetX * 100) / 100.0 != Math.round(currentX * 100) / 100.0 || Math.round(targetY * 100) / 100.0 != Math.round(currentY * 100) / 100.0) { + currentX = Mth.lerp(minecraft.getDeltaFrameTime(), currentX, targetX); + currentY = Mth.lerp(minecraft.getDeltaFrameTime(), currentY, targetY); - ((MouseHandlerAccessor) minecraft.mouseHandler).invokeOnMove(minecraft.getWindow().getWindow(), currentX, currentY); + ((MouseHandlerAccessor) minecraft.mouseHandler).invokeOnMove(minecraft.getWindow().getWindow(), currentX, currentY); + } else { + currentX = targetX; + currentY = targetY; + } + + if (Math.abs(scrollX) >= 0.01 || Math.abs(scrollY) >= 0.01) { + var currentScrollY = scrollY * Minecraft.getInstance().getDeltaFrameTime(); + scrollY -= currentScrollY; + var currentScrollX = scrollX * Minecraft.getInstance().getDeltaFrameTime(); + scrollX -= currentScrollX; + + ((MouseHandlerAccessor) minecraft.mouseHandler).invokeOnScroll(minecraft.getWindow().getWindow(), currentScrollX, currentScrollY); + } else { + scrollX = scrollY = 0; + } } public void onScreenChanged() { @@ -141,7 +161,6 @@ public class VirtualMouseHandler { public void enableVirtualMouse() { if (virtualMouseEnabled) return; - setMousePosition(); GLFW.glfwSetInputMode(minecraft.getWindow().getWindow(), GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_DISABLED); virtualMouseEnabled = true; @@ -152,6 +171,7 @@ public class VirtualMouseHandler { targetX = currentX = minecraft.mouseHandler.xpos(); targetY = currentY = minecraft.mouseHandler.ypos(); } + setMousePosition(); ControlifyEvents.VIRTUAL_MOUSE_TOGGLED.invoker().onVirtualMouseToggled(true); } @@ -162,6 +182,7 @@ public class VirtualMouseHandler { // make sure minecraft doesn't think the mouse is grabbed when it isn't ((MouseHandlerAccessor) minecraft.mouseHandler).setMouseGrabbed(false); + Controlify.instance().hideMouse(true, true); GLFW.glfwSetInputMode(minecraft.getWindow().getWindow(), GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_NORMAL); setMousePosition(); virtualMouseEnabled = false; @@ -196,7 +217,7 @@ public class VirtualMouseHandler { if (screens.contains(screenClass)) { screens.remove(screenClass); disableVirtualMouse(); - Controlify.instance().hideMouse(true); + Controlify.instance().hideMouse(true, false); minecraft.getToasts().addToast(SystemToast.multiline( minecraft, diff --git a/src/main/resources/assets/controlify/lang/en_us.json b/src/main/resources/assets/controlify/lang/en_us.json index d00c16e..49b7cc0 100644 --- a/src/main/resources/assets/controlify/lang/en_us.json +++ b/src/main/resources/assets/controlify/lang/en_us.json @@ -6,14 +6,24 @@ "controlify.gui.out_of_focus_input.tooltip": "If enabled, Controlify will still receive input even if the game window is not focused.", "controlify.gui.open_issue_tracker": "Open Issue Tracker", - "controlify.gui.group.config": "Config", - "controlify.gui.group.config.tooltip": "Adjust the controller configuration.", + "controlify.gui.group.basic": "Basic", + "controlify.gui.group.basic.tooltip": "Adjust how your controller behaves.", "controlify.gui.horizontal_look_sensitivity": "Horizontal Look Sensitivity", "controlify.gui.horizontal_look_sensitivity.tooltip": "How fast the camera moves horizontally when looking around.", "controlify.gui.vertical_look_sensitivity": "Vertical Look Sensitivity", "controlify.gui.vertical_look_sensitivity.tooltip": "How fast the camera moves vertically when looking around.", + "controlify.gui.toggle_sneak": "Sneak", + "controlify.gui.toggle_sneak.tooltip": "How the state of the sneak button behaves.", + "controlify.gui.toggle_sprint": "Sprint", + "controlify.gui.toggle_sprint.tooltip": "How the state of the sprint button behaves.", "controlify.gui.vmouse_sensitivity": "Virtual Mouse Sensitivity", "controlify.gui.vmouse_sensitivity.tooltip": "How fast the virtual mouse moves.", + "controlify.gui.controller_theme": "Controller Theme", + "controlify.gui.controller_theme.tooltip": "The theme to use for rendering controller buttons.", + "controlify.gui.custom_name": "Display Name", + "controlify.gui.custom_name.tooltip": "Name to display for this controller throughout Minecraft.", + "controlify.gui.group.advanced": "Advanced", + "controlify.gui.group.advanced.tooltip": "Settings you probably shouldn't touch!.", "controlify.gui.screen_repeat_navi_delay": "Screen Repeat Navigation Delay", "controlify.gui.screen_repeat_navi_delay.tooltip": "How the delay is for navigation to start repeating if you hold the stick.", "controlify.gui.left_stick_deadzone": "Left Stick Deadzone", @@ -23,14 +33,14 @@ "controlify.gui.stickdrift_warning": "Warning: Setting this too low will cause stickdrift! This is where the internals of your controller become mis-calibrated and register small amounts of input when there shouldn't be.", "controlify.gui.button_activation_threshold": "Button Activation Threshold", "controlify.gui.button_activation_threshold.tooltip": "How far a button needs to be pushed before registering as pressed.", - "controlify.gui.controller_theme": "Controller Theme", - "controlify.gui.controller_theme.tooltip": "The theme to use for rendering controller buttons.", "controlify.gui.group.controls": "Controls", "controlify.gui.group.controls.tooltip": "Adjust the controller controls.", "controlify.gui.bind_input_awaiting": "Press any button", "controlify.gui.format.ticks": "%s ticks", + "controlify.gui.format.hold_toggle.hold": "Hold", + "controlify.gui.format.hold_toggle.toggle": "Toggle", "controlify.gui.format.open": "OPEN URL", "controlify.gui.error.title": "Could not open Controlify settings", @@ -43,7 +53,7 @@ "controlify.toast.vmouse_disabled.title": "Virtual Mouse Disabled", "controlify.toast.vmouse_disabled.description": "Controlify virtual mouse is now disabled for this screen.", "controlify.toast.controller_connected.title": "Controller Connected", - "controlify.toast.controller_connected.description": "A new '%s' controller named has just been connected. You can switch to your other controller in Controlify settings.", + "controlify.toast.controller_connected.description": "A controller named '%s' has just been connected. You can switch to your other controller in Controlify settings.", "controlify.toast.controller_disconnected.title": "Controller Disconnected", "controlify.toast.controller_disconnected.description": "'%s' was disconnected.", @@ -73,10 +83,12 @@ "controlify.binding.controlify.vmouse_lclick": "Virtual Mouse LClick", "controlify.binding.controlify.vmouse_rclick": "Virtual Mouse RClick", "controlify.binding.controlify.vmouse_mclick": "Virtual Mouse MClick", + "controlify.binding.controlify.vmouse_scroll_up": "Virtual Mouse Scroll Up", + "controlify.binding.controlify.vmouse_scroll_down": "Virtual Mouse Scroll Down", "controlify.binding.controlify.vmouse_escape": "Virtual Mouse Key Escape", "controlify.binding.controlify.vmouse_shift": "Virtual Mouse Key Shift", "controlify.binding.controlify.vmouse_toggle": "Toggle Virtual Mouse", - "controlify.binding.controlify.toggle_debug_menu": "Toggle F3 Menu", + "controlify.binding.controlify.pick_block": "Pick Block", "controlify.beta.title": "Controlify Beta Notice", "controlify.beta.message": "You are currently using Controlify Beta.\n\nThis mod is a work in progress and will contain many bugs. Please, if you spot a bug in this mod or have a suggestion to make it even better, please create an issue on the %s!\n\nYou can always find the link to the issue tracker in Controlify's settings menu.", diff --git a/src/main/resources/controlify.mixins.json b/src/main/resources/controlify.mixins.json index 0a7b619..eded1ec 100644 --- a/src/main/resources/controlify.mixins.json +++ b/src/main/resources/controlify.mixins.json @@ -6,6 +6,7 @@ "mixins": [ ], "client": [ + "compat.screen.vanilla.AbstractButtonMixin", "compat.screen.vanilla.AbstractContainerEventHandlerMixin", "compat.screen.vanilla.AbstractSelectionListMixin", "compat.screen.vanilla.AbstractSliderButtonMixin", @@ -22,6 +23,9 @@ "compat.screen.vanilla.SelectWorldScreenMixin", "compat.screen.vanilla.ServerSelectionListEntryMixin", "compat.screen.vanilla.WorldSelectionListEntryMixin", + "compat.screen.yacl.CyclingControllerElementMixin", + "compat.screen.yacl.SliderControllerElementMixin", + "compat.screen.yacl.YACLScreenMixin", "core.ClientPacketListenerMixin", "core.KeyboardHandlerMixin", "core.MinecraftMixin",