From 681eabd90ac2d9a9235a18f9c2c9d5fa985cb4ad Mon Sep 17 00:00:00 2001 From: isXander Date: Tue, 2 May 2023 12:30:34 +0100 Subject: [PATCH] fix bugs: fix reconnecting controllers are unidentified fix some mod keybinds failing to register fix crash with unmapped joysticks --- gradle/libs.versions.toml | 4 ++-- midnight-controls-comparison.md | 4 ++-- src/main/java/dev/isxander/controlify/Controlify.java | 2 ++ .../dev/isxander/controlify/api/ControlifyApi.java | 11 ++++++++--- .../isxander/controlify/api/bind/BindingSupplier.java | 3 ++- .../controlify/bindings/ControllerBindings.java | 7 ++++++- .../controlify/controller/AbstractController.java | 9 +++++++++ .../isxander/controlify/controller/Controller.java | 7 +++++++ .../controller/hid/ControllerHIDService.java | 4 ++++ .../joystick/CompoundJoystickController.java | 7 +++++++ .../joystick/mapping/UnmappedJoystickMapping.java | 2 +- .../dev/isxander/controlify/test/FakeController.java | 7 +++++++ 12 files changed, 57 insertions(+), 10 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e5bb1d1..1cc9e2e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,7 +13,7 @@ quilt_mappings = "10" fabric_loader = "0.14.19" fabric_api = "0.78.0+1.19.4" mixin_extras = "0.2.0-beta.6" -yet_another_config_lib = "2.4.2" +yet_another_config_lib = "2.5.0+1.19.4" mod_menu = "6.1.0-rc.4" hid4java = "0.7.0" quilt_json5 = "1.0.3" @@ -28,7 +28,7 @@ fabric_loader = { module = "net.fabricmc:fabric-loader", version.ref = "fabric_l fabric_api = { module = "net.fabricmc.fabric-api:fabric-api", version.ref = "fabric_api" } mixin_extras = { module = "com.github.llamalad7.mixinextras:mixinextras-fabric", version.ref = "mixin_extras" } -yet_another_config_lib = { module = "dev.isxander:yet-another-config-lib", version.ref = "yet_another_config_lib" } +yet_another_config_lib = { module = "dev.isxander.yacl:yet-another-config-lib-fabric", version.ref = "yet_another_config_lib" } mod_menu = { module = "com.terraformersmc:modmenu", version.ref = "mod_menu" } hid4java = { module = "org.hid4java:hid4java", version.ref = "hid4java" } quilt_json5 = { module = "org.quiltmc:quilt-json5", version.ref = "quilt_json5" } diff --git a/midnight-controls-comparison.md b/midnight-controls-comparison.md index 8e359fc..bf07515 100644 --- a/midnight-controls-comparison.md +++ b/midnight-controls-comparison.md @@ -7,10 +7,10 @@ | **Controller rumble** | ✅ Individual rumble effect intensity configuration | ⛔ Not present. | | **In-game button guide** | Extensible by 3rd party mods | Harcoded buttons and positions | | **Reach-around block placement** | ✅ Emulates Bedrock Edition reach-around | ✅ Takes custom liberties and has behaviour not present in bedrock | -| **Gyro support** | ✅ Option to require a button held and flick stick. Bypasses some sensitivity modifiers. | ⛔ Only works with Steam Deck due to Steam Input emulation | +| **Gyro support** | ✅ Supported on all controllers with native gyro. | ⛔ Only works with Steam Deck due to Steam Input emulation | | **Controller detection** | Powered by resource packs for unlimited data-driven detection | Hardcoded identifiers in code | | **Controller button rendering** | Powered by resource pack controller detection | Texture atlas for hardcoded identifiers | -| **In-game look sensitivity & behaviour** | Emulated Bedrock Edition with good defaults and snappy behaviour | testing required - reported bad defaults | +| **In-game look sensitivity & behaviour** | Emulated Bedrock Edition with good defaults and snappy behaviour | Default sensitivity is insane - more testing required | | **Container interaction** | Controlled cursor snaps to container slots (with API) with power of left click, right click and shift click | No slot snapping, testing required | | **Touchscreen support** | ⛔ | ✅ No multi-touch support | | **Joystick support** | ✅ Multiple joysticks can be combined together (no UI yet) | ✅ Multiple joysticks can be combined together | diff --git a/src/main/java/dev/isxander/controlify/Controlify.java b/src/main/java/dev/isxander/controlify/Controlify.java index 1a5ccbc..e11e20b 100644 --- a/src/main/java/dev/isxander/controlify/Controlify.java +++ b/src/main/java/dev/isxander/controlify/Controlify.java @@ -298,6 +298,8 @@ public class Controlify implements ControlifyApi { Controller.CONTROLLERS.values().stream().filter(controller -> controller.joystickId() == jid).findAny().ifPresent(controller -> { Controller.remove(controller); + controller.hidInfo().ifPresent(controllerHIDService::unconsumeController); + setCurrentController(Controller.CONTROLLERS.values().stream().findFirst().orElse(null)); LOGGER.info("Controller disconnected: " + controller.name()); this.setInputMode(currentController == null ? InputMode.KEYBOARD_MOUSE : InputMode.CONTROLLER); diff --git a/src/main/java/dev/isxander/controlify/api/ControlifyApi.java b/src/main/java/dev/isxander/controlify/api/ControlifyApi.java index ac599ba..2c65869 100644 --- a/src/main/java/dev/isxander/controlify/api/ControlifyApi.java +++ b/src/main/java/dev/isxander/controlify/api/ControlifyApi.java @@ -17,6 +17,13 @@ import java.util.Optional; * Anything that is asked for from this API is safe to use, even if it is not in the API package. */ public interface ControlifyApi { + /** + * The controller that is currently enabled and in use. + * If there is no controller disconnected or disabled, this will return {@link Optional#empty()}. + * This is the controller that is used for {@link dev.isxander.controlify.api.event.ControlifyEvents#ACTIVE_CONTROLLER_TICKED} + */ + @NotNull Optional> getCurrentController(); + /** * @deprecated Use {@link #getCurrentController()} instead. * @return the controller currently in use. If disabled, this will return {@link Controller#DUMMY} @@ -24,10 +31,8 @@ public interface ControlifyApi { @Deprecated @NotNull Controller currentController(); - @NotNull Optional> getCurrentController(); - /** - * Get the current input mode for the game. + * The last input received: a controller or keyboard/mouse. */ @NotNull InputMode currentInputMode(); boolean setInputMode(@NotNull InputMode mode); diff --git a/src/main/java/dev/isxander/controlify/api/bind/BindingSupplier.java b/src/main/java/dev/isxander/controlify/api/bind/BindingSupplier.java index ae5133e..6d2a0a8 100644 --- a/src/main/java/dev/isxander/controlify/api/bind/BindingSupplier.java +++ b/src/main/java/dev/isxander/controlify/api/bind/BindingSupplier.java @@ -1,8 +1,9 @@ package dev.isxander.controlify.api.bind; import dev.isxander.controlify.controller.Controller; +import org.jetbrains.annotations.NotNull; @FunctionalInterface public interface BindingSupplier { - ControllerBinding onController(Controller controller); + ControllerBinding onController(@NotNull Controller controller); } diff --git a/src/main/java/dev/isxander/controlify/bindings/ControllerBindings.java b/src/main/java/dev/isxander/controlify/bindings/ControllerBindings.java index 38fba8e..268688e 100644 --- a/src/main/java/dev/isxander/controlify/bindings/ControllerBindings.java +++ b/src/main/java/dev/isxander/controlify/bindings/ControllerBindings.java @@ -417,7 +417,12 @@ public class ControllerBindings { continue; try { - var identifier = new ResourceLocation("fabric-key-binding-api-v1", keyMapping.getName()); + var idPath = keyMapping.getName() + .toLowerCase() + .replaceAll("[^a-z0-9/._-]", "_") + .trim(); + + var identifier = new ResourceLocation("fabric-key-binding-api-v1", idPath); BooleanSupplier toggleOverride = () -> false; if (keyMapping instanceof ToggleKeyMapping toggleKeyMapping) { toggleOverride = ((ToggleKeyMappingAccessor) toggleKeyMapping).getNeedsToggle(); diff --git a/src/main/java/dev/isxander/controlify/controller/AbstractController.java b/src/main/java/dev/isxander/controlify/controller/AbstractController.java index 78435ef..0407a7c 100644 --- a/src/main/java/dev/isxander/controlify/controller/AbstractController.java +++ b/src/main/java/dev/isxander/controlify/controller/AbstractController.java @@ -16,6 +16,7 @@ import org.libsdl.SDL; import org.lwjgl.glfw.GLFW; import java.util.Objects; +import java.util.Optional; import java.util.UUID; public abstract class AbstractController implements Controller, RumbleCapable { @@ -24,6 +25,7 @@ public abstract class AbstractController bindings; protected C config, defaultConfig; @@ -34,6 +36,8 @@ public abstract class AbstractController hidInfo() { + return Optional.of(hidInfo); + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/src/main/java/dev/isxander/controlify/controller/Controller.java b/src/main/java/dev/isxander/controlify/controller/Controller.java index afa15ed..ca0dafe 100644 --- a/src/main/java/dev/isxander/controlify/controller/Controller.java +++ b/src/main/java/dev/isxander/controlify/controller/Controller.java @@ -48,6 +48,8 @@ public interface Controller hidInfo(); + default boolean canBeUsed() { return true; } @@ -156,6 +158,11 @@ public interface Controller hidInfo() { + return Optional.empty(); + } + @Override public String name() { return "DUMMY"; diff --git a/src/main/java/dev/isxander/controlify/controller/hid/ControllerHIDService.java b/src/main/java/dev/isxander/controlify/controller/hid/ControllerHIDService.java index 5e1f488..7bd239e 100644 --- a/src/main/java/dev/isxander/controlify/controller/hid/ControllerHIDService.java +++ b/src/main/java/dev/isxander/controlify/controller/hid/ControllerHIDService.java @@ -105,6 +105,10 @@ public class ControllerHIDService { } } + public void unconsumeController(ControllerHIDInfo hid) { + hid.hidDevice.ifPresent(device -> attachedDevices.remove(device.getPath())); + } + private boolean isController(HidDevice device) { boolean isControllerType = ControllerType.getTypeMap().containsKey(new HIDIdentifier(device.getVendorId(), device.getProductId())); boolean isGenericDesktopControlOrGameControl = device.getUsagePage() == 0x1 || device.getUsagePage() == 0x5; diff --git a/src/main/java/dev/isxander/controlify/controller/joystick/CompoundJoystickController.java b/src/main/java/dev/isxander/controlify/controller/joystick/CompoundJoystickController.java index 8e80d48..ce8f155 100644 --- a/src/main/java/dev/isxander/controlify/controller/joystick/CompoundJoystickController.java +++ b/src/main/java/dev/isxander/controlify/controller/joystick/CompoundJoystickController.java @@ -6,6 +6,7 @@ import com.google.gson.JsonElement; import dev.isxander.controlify.Controlify; import dev.isxander.controlify.bindings.ControllerBindings; import dev.isxander.controlify.controller.ControllerType; +import dev.isxander.controlify.controller.hid.ControllerHIDService; import dev.isxander.controlify.controller.joystick.mapping.JoystickMapping; import dev.isxander.controlify.controller.joystick.mapping.RPJoystickMapping; import dev.isxander.controlify.rumble.RumbleCapable; @@ -14,6 +15,7 @@ import dev.isxander.controlify.rumble.RumbleSource; import org.lwjgl.glfw.GLFW; import java.util.List; +import java.util.Optional; public class CompoundJoystickController implements JoystickController, RumbleCapable { private final String uid; @@ -177,4 +179,9 @@ public class CompoundJoystickController implements JoystickController hidInfo() { + return Optional.empty(); + } } diff --git a/src/main/java/dev/isxander/controlify/controller/joystick/mapping/UnmappedJoystickMapping.java b/src/main/java/dev/isxander/controlify/controller/joystick/mapping/UnmappedJoystickMapping.java index b49e03f..2d6c171 100644 --- a/src/main/java/dev/isxander/controlify/controller/joystick/mapping/UnmappedJoystickMapping.java +++ b/src/main/java/dev/isxander/controlify/controller/joystick/mapping/UnmappedJoystickMapping.java @@ -20,7 +20,7 @@ public class UnmappedJoystickMapping implements JoystickMapping { this.axes[i] = new UnmappedAxis(i, new GenericRenderer.Axis(Integer.toString(i + 1))); } - this.buttons = new UnmappedButton[axisCount]; + this.buttons = new UnmappedButton[buttonCount]; for (int i = 0; i < buttonCount; i++) { this.buttons[i] = new UnmappedButton(i, new GenericRenderer.Button(Integer.toString(i + 1))); } diff --git a/src/testmod/java/dev/isxander/controlify/test/FakeController.java b/src/testmod/java/dev/isxander/controlify/test/FakeController.java index 42c0556..72ad5af 100644 --- a/src/testmod/java/dev/isxander/controlify/test/FakeController.java +++ b/src/testmod/java/dev/isxander/controlify/test/FakeController.java @@ -6,6 +6,7 @@ import dev.isxander.controlify.Controlify; import dev.isxander.controlify.bindings.ControllerBindings; import dev.isxander.controlify.controller.Controller; import dev.isxander.controlify.controller.ControllerType; +import dev.isxander.controlify.controller.hid.ControllerHIDService; import dev.isxander.controlify.controller.joystick.JoystickConfig; import dev.isxander.controlify.controller.joystick.JoystickController; import dev.isxander.controlify.controller.joystick.JoystickState; @@ -16,6 +17,7 @@ import dev.isxander.controlify.rumble.RumbleManager; import dev.isxander.controlify.rumble.RumbleSource; import java.util.List; +import java.util.Optional; public class FakeController implements JoystickController { public static int JOYSTICK_COUNT = 0; @@ -139,6 +141,11 @@ public class FakeController implements JoystickController { return false; } + @Override + public Optional hidInfo() { + return Optional.empty(); + } + @Override public JoystickMapping mapping() { return UnmappedJoystickMapping.EMPTY;