forked from Clones/Controlify
joystick support
This commit is contained in:
@ -1,8 +1,10 @@
|
||||
package dev.isxander.controlify.config.gui;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import dev.isxander.controlify.bindings.Bind;
|
||||
import dev.isxander.controlify.bindings.GamepadBind;
|
||||
import dev.isxander.controlify.bindings.IBind;
|
||||
import dev.isxander.controlify.controller.gamepad.GamepadController;
|
||||
import dev.isxander.controlify.controller.gamepad.GamepadState;
|
||||
import dev.isxander.controlify.screenop.ScreenProcessor;
|
||||
import dev.isxander.controlify.screenop.ComponentProcessor;
|
||||
import dev.isxander.controlify.screenop.ComponentProcessorProvider;
|
||||
@ -16,20 +18,17 @@ import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
public class GamepadBindController implements Controller<IBind<GamepadState>> {
|
||||
private final Option<IBind<GamepadState>> option;
|
||||
private final GamepadController controller;
|
||||
|
||||
public class BindButtonController implements Controller<IBind> {
|
||||
private final Option<IBind> option;
|
||||
private final dev.isxander.controlify.controller.Controller controller;
|
||||
|
||||
public BindButtonController(Option<IBind> option, dev.isxander.controlify.controller.Controller controller) {
|
||||
public GamepadBindController(Option<IBind<GamepadState>> option, GamepadController controller) {
|
||||
this.option = option;
|
||||
this.controller = controller;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Option<IBind> option() {
|
||||
public Option<IBind<GamepadState>> option() {
|
||||
return this.option;
|
||||
}
|
||||
|
||||
@ -43,26 +42,18 @@ public class BindButtonController implements Controller<IBind> {
|
||||
return new BindButtonWidget(this, yaclScreen, dimension);
|
||||
}
|
||||
|
||||
public static class BindButtonWidget extends ControllerWidget<BindButtonController> implements ComponentProcessorProvider, ComponentProcessor {
|
||||
public static class BindButtonWidget extends ControllerWidget<GamepadBindController> implements ComponentProcessorProvider, ComponentProcessor {
|
||||
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<>();
|
||||
|
||||
public BindButtonWidget(BindButtonController control, YACLScreen screen, Dimension<Integer> dim) {
|
||||
public BindButtonWidget(GamepadBindController control, YACLScreen screen, Dimension<Integer> dim) {
|
||||
super(control, screen, dim);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawValueText(PoseStack matrices, int mouseX, int mouseY, float delta) {
|
||||
if (awaitingControllerInput) {
|
||||
if (pressedBinds.isEmpty()) {
|
||||
textRenderer.drawShadow(matrices, awaitingText, getDimension().xLimit() - textRenderer.width(awaitingText) - getXPadding(), getDimension().centerY() - textRenderer.lineHeight / 2f, 0xFFFFFF);
|
||||
} else {
|
||||
var bind = IBind.create(pressedBinds);
|
||||
var plusSize = 2 + textRenderer.width("+");
|
||||
bind.draw(matrices, getDimension().xLimit() - bind.drawSize().width() - getXPadding() - plusSize, getDimension().centerY(), control.controller);
|
||||
textRenderer.drawShadow(matrices, "+", getDimension().xLimit() - getXPadding() - plusSize, getDimension().centerY() - textRenderer.lineHeight / 2f, 0xFFFFFF);
|
||||
}
|
||||
textRenderer.drawShadow(matrices, awaitingText, getDimension().xLimit() - textRenderer.width(awaitingText) - getXPadding(), getDimension().centerY() - textRenderer.lineHeight / 2f, 0xFFFFFF);
|
||||
} else {
|
||||
var bind = control.option().pendingValue();
|
||||
bind.draw(matrices, getDimension().xLimit() - bind.drawSize().width(), getDimension().centerY(), control.controller);
|
||||
@ -95,41 +86,31 @@ public class BindButtonController implements Controller<IBind> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean overrideControllerButtons(ScreenProcessor<?> screen, dev.isxander.controlify.controller.Controller controller) {
|
||||
public boolean overrideControllerButtons(ScreenProcessor<?> screen, dev.isxander.controlify.controller.Controller<?, ?> controller) {
|
||||
if (controller != control.controller) return true;
|
||||
|
||||
if (controller.bindings().GUI_PRESS.justPressed() && !awaitingControllerInput) {
|
||||
return awaitingControllerInput = true;
|
||||
}
|
||||
|
||||
if (!awaitingControllerInput) return false;
|
||||
|
||||
if (pressedBinds.stream().anyMatch(bind -> !bind.held(controller.state(), controller))) {
|
||||
// finished
|
||||
awaitingControllerInput = false;
|
||||
control.option().requestSet(IBind.create(pressedBinds));
|
||||
pressedBinds.clear();
|
||||
} else {
|
||||
for (var bind : Bind.values()) {
|
||||
if (bind.held(controller.state(), controller) && !bind.held(controller.prevState(), controller)) {
|
||||
if (bind == Bind.GUIDE) { // FIXME: guide cannot be used as reserve because Windows hooks into xbox button to open game bar, maybe START?
|
||||
if (pressedBinds.isEmpty()) {
|
||||
awaitingControllerInput = false;
|
||||
control.option().requestSet(IBind.create(Bind.NONE));
|
||||
pressedBinds.clear();
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
pressedBinds.add(bind);
|
||||
}
|
||||
}
|
||||
var gamepad = control.controller;
|
||||
|
||||
for (var bind : GamepadBind.values()) {
|
||||
if (bind.held(gamepad.state(), gamepad) && !bind.held(gamepad.prevState(), gamepad)) {
|
||||
control.option().requestSet(bind);
|
||||
awaitingControllerInput = false;
|
||||
gamepad.consumeButtonState();
|
||||
return true;
|
||||
}
|
||||
control.controller.consumeButtonState();
|
||||
}
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean overrideControllerNavigation(ScreenProcessor<?> screen, dev.isxander.controlify.controller.Controller controller) {
|
||||
public boolean overrideControllerNavigation(ScreenProcessor<?> screen, dev.isxander.controlify.controller.Controller<?, ?> controller) {
|
||||
return awaitingControllerInput;
|
||||
}
|
||||
|
@ -0,0 +1,164 @@
|
||||
package dev.isxander.controlify.config.gui;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import dev.isxander.controlify.bindings.*;
|
||||
import dev.isxander.controlify.controller.gamepad.GamepadController;
|
||||
import dev.isxander.controlify.controller.gamepad.GamepadState;
|
||||
import dev.isxander.controlify.controller.joystick.JoystickController;
|
||||
import dev.isxander.controlify.controller.joystick.JoystickState;
|
||||
import dev.isxander.controlify.screenop.ComponentProcessor;
|
||||
import dev.isxander.controlify.screenop.ComponentProcessorProvider;
|
||||
import dev.isxander.controlify.screenop.ScreenProcessor;
|
||||
import dev.isxander.yacl.api.Controller;
|
||||
import dev.isxander.yacl.api.Option;
|
||||
import dev.isxander.yacl.api.utils.Dimension;
|
||||
import dev.isxander.yacl.gui.AbstractWidget;
|
||||
import dev.isxander.yacl.gui.YACLScreen;
|
||||
import dev.isxander.yacl.gui.controllers.ControllerWidget;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class JoystickBindController implements Controller<IBind<JoystickState>> {
|
||||
private final Option<IBind<JoystickState>> option;
|
||||
private final JoystickController controller;
|
||||
|
||||
public JoystickBindController(Option<IBind<JoystickState>> option, JoystickController controller) {
|
||||
this.option = option;
|
||||
this.controller = controller;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Option<IBind<JoystickState>> option() {
|
||||
return this.option;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component formatValue() {
|
||||
return Component.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractWidget provideWidget(YACLScreen yaclScreen, Dimension<Integer> dimension) {
|
||||
return new BindButtonWidget(this, yaclScreen, dimension);
|
||||
}
|
||||
|
||||
public static class BindButtonWidget extends ControllerWidget<JoystickBindController> implements ComponentProcessorProvider, ComponentProcessor {
|
||||
private boolean awaitingControllerInput = false;
|
||||
private final Component awaitingText = Component.translatable("controlify.gui.bind_input_awaiting").withStyle(ChatFormatting.ITALIC);
|
||||
|
||||
public BindButtonWidget(JoystickBindController control, YACLScreen screen, Dimension<Integer> dim) {
|
||||
super(control, screen, dim);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawValueText(PoseStack matrices, int mouseX, int mouseY, float delta) {
|
||||
if (awaitingControllerInput) {
|
||||
textRenderer.drawShadow(matrices, awaitingText, getDimension().xLimit() - textRenderer.width(awaitingText) - getXPadding(), getDimension().centerY() - textRenderer.lineHeight / 2f, 0xFFFFFF);
|
||||
} else {
|
||||
var bind = control.option().pendingValue();
|
||||
bind.draw(matrices, getDimension().xLimit() - bind.drawSize().width(), getDimension().centerY(), control.controller);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
|
||||
if (isFocused() && keyCode == GLFW.GLFW_KEY_ENTER && !awaitingControllerInput) {
|
||||
awaitingControllerInput = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseClicked(double mouseX, double mouseY, int button) {
|
||||
if (getDimension().isPointInside((int)mouseX, (int)mouseY)) {
|
||||
awaitingControllerInput = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComponentProcessor componentProcessor() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean overrideControllerButtons(ScreenProcessor<?> screen, dev.isxander.controlify.controller.Controller<?, ?> controller) {
|
||||
if (controller != control.controller) return true;
|
||||
|
||||
if (controller.bindings().GUI_PRESS.justPressed() && !awaitingControllerInput) {
|
||||
return awaitingControllerInput = true;
|
||||
}
|
||||
|
||||
if (!awaitingControllerInput) return false;
|
||||
|
||||
var joystick = control.controller;
|
||||
|
||||
var state = joystick.state();
|
||||
var prevState = joystick.prevState();
|
||||
|
||||
for (int i = 0; i < Math.min(state.buttons().size(), prevState.buttons().size()); i++) {
|
||||
if (state.buttons().get(i) && !prevState.buttons().get(i)) {
|
||||
control.option().requestSet(new JoystickButtonBind(joystick, i));
|
||||
awaitingControllerInput = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < Math.min(state.axes().size(), prevState.axes().size()); i++) {
|
||||
var axis = state.axes().get(i);
|
||||
var prevAxis = prevState.axes().get(i);
|
||||
var activationThreshold = joystick.config().buttonActivationThreshold;
|
||||
|
||||
if (Math.abs(prevAxis) < activationThreshold) {
|
||||
if (axis > activationThreshold) {
|
||||
control.option().requestSet(new JoystickAxisBind(joystick, i, JoystickAxisBind.AxisDirection.POSITIVE));
|
||||
awaitingControllerInput = false;
|
||||
return true;
|
||||
} else if (axis < -activationThreshold) {
|
||||
control.option().requestSet(new JoystickAxisBind(joystick, i, JoystickAxisBind.AxisDirection.NEGATIVE));
|
||||
awaitingControllerInput = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < Math.min(state.hats().size(), prevState.hats().size()); i++) {
|
||||
var hat = state.hats().get(i);
|
||||
var prevHat = prevState.hats().get(i);
|
||||
|
||||
if (prevHat.isCentered() && !hat.isCentered()) {
|
||||
control.option().requestSet(new JoystickHatBind(joystick, i, hat));
|
||||
awaitingControllerInput = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean overrideControllerNavigation(ScreenProcessor<?> screen, dev.isxander.controlify.controller.Controller<?, ?> controller) {
|
||||
return awaitingControllerInput;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getHoveredControlWidth() {
|
||||
return getUnhoveredControlWidth();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getUnhoveredControlWidth() {
|
||||
if (awaitingControllerInput)
|
||||
return textRenderer.width(awaitingText);
|
||||
|
||||
return control.option().pendingValue().drawSize().width();
|
||||
}
|
||||
}
|
||||
}
|
@ -3,8 +3,12 @@ package dev.isxander.controlify.config.gui;
|
||||
import dev.isxander.controlify.Controlify;
|
||||
import dev.isxander.controlify.bindings.IBind;
|
||||
import dev.isxander.controlify.config.GlobalSettings;
|
||||
import dev.isxander.controlify.controller.ControllerTheme;
|
||||
import dev.isxander.controlify.controller.Controller;
|
||||
import dev.isxander.controlify.controller.gamepad.GamepadController;
|
||||
import dev.isxander.controlify.controller.gamepad.GamepadState;
|
||||
import dev.isxander.controlify.controller.gamepad.BuiltinGamepadTheme;
|
||||
import dev.isxander.controlify.controller.joystick.JoystickController;
|
||||
import dev.isxander.controlify.controller.joystick.JoystickState;
|
||||
import dev.isxander.controlify.gui.screen.ControllerDeadzoneCalibrationScreen;
|
||||
import dev.isxander.yacl.api.*;
|
||||
import dev.isxander.yacl.gui.controllers.ActionController;
|
||||
@ -22,6 +26,10 @@ import net.minecraft.client.gui.screens.AlertScreen;
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
import net.minecraft.network.chat.Component;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class YACLHelper {
|
||||
public static Screen generateConfigScreen(Screen parent) {
|
||||
if (Controlify.instance().currentController() == null) {
|
||||
@ -41,11 +49,11 @@ public class YACLHelper {
|
||||
var globalSettings = Controlify.instance().config().globalSettings();
|
||||
var globalCategory = ConfigCategory.createBuilder()
|
||||
.name(Component.translatable("controlify.gui.category.global"))
|
||||
.option(Option.createBuilder(Controller.class)
|
||||
.option(Option.createBuilder((Class<Controller<?, ?>>) (Class<?>) Controller.class)
|
||||
.name(Component.translatable("controlify.gui.current_controller"))
|
||||
.tooltip(Component.translatable("controlify.gui.current_controller.tooltip"))
|
||||
.binding(Controlify.instance().currentController(), () -> Controlify.instance().currentController(), v -> Controlify.instance().setCurrentController(v))
|
||||
.controller(opt -> new CyclingListController<>(opt, Controller.CONTROLLERS.values().stream().filter(Controller::connected).toList(), c -> Component.literal(c.name())))
|
||||
.controller(opt -> new CyclingListController<>(opt, Controller.CONTROLLERS.values(), c -> Component.literal(c.name())))
|
||||
.instant(true)
|
||||
.build())
|
||||
.option(Option.createBuilder(boolean.class)
|
||||
@ -114,14 +122,22 @@ public class YACLHelper {
|
||||
.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())
|
||||
.build());
|
||||
|
||||
if (controller instanceof GamepadController gamepad) {
|
||||
var gamepadConfig = gamepad.config();
|
||||
var defaultGamepadConfig = gamepad.defaultConfig();
|
||||
|
||||
basicGroup.option(Option.createBuilder(BuiltinGamepadTheme.class)
|
||||
.name(Component.translatable("controlify.gui.controller_theme"))
|
||||
.tooltip(Component.translatable("controlify.gui.controller_theme.tooltip"))
|
||||
.binding(defaultGamepadConfig.theme, () -> gamepadConfig.theme, v -> gamepadConfig.theme = v)
|
||||
.controller(EnumController::new)
|
||||
.instant(true)
|
||||
.build());
|
||||
}
|
||||
|
||||
basicGroup
|
||||
.option(Option.createBuilder(String.class)
|
||||
.name(Component.translatable("controlify.gui.custom_name"))
|
||||
.tooltip(Component.translatable("controlify.gui.custom_name.tooltip"))
|
||||
@ -139,21 +155,59 @@ public class YACLHelper {
|
||||
.tooltip(Component.translatable("controlify.gui.screen_repeat_navi_delay.tooltip"))
|
||||
.binding(def.screenRepeatNavigationDelay, () -> config.screenRepeatNavigationDelay, v -> config.screenRepeatNavigationDelay = v)
|
||||
.controller(opt -> new IntegerSliderController(opt, 1, 20, 1, v -> Component.translatable("controlify.gui.format.ticks", v)))
|
||||
.build())
|
||||
.option(Option.createBuilder(float.class)
|
||||
.name(Component.translatable("controlify.gui.left_stick_deadzone"))
|
||||
.tooltip(Component.translatable("controlify.gui.left_stick_deadzone.tooltip"))
|
||||
.build());
|
||||
|
||||
if (controller instanceof GamepadController gamepad) {
|
||||
var gpCfg = gamepad.config();
|
||||
var gpCfgDef = gamepad.defaultConfig();
|
||||
advancedGroup
|
||||
.option(Option.createBuilder(float.class)
|
||||
.name(Component.translatable("controlify.gui.left_stick_deadzone"))
|
||||
.tooltip(Component.translatable("controlify.gui.left_stick_deadzone.tooltip"))
|
||||
.tooltip(Component.translatable("controlify.gui.stickdrift_warning").withStyle(ChatFormatting.RED))
|
||||
.binding(
|
||||
Math.max(gpCfgDef.leftStickDeadzoneX, gpCfgDef.leftStickDeadzoneY),
|
||||
() -> Math.max(gpCfg.leftStickDeadzoneX, gpCfgDef.leftStickDeadzoneY),
|
||||
v -> gpCfg.leftStickDeadzoneX = gpCfg.leftStickDeadzoneY = v
|
||||
)
|
||||
.controller(opt -> new FloatSliderController(opt, 0, 1, 0.01f, v -> Component.literal(String.format("%.0f%%", v*100))))
|
||||
.build())
|
||||
.option(Option.createBuilder(float.class)
|
||||
.name(Component.translatable("controlify.gui.right_stick_deadzone"))
|
||||
.tooltip(Component.translatable("controlify.gui.right_stick_deadzone.tooltip"))
|
||||
.tooltip(Component.translatable("controlify.gui.stickdrift_warning").withStyle(ChatFormatting.RED))
|
||||
.binding(
|
||||
Math.max(gpCfgDef.rightStickDeadzoneX, gpCfgDef.rightStickDeadzoneY),
|
||||
() -> Math.max(gpCfg.rightStickDeadzoneX, gpCfgDef.rightStickDeadzoneY),
|
||||
v -> gpCfg.rightStickDeadzoneX = gpCfg.rightStickDeadzoneY = v
|
||||
)
|
||||
.controller(opt -> new FloatSliderController(opt, 0, 1, 0.01f, v -> Component.literal(String.format("%.0f%%", v*100))))
|
||||
.build());
|
||||
} else if (controller instanceof JoystickController joystick) {
|
||||
Collection<Integer> deadzoneAxes = IntStream.range(0, joystick.axisCount())
|
||||
.filter(i -> joystick.mapping().axis(i).requiresDeadzone())
|
||||
.boxed()
|
||||
.collect(Collectors.toMap(
|
||||
i -> joystick.mapping().axis(i).identifier(),
|
||||
i -> i,
|
||||
(x, y) -> x
|
||||
))
|
||||
.values();
|
||||
var jsCfg = joystick.config();
|
||||
var jsCfgDef = joystick.defaultConfig();
|
||||
|
||||
for (int i : deadzoneAxes) {
|
||||
advancedGroup.option(Option.createBuilder(float.class)
|
||||
.name(Component.translatable("controlify.gui.joystick_axis_deadzone", joystick.mapping().axis(i).name()))
|
||||
.tooltip(Component.translatable("controlify.gui.joystick_axis_deadzone.tooltip", joystick.mapping().axis(i).name()))
|
||||
.tooltip(Component.translatable("controlify.gui.stickdrift_warning").withStyle(ChatFormatting.RED))
|
||||
.binding(def.leftStickDeadzone, () -> config.leftStickDeadzone, v -> config.leftStickDeadzone = v)
|
||||
.binding(jsCfgDef.getDeadzone(i), () -> jsCfg.getDeadzone(i), v -> jsCfg.setDeadzone(i, v))
|
||||
.controller(opt -> new FloatSliderController(opt, 0, 1, 0.01f, v -> Component.literal(String.format("%.0f%%", v*100))))
|
||||
.build())
|
||||
.option(Option.createBuilder(float.class)
|
||||
.name(Component.translatable("controlify.gui.right_stick_deadzone"))
|
||||
.tooltip(Component.translatable("controlify.gui.right_stick_deadzone.tooltip"))
|
||||
.tooltip(Component.translatable("controlify.gui.stickdrift_warning").withStyle(ChatFormatting.RED))
|
||||
.binding(def.rightStickDeadzone, () -> config.rightStickDeadzone, v -> config.rightStickDeadzone = v)
|
||||
.controller(opt -> new FloatSliderController(opt, 0, 1, 0.01f, v -> Component.literal(String.format("%.0f%%", v*100))))
|
||||
.build())
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
advancedGroup
|
||||
.option(ButtonOption.createBuilder()
|
||||
.name(Component.translatable("controlify.gui.auto_calibration"))
|
||||
.tooltip(Component.translatable("controlify.gui.auto_calibration.tooltip"))
|
||||
@ -170,19 +224,26 @@ public class YACLHelper {
|
||||
|
||||
var controlsGroup = OptionGroup.createBuilder()
|
||||
.name(Component.translatable("controlify.gui.group.controls"));
|
||||
for (var control : controller.bindings().registry().values()) {
|
||||
controlsGroup.option(Option.createBuilder(IBind.class)
|
||||
.name(control.name())
|
||||
.binding(control.defaultBind(), control::currentBind, control::setCurrentBind)
|
||||
.controller(opt -> new BindButtonController(opt, controller))
|
||||
.tooltip(control.description())
|
||||
.instant(true)
|
||||
.listener((opt, bind) -> { // yacl instant options have a bug where they don't save
|
||||
opt.applyValue();
|
||||
controlify.config().save();
|
||||
})
|
||||
.build());
|
||||
if (controller instanceof GamepadController gamepad) {
|
||||
for (var binding : gamepad.bindings().registry().values()) {
|
||||
controlsGroup.option(Option.createBuilder((Class<IBind<GamepadState>>) (Class<?>) IBind.class)
|
||||
.name(binding.name())
|
||||
.binding(binding.defaultBind(), binding::currentBind, binding::setCurrentBind)
|
||||
.controller(opt -> new GamepadBindController(opt, gamepad))
|
||||
.tooltip(binding.description())
|
||||
.build());
|
||||
}
|
||||
} else if (controller instanceof JoystickController joystick) {
|
||||
for (var binding : joystick.bindings().registry().values()) {
|
||||
controlsGroup.option(Option.createBuilder((Class<IBind<JoystickState>>) (Class<?>) IBind.class)
|
||||
.name(binding.name())
|
||||
.binding(binding.defaultBind(), binding::currentBind, binding::setCurrentBind)
|
||||
.controller(opt -> new JoystickBindController(opt, joystick))
|
||||
.tooltip(binding.description())
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
category.group(controlsGroup.build());
|
||||
|
||||
yacl.category(category.build());
|
||||
|
Reference in New Issue
Block a user