forked from Clones/Controlify
scrollable vmouse, YACL compat, toggle sneak/sprint, 22w06a, custom name
This commit is contained in:
@ -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);
|
||||
|
@ -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<Controller, Set<Bind>> 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) {
|
||||
}
|
||||
}
|
||||
|
@ -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<ResourceLocation, ControllerBinding> 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);
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ import java.util.*;
|
||||
|
||||
public class ScreenProcessor<T extends Screen> {
|
||||
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<T extends Screen> {
|
||||
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<T extends Screen> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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<YACLScreen> {
|
||||
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);
|
||||
}
|
||||
}
|
@ -47,7 +47,7 @@ public class BindButtonController implements Controller<IBind> {
|
||||
}
|
||||
|
||||
public static class BindButtonWidget extends ControllerWidget<BindButtonController> 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<Bind> pressedBinds = new LinkedHashSet<>();
|
||||
|
||||
|
@ -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"));
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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,
|
||||
|
Reference in New Issue
Block a user