diff --git a/build.gradle.kts b/build.gradle.kts index 544ecfe..608bed9 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -54,6 +54,9 @@ dependencies { implementation(libs.hid4java) include(libs.hid4java) + + implementation(libs.quilt.json5) + include(libs.quilt.json5) } tasks { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8a07195..497bd93 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,6 +15,7 @@ mixin_extras = "0.2.0-beta.1" yet_another_config_lib = "2.3.0+beta.2+update.1.19.4-SNAPSHOT" mod_menu = "6.1.0-alpha.1" hid4java = "0.7.0" +quilt_json5 = "1.0.3" [libraries] minecraft = { module = "com.mojang:minecraft", version.ref = "minecraft" } @@ -25,6 +26,7 @@ mixin_extras = { module = "com.github.llamalad7:mixinextras", version.ref = "mix yet_another_config_lib = { module = "dev.isxander:yet-another-config-lib", 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" } [plugins] loom = { id = "fabric-loom", version.ref = "loom" } diff --git a/src/main/java/dev/isxander/controlify/bindings/ControllerBinding.java b/src/main/java/dev/isxander/controlify/bindings/ControllerBinding.java index 7289e98..4973091 100644 --- a/src/main/java/dev/isxander/controlify/bindings/ControllerBinding.java +++ b/src/main/java/dev/isxander/controlify/bindings/ControllerBinding.java @@ -38,11 +38,12 @@ public class ControllerBinding { this(controller, defaultBind, id, null, () -> false); } - public ControllerBinding(Controller controller, GamepadBind defaultBind, ResourceLocation id, KeyMapping override, BooleanSupplier toggleOverride) { - this(controller, controller instanceof GamepadController ? (IBind) defaultBind : new EmptyBind<>(), id, override, toggleOverride); + @SuppressWarnings("unchecked") + public ControllerBinding(Controller controller, GamepadBinds defaultBind, ResourceLocation id, KeyMapping override, BooleanSupplier toggleOverride) { + this(controller, controller instanceof GamepadController gamepad ? (IBind) defaultBind.forGamepad(gamepad) : new EmptyBind<>(), id, override, toggleOverride); } - public ControllerBinding(Controller controller, GamepadBind defaultBind, ResourceLocation id) { + public ControllerBinding(Controller controller, GamepadBinds defaultBind, ResourceLocation id) { this(controller, defaultBind, id, null, () -> false); } @@ -55,11 +56,11 @@ public class ControllerBinding { } public boolean held() { - return bind.held(controller.state(), controller); + return bind.held(controller.state()); } public boolean prevHeld() { - return bind.held(controller.prevState(), controller); + return bind.held(controller.prevState()); } public boolean justPressed() { @@ -108,6 +109,10 @@ public class ControllerBinding { return description; } + public boolean unbound() { + return bind instanceof EmptyBind; + } + public KeyMappingOverride override() { return override; } diff --git a/src/main/java/dev/isxander/controlify/bindings/ControllerBindings.java b/src/main/java/dev/isxander/controlify/bindings/ControllerBindings.java index 17bf2fd..9a2ea95 100644 --- a/src/main/java/dev/isxander/controlify/bindings/ControllerBindings.java +++ b/src/main/java/dev/isxander/controlify/bindings/ControllerBindings.java @@ -48,52 +48,52 @@ public class ControllerBindings { this.controller = controller; var options = Minecraft.getInstance().options; - register(WALK_FORWARD = new ControllerBinding<>(controller, GamepadBind.LEFT_STICK_FORWARD, new ResourceLocation("controlify", "walk_forward"))); - register(WALK_BACKWARD = new ControllerBinding<>(controller, GamepadBind.LEFT_STICK_BACKWARD, new ResourceLocation("controlify", "walk_backward"))); - register(WALK_LEFT = new ControllerBinding<>(controller, GamepadBind.LEFT_STICK_LEFT, new ResourceLocation("controlify", "strafe_left"))); - register(WALK_RIGHT = new ControllerBinding<>(controller, GamepadBind.LEFT_STICK_RIGHT, new ResourceLocation("controlify", "strafe_right"))); - register(LOOK_UP = new ControllerBinding<>(controller, GamepadBind.RIGHT_STICK_FORWARD, new ResourceLocation("controlify", "look_up"))); - register(LOOK_DOWN = new ControllerBinding<>(controller, GamepadBind.RIGHT_STICK_BACKWARD, new ResourceLocation("controlify", "look_down"))); - register(LOOK_LEFT = new ControllerBinding<>(controller, GamepadBind.RIGHT_STICK_LEFT, new ResourceLocation("controlify", "look_left"))); - register(LOOK_RIGHT = new ControllerBinding<>(controller, GamepadBind.RIGHT_STICK_RIGHT, new ResourceLocation("controlify", "look_right"))); - register(JUMP = new ControllerBinding<>(controller, GamepadBind.A_BUTTON, new ResourceLocation("controlify", "jump"), options.keyJump, () -> false)); - register(SNEAK = new ControllerBinding<>(controller, GamepadBind.RIGHT_STICK_PRESS, new ResourceLocation("controlify", "sneak"), options.keyShift, () -> controller.config().toggleSneak)); - register(ATTACK = new ControllerBinding<>(controller, GamepadBind.RIGHT_TRIGGER, new ResourceLocation("controlify", "attack"), options.keyAttack, () -> false)); - register(USE = new ControllerBinding<>(controller, GamepadBind.LEFT_TRIGGER, new ResourceLocation("controlify", "use"), options.keyUse, () -> false)); - register(SPRINT = new ControllerBinding<>(controller, GamepadBind.LEFT_STICK_PRESS, new ResourceLocation("controlify", "sprint"), options.keySprint, () -> controller.config().toggleSprint)); - register(DROP = new ControllerBinding<>(controller, GamepadBind.DPAD_DOWN, new ResourceLocation("controlify", "drop"), options.keyDrop, () -> false)); - register(NEXT_SLOT = new ControllerBinding<>(controller, GamepadBind.RIGHT_BUMPER, new ResourceLocation("controlify", "next_slot"))); - register(PREV_SLOT = new ControllerBinding<>(controller, GamepadBind.LEFT_BUMPER, new ResourceLocation("controlify", "prev_slot"))); - register(PAUSE = new ControllerBinding<>(controller, GamepadBind.START, new ResourceLocation("controlify", "pause"))); - register(INVENTORY = new ControllerBinding<>(controller, GamepadBind.Y_BUTTON, new ResourceLocation("controlify", "inventory"), options.keyInventory, () -> false)); - register(CHANGE_PERSPECTIVE = new ControllerBinding<>(controller, GamepadBind.BACK, new ResourceLocation("controlify", "change_perspective"), options.keyTogglePerspective, () -> false)); - register(SWAP_HANDS = new ControllerBinding<>(controller, GamepadBind.X_BUTTON, new ResourceLocation("controlify", "swap_hands"), options.keySwapOffhand, () -> false)); - register(OPEN_CHAT = new ControllerBinding<>(controller, GamepadBind.DPAD_UP, new ResourceLocation("controlify", "open_chat"), options.keyChat, () -> false)); - register(GUI_PRESS = new ControllerBinding<>(controller, GamepadBind.A_BUTTON, new ResourceLocation("controlify", "gui_press"))); - register(GUI_BACK = new ControllerBinding<>(controller, GamepadBind.B_BUTTON, new ResourceLocation("controlify", "gui_back"))); - register(GUI_NEXT_TAB = new ControllerBinding<>(controller, GamepadBind.RIGHT_BUMPER, new ResourceLocation("controlify", "gui_next_tab"))); - register(GUI_PREV_TAB = new ControllerBinding<>(controller, GamepadBind.LEFT_BUMPER, new ResourceLocation("controlify", "gui_prev_tab"))); - register(PICK_BLOCK = new ControllerBinding<>(controller, GamepadBind.DPAD_LEFT, new ResourceLocation("controlify", "pick_block"), options.keyPickItem, () -> false)); + register(WALK_FORWARD = new ControllerBinding<>(controller, GamepadBinds.LEFT_STICK_FORWARD, new ResourceLocation("controlify", "walk_forward"))); + register(WALK_BACKWARD = new ControllerBinding<>(controller, GamepadBinds.LEFT_STICK_BACKWARD, new ResourceLocation("controlify", "walk_backward"))); + register(WALK_LEFT = new ControllerBinding<>(controller, GamepadBinds.LEFT_STICK_LEFT, new ResourceLocation("controlify", "strafe_left"))); + register(WALK_RIGHT = new ControllerBinding<>(controller, GamepadBinds.LEFT_STICK_RIGHT, new ResourceLocation("controlify", "strafe_right"))); + register(LOOK_UP = new ControllerBinding<>(controller, GamepadBinds.RIGHT_STICK_FORWARD, new ResourceLocation("controlify", "look_up"))); + register(LOOK_DOWN = new ControllerBinding<>(controller, GamepadBinds.RIGHT_STICK_BACKWARD, new ResourceLocation("controlify", "look_down"))); + register(LOOK_LEFT = new ControllerBinding<>(controller, GamepadBinds.RIGHT_STICK_LEFT, new ResourceLocation("controlify", "look_left"))); + register(LOOK_RIGHT = new ControllerBinding<>(controller, GamepadBinds.RIGHT_STICK_RIGHT, new ResourceLocation("controlify", "look_right"))); + register(JUMP = new ControllerBinding<>(controller, GamepadBinds.A_BUTTON, new ResourceLocation("controlify", "jump"), options.keyJump, () -> false)); + register(SNEAK = new ControllerBinding<>(controller, GamepadBinds.RIGHT_STICK_PRESS, new ResourceLocation("controlify", "sneak"), options.keyShift, () -> controller.config().toggleSneak)); + register(ATTACK = new ControllerBinding<>(controller, GamepadBinds.RIGHT_TRIGGER, new ResourceLocation("controlify", "attack"), options.keyAttack, () -> false)); + register(USE = new ControllerBinding<>(controller, GamepadBinds.LEFT_TRIGGER, new ResourceLocation("controlify", "use"), options.keyUse, () -> false)); + register(SPRINT = new ControllerBinding<>(controller, GamepadBinds.LEFT_STICK_PRESS, new ResourceLocation("controlify", "sprint"), options.keySprint, () -> controller.config().toggleSprint)); + register(DROP = new ControllerBinding<>(controller, GamepadBinds.DPAD_DOWN, new ResourceLocation("controlify", "drop"), options.keyDrop, () -> false)); + register(NEXT_SLOT = new ControllerBinding<>(controller, GamepadBinds.RIGHT_BUMPER, new ResourceLocation("controlify", "next_slot"))); + register(PREV_SLOT = new ControllerBinding<>(controller, GamepadBinds.LEFT_BUMPER, new ResourceLocation("controlify", "prev_slot"))); + register(PAUSE = new ControllerBinding<>(controller, GamepadBinds.START, new ResourceLocation("controlify", "pause"))); + register(INVENTORY = new ControllerBinding<>(controller, GamepadBinds.Y_BUTTON, new ResourceLocation("controlify", "inventory"), options.keyInventory, () -> false)); + register(CHANGE_PERSPECTIVE = new ControllerBinding<>(controller, GamepadBinds.BACK, new ResourceLocation("controlify", "change_perspective"), options.keyTogglePerspective, () -> false)); + register(SWAP_HANDS = new ControllerBinding<>(controller, GamepadBinds.X_BUTTON, new ResourceLocation("controlify", "swap_hands"), options.keySwapOffhand, () -> false)); + register(OPEN_CHAT = new ControllerBinding<>(controller, GamepadBinds.DPAD_UP, new ResourceLocation("controlify", "open_chat"), options.keyChat, () -> false)); + register(GUI_PRESS = new ControllerBinding<>(controller, GamepadBinds.A_BUTTON, new ResourceLocation("controlify", "gui_press"))); + register(GUI_BACK = new ControllerBinding<>(controller, GamepadBinds.B_BUTTON, new ResourceLocation("controlify", "gui_back"))); + register(GUI_NEXT_TAB = new ControllerBinding<>(controller, GamepadBinds.RIGHT_BUMPER, new ResourceLocation("controlify", "gui_next_tab"))); + register(GUI_PREV_TAB = new ControllerBinding<>(controller, GamepadBinds.LEFT_BUMPER, new ResourceLocation("controlify", "gui_prev_tab"))); + register(PICK_BLOCK = new ControllerBinding<>(controller, GamepadBinds.DPAD_LEFT, new ResourceLocation("controlify", "pick_block"), options.keyPickItem, () -> false)); register(TOGGLE_HUD_VISIBILITY = new ControllerBinding<>(controller, new EmptyBind<>(), new ResourceLocation("controlify", "toggle_hud_visibility"))); - register(SHOW_PLAYER_LIST = new ControllerBinding<>(controller, GamepadBind.DPAD_RIGHT, new ResourceLocation("controlify", "show_player_list"), options.keyPlayerList, () -> false)); - register(VMOUSE_MOVE_UP = new ControllerBinding<>(controller, GamepadBind.LEFT_STICK_FORWARD, new ResourceLocation("controlify", "vmouse_move_up"))); - register(VMOUSE_MOVE_DOWN = new ControllerBinding<>(controller, GamepadBind.LEFT_STICK_BACKWARD, new ResourceLocation("controlify", "vmouse_move_down"))); - register(VMOUSE_MOVE_LEFT = new ControllerBinding<>(controller, GamepadBind.LEFT_STICK_LEFT, new ResourceLocation("controlify", "vmouse_move_left"))); - register(VMOUSE_MOVE_RIGHT = new ControllerBinding<>(controller, GamepadBind.LEFT_STICK_RIGHT, new ResourceLocation("controlify", "vmouse_move_right"))); - register(VMOUSE_LCLICK = new ControllerBinding<>(controller, GamepadBind.A_BUTTON, new ResourceLocation("controlify", "vmouse_lclick"))); - register(VMOUSE_RCLICK = new ControllerBinding<>(controller, GamepadBind.X_BUTTON, new ResourceLocation("controlify", "vmouse_rclick"))); - register(VMOUSE_SHIFT_CLICK = new ControllerBinding<>(controller, GamepadBind.Y_BUTTON, new ResourceLocation("controlify", "vmouse_shift_click"))); - register(VMOUSE_SCROLL_UP = new ControllerBinding<>(controller, GamepadBind.RIGHT_STICK_FORWARD, new ResourceLocation("controlify", "vmouse_scroll_up"))); - register(VMOUSE_SCROLL_DOWN = new ControllerBinding<>(controller, GamepadBind.RIGHT_STICK_BACKWARD, new ResourceLocation("controlify", "vmouse_scroll_down"))); - register(VMOUSE_ESCAPE = new ControllerBinding<>(controller, GamepadBind.B_BUTTON, new ResourceLocation("controlify", "vmouse_escape"))); - register(VMOUSE_SHIFT = new ControllerBinding<>(controller, GamepadBind.LEFT_STICK_PRESS, new ResourceLocation("controlify", "vmouse_shift"))); - register(VMOUSE_TOGGLE = new ControllerBinding<>(controller, GamepadBind.BACK, new ResourceLocation("controlify", "vmouse_toggle"))); - register(GUI_NAVI_UP = new ControllerBinding<>(controller, GamepadBind.LEFT_STICK_FORWARD, new ResourceLocation("controlify", "gui_navi_up"))); - register(GUI_NAVI_DOWN = new ControllerBinding<>(controller, GamepadBind.LEFT_STICK_BACKWARD, new ResourceLocation("controlify", "gui_navi_down"))); - register(GUI_NAVI_LEFT = new ControllerBinding<>(controller, GamepadBind.LEFT_STICK_LEFT, new ResourceLocation("controlify", "gui_navi_left"))); - register(GUI_NAVI_RIGHT = new ControllerBinding<>(controller, GamepadBind.LEFT_STICK_RIGHT, new ResourceLocation("controlify", "gui_navi_right"))); - register(YACL_CYCLE_OPT_FORWARD = new ControllerBinding<>(controller, GamepadBind.RIGHT_STICK_RIGHT, new ResourceLocation("controlify", "yacl_cycle_opt_forward"))); - register(YACL_CYCLE_OPT_BACKWARD = new ControllerBinding<>(controller, GamepadBind.RIGHT_STICK_LEFT, new ResourceLocation("controlify", "yacl_cycle_opt_backward"))); + register(SHOW_PLAYER_LIST = new ControllerBinding<>(controller, GamepadBinds.DPAD_RIGHT, new ResourceLocation("controlify", "show_player_list"), options.keyPlayerList, () -> false)); + register(VMOUSE_MOVE_UP = new ControllerBinding<>(controller, GamepadBinds.LEFT_STICK_FORWARD, new ResourceLocation("controlify", "vmouse_move_up"))); + register(VMOUSE_MOVE_DOWN = new ControllerBinding<>(controller, GamepadBinds.LEFT_STICK_BACKWARD, new ResourceLocation("controlify", "vmouse_move_down"))); + register(VMOUSE_MOVE_LEFT = new ControllerBinding<>(controller, GamepadBinds.LEFT_STICK_LEFT, new ResourceLocation("controlify", "vmouse_move_left"))); + register(VMOUSE_MOVE_RIGHT = new ControllerBinding<>(controller, GamepadBinds.LEFT_STICK_RIGHT, new ResourceLocation("controlify", "vmouse_move_right"))); + register(VMOUSE_LCLICK = new ControllerBinding<>(controller, GamepadBinds.A_BUTTON, new ResourceLocation("controlify", "vmouse_lclick"))); + register(VMOUSE_RCLICK = new ControllerBinding<>(controller, GamepadBinds.X_BUTTON, new ResourceLocation("controlify", "vmouse_rclick"))); + register(VMOUSE_SHIFT_CLICK = new ControllerBinding<>(controller, GamepadBinds.Y_BUTTON, new ResourceLocation("controlify", "vmouse_shift_click"))); + register(VMOUSE_SCROLL_UP = new ControllerBinding<>(controller, GamepadBinds.RIGHT_STICK_FORWARD, new ResourceLocation("controlify", "vmouse_scroll_up"))); + register(VMOUSE_SCROLL_DOWN = new ControllerBinding<>(controller, GamepadBinds.RIGHT_STICK_BACKWARD, new ResourceLocation("controlify", "vmouse_scroll_down"))); + register(VMOUSE_ESCAPE = new ControllerBinding<>(controller, GamepadBinds.B_BUTTON, new ResourceLocation("controlify", "vmouse_escape"))); + register(VMOUSE_SHIFT = new ControllerBinding<>(controller, GamepadBinds.LEFT_STICK_PRESS, new ResourceLocation("controlify", "vmouse_shift"))); + register(VMOUSE_TOGGLE = new ControllerBinding<>(controller, GamepadBinds.BACK, new ResourceLocation("controlify", "vmouse_toggle"))); + register(GUI_NAVI_UP = new ControllerBinding<>(controller, GamepadBinds.LEFT_STICK_FORWARD, new ResourceLocation("controlify", "gui_navi_up"))); + register(GUI_NAVI_DOWN = new ControllerBinding<>(controller, GamepadBinds.LEFT_STICK_BACKWARD, new ResourceLocation("controlify", "gui_navi_down"))); + register(GUI_NAVI_LEFT = new ControllerBinding<>(controller, GamepadBinds.LEFT_STICK_LEFT, new ResourceLocation("controlify", "gui_navi_left"))); + register(GUI_NAVI_RIGHT = new ControllerBinding<>(controller, GamepadBinds.LEFT_STICK_RIGHT, new ResourceLocation("controlify", "gui_navi_right"))); + register(YACL_CYCLE_OPT_FORWARD = new ControllerBinding<>(controller, GamepadBinds.RIGHT_STICK_RIGHT, new ResourceLocation("controlify", "yacl_cycle_opt_forward"))); + register(YACL_CYCLE_OPT_BACKWARD = new ControllerBinding<>(controller, GamepadBinds.RIGHT_STICK_LEFT, new ResourceLocation("controlify", "yacl_cycle_opt_backward"))); ControlifyEvents.CONTROLLER_BIND_REGISTRY.invoker().onRegisterControllerBinds(this, controller); diff --git a/src/main/java/dev/isxander/controlify/bindings/EmptyBind.java b/src/main/java/dev/isxander/controlify/bindings/EmptyBind.java index e0245b1..21ead8c 100644 --- a/src/main/java/dev/isxander/controlify/bindings/EmptyBind.java +++ b/src/main/java/dev/isxander/controlify/bindings/EmptyBind.java @@ -15,7 +15,12 @@ public class EmptyBind implements IBind { } @Override - public void draw(PoseStack matrices, int x, int centerY, Controller controller) { + public boolean held(T state) { + return false; + } + + @Override + public void draw(PoseStack matrices, int x, int centerY) { } @@ -31,6 +36,11 @@ public class EmptyBind implements IBind { return object; } + @Override + public Controller controller() { + return null; + } + @Override public boolean equals(Object obj) { return obj instanceof EmptyBind; diff --git a/src/main/java/dev/isxander/controlify/bindings/GamepadBind.java b/src/main/java/dev/isxander/controlify/bindings/GamepadBind.java index 6d443a6..bfe8f09 100644 --- a/src/main/java/dev/isxander/controlify/bindings/GamepadBind.java +++ b/src/main/java/dev/isxander/controlify/bindings/GamepadBind.java @@ -4,78 +4,37 @@ import com.google.gson.JsonObject; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; import dev.isxander.controlify.controller.Controller; -import dev.isxander.controlify.controller.gamepad.GamepadConfig; import dev.isxander.controlify.controller.gamepad.BuiltinGamepadTheme; +import dev.isxander.controlify.controller.gamepad.GamepadConfig; +import dev.isxander.controlify.controller.gamepad.GamepadController; import dev.isxander.controlify.controller.gamepad.GamepadState; import dev.isxander.controlify.gui.DrawSize; import net.minecraft.client.gui.GuiComponent; import net.minecraft.resources.ResourceLocation; -import java.util.HashMap; -import java.util.Map; import java.util.function.Function; -public enum GamepadBind implements IBind { - A_BUTTON(state -> state.gamepadButtons().a(), "a_button"), - B_BUTTON(state -> state.gamepadButtons().b(), "b_button"), - X_BUTTON(state -> state.gamepadButtons().x(), "x_button"), - Y_BUTTON(state -> state.gamepadButtons().y(), "y_button"), - LEFT_BUMPER(state -> state.gamepadButtons().leftBumper(), "left_bumper"), - RIGHT_BUMPER(state -> state.gamepadButtons().rightBumper(), "right_bumper"), - LEFT_STICK_PRESS(state -> state.gamepadButtons().leftStick(), "left_stick_press"), - RIGHT_STICK_PRESS(state -> state.gamepadButtons().rightStick(), "right_stick_press"), - START(state -> state.gamepadButtons().start(), "start"), - BACK(state -> state.gamepadButtons().back(), "back"), - GUIDE(state -> state.gamepadButtons().guide(), "guide"), // the middle button - DPAD_UP(state -> state.gamepadButtons().dpadUp(), "dpad_up"), - DPAD_DOWN(state -> state.gamepadButtons().dpadDown(), "dpad_down"), - DPAD_LEFT(state -> state.gamepadButtons().dpadLeft(), "dpad_left"), - DPAD_RIGHT(state -> state.gamepadButtons().dpadRight(), "dpad_right"), - LEFT_TRIGGER(state -> state.gamepadAxes().leftTrigger(), "left_trigger", true), - RIGHT_TRIGGER(state -> state.gamepadAxes().rightTrigger(), "right_trigger", true), - LEFT_STICK_FORWARD(state -> -Math.min(0, state.gamepadAxes().leftStickY()), "left_stick_up", true), - LEFT_STICK_BACKWARD(state -> Math.max(0, state.gamepadAxes().leftStickY()), "left_stick_down", true), - LEFT_STICK_LEFT(state -> -Math.min(0, state.gamepadAxes().leftStickX()), "left_stick_left", true), - LEFT_STICK_RIGHT(state -> Math.max(0, state.gamepadAxes().leftStickX()), "left_stick_right", true), - RIGHT_STICK_FORWARD(state -> -Math.min(0, state.gamepadAxes().rightStickY()), "right_stick_up", true), - RIGHT_STICK_BACKWARD(state -> Math.max(0, state.gamepadAxes().rightStickY()), "right_stick_down", true), - RIGHT_STICK_LEFT(state -> -Math.min(0, state.gamepadAxes().rightStickX()), "right_stick_left", true), - RIGHT_STICK_RIGHT(state -> Math.max(0, state.gamepadAxes().rightStickX()), "right_stick_right", true); - - public static final String BIND_ID = "gamepad"; - - private final Function state; +public class GamepadBind implements IBind { + private final Function stateSupplier; private final String identifier; - private final Map textureLocations; + private final GamepadController gamepad; + private final ResourceLocation defaultTexture; - GamepadBind(Function state, String identifier, boolean jvmIsBad) { - this.state = state; + public GamepadBind(Function stateSupplier, String identifier, GamepadController gamepad) { + this.stateSupplier = stateSupplier; this.identifier = identifier; - - this.textureLocations = new HashMap<>(); - for (BuiltinGamepadTheme theme : BuiltinGamepadTheme.values()) { - if (theme == BuiltinGamepadTheme.DEFAULT) continue; - textureLocations.put(theme, new ResourceLocation("controlify", "textures/gui/gamepad_buttons/" + theme.id() + "/" + identifier + ".png")); - } - } - - GamepadBind(Function state, String identifier) { - this(state1 -> state.apply(state1) ? 1f : 0f, identifier, true); + this.gamepad = gamepad; + this.defaultTexture = new ResourceLocation("controlify", "textures/gui/gamepad_buttons/" + gamepad.config().theme.id() + "/" + identifier + ".png"); } @Override public float state(GamepadState state) { - return this.state.apply(state); + return stateSupplier.apply(state); } @Override - public void draw(PoseStack matrices, int x, int centerY, Controller controller) { - ResourceLocation texture; - if (((GamepadConfig)controller.config()).theme == BuiltinGamepadTheme.DEFAULT) { - texture = new ResourceLocation("controlify", "textures/gui/gamepad/" + controller.type().identifier() + "/" + identifier + ".png"); - } else { - texture = textureLocations.get(((GamepadConfig)controller.config()).theme); - } + public void draw(PoseStack matrices, int x, int centerY) { + ResourceLocation texture = getTexture(gamepad.config().theme); RenderSystem.setShaderTexture(0, texture); RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); @@ -92,19 +51,22 @@ public enum GamepadBind implements IBind { return identifier; } + @Override + public Controller controller() { + return this.gamepad; + } + @Override public JsonObject toJson() { JsonObject object = new JsonObject(); - object.addProperty("type", BIND_ID); + object.addProperty("type", GamepadBinds.BIND_ID); object.addProperty("bind", identifier); return object; } - public static GamepadBind fromJson(JsonObject object) { - String name = object.get("bind").getAsString(); - for (GamepadBind bind : values()) { - if (bind.identifier.equals(name)) return bind; - } - return null; + private ResourceLocation getTexture(BuiltinGamepadTheme theme) { + if (theme == BuiltinGamepadTheme.DEFAULT) + return defaultTexture; + return new ResourceLocation("controlify", "textures/gui/gamepad_buttons/" + theme.id() + "/" + identifier + ".png"); } } diff --git a/src/main/java/dev/isxander/controlify/bindings/GamepadBinds.java b/src/main/java/dev/isxander/controlify/bindings/GamepadBinds.java new file mode 100644 index 0000000..2c02409 --- /dev/null +++ b/src/main/java/dev/isxander/controlify/bindings/GamepadBinds.java @@ -0,0 +1,62 @@ +package dev.isxander.controlify.bindings; + +import com.google.gson.JsonObject; +import dev.isxander.controlify.controller.gamepad.GamepadController; +import dev.isxander.controlify.controller.gamepad.GamepadState; + +import java.util.Optional; +import java.util.function.Function; + +public enum GamepadBinds { + A_BUTTON(state -> state.gamepadButtons().a(), "a_button"), + B_BUTTON(state -> state.gamepadButtons().b(), "b_button"), + X_BUTTON(state -> state.gamepadButtons().x(), "x_button"), + Y_BUTTON(state -> state.gamepadButtons().y(), "y_button"), + LEFT_BUMPER(state -> state.gamepadButtons().leftBumper(), "left_bumper"), + RIGHT_BUMPER(state -> state.gamepadButtons().rightBumper(), "right_bumper"), + LEFT_STICK_PRESS(state -> state.gamepadButtons().leftStick(), "left_stick_press"), + RIGHT_STICK_PRESS(state -> state.gamepadButtons().rightStick(), "right_stick_press"), + START(state -> state.gamepadButtons().start(), "start"), + BACK(state -> state.gamepadButtons().back(), "back"), + GUIDE(state -> state.gamepadButtons().guide(), "guide"), // the middle button + DPAD_UP(state -> state.gamepadButtons().dpadUp(), "dpad_up"), + DPAD_DOWN(state -> state.gamepadButtons().dpadDown(), "dpad_down"), + DPAD_LEFT(state -> state.gamepadButtons().dpadLeft(), "dpad_left"), + DPAD_RIGHT(state -> state.gamepadButtons().dpadRight(), "dpad_right"), + LEFT_TRIGGER(state -> state.gamepadAxes().leftTrigger(), "left_trigger", true), + RIGHT_TRIGGER(state -> state.gamepadAxes().rightTrigger(), "right_trigger", true), + LEFT_STICK_FORWARD(state -> -Math.min(0, state.gamepadAxes().leftStickY()), "left_stick_up", true), + LEFT_STICK_BACKWARD(state -> Math.max(0, state.gamepadAxes().leftStickY()), "left_stick_down", true), + LEFT_STICK_LEFT(state -> -Math.min(0, state.gamepadAxes().leftStickX()), "left_stick_left", true), + LEFT_STICK_RIGHT(state -> Math.max(0, state.gamepadAxes().leftStickX()), "left_stick_right", true), + RIGHT_STICK_FORWARD(state -> -Math.min(0, state.gamepadAxes().rightStickY()), "right_stick_up", true), + RIGHT_STICK_BACKWARD(state -> Math.max(0, state.gamepadAxes().rightStickY()), "right_stick_down", true), + RIGHT_STICK_LEFT(state -> -Math.min(0, state.gamepadAxes().rightStickX()), "right_stick_left", true), + RIGHT_STICK_RIGHT(state -> Math.max(0, state.gamepadAxes().rightStickX()), "right_stick_right", true); + + public static final String BIND_ID = "gamepad"; + + private final Function state; + private final String identifier; + + GamepadBinds(Function state, String identifier, boolean jvmIsBad) { + this.state = state; + this.identifier = identifier; + } + + GamepadBinds(Function state, String identifier) { + this(state1 -> state.apply(state1) ? 1f : 0f, identifier, true); + } + + public GamepadBind forGamepad(GamepadController gamepad) { + return new GamepadBind(state, identifier, gamepad); + } + + public static Optional fromJson(JsonObject object) { + String name = object.get("bind").getAsString(); + for (GamepadBinds bind : values()) { + if (bind.identifier.equals(name)) return Optional.of(bind); + } + return Optional.empty(); + } +} diff --git a/src/main/java/dev/isxander/controlify/bindings/IBind.java b/src/main/java/dev/isxander/controlify/bindings/IBind.java index 82228e6..a1f12fb 100644 --- a/src/main/java/dev/isxander/controlify/bindings/IBind.java +++ b/src/main/java/dev/isxander/controlify/bindings/IBind.java @@ -10,23 +10,25 @@ import dev.isxander.controlify.gui.DrawSize; public interface IBind { float state(S state); - default boolean held(S state, Controller controller) { - return state(state) > controller.config().buttonActivationThreshold; + default boolean held(S state) { + return state(state) > controller().config().buttonActivationThreshold; } - void draw(PoseStack matrices, int x, int centerY, Controller controller); + void draw(PoseStack matrices, int x, int centerY); DrawSize drawSize(); JsonObject toJson(); + Controller controller(); + @SuppressWarnings("unchecked") static IBind fromJson(JsonObject json, Controller controller) { var type = json.get("type").getAsString(); if (type.equals(EmptyBind.BIND_ID)) return new EmptyBind<>(); - if (controller instanceof GamepadController && type.equals(GamepadBind.BIND_ID)) { - return (IBind) GamepadBind.fromJson(json); + if (controller instanceof GamepadController gamepad && type.equals(GamepadBinds.BIND_ID)) { + return GamepadBinds.fromJson(json).map(bind -> (IBind) bind.forGamepad(gamepad)).orElse(new EmptyBind<>()); } else if (controller instanceof JoystickController joystick) { return (IBind) switch (type) { case JoystickButtonBind.BIND_ID -> JoystickButtonBind.fromJson(json, joystick); diff --git a/src/main/java/dev/isxander/controlify/bindings/JoystickAxisBind.java b/src/main/java/dev/isxander/controlify/bindings/JoystickAxisBind.java index e31a400..03f5119 100644 --- a/src/main/java/dev/isxander/controlify/bindings/JoystickAxisBind.java +++ b/src/main/java/dev/isxander/controlify/bindings/JoystickAxisBind.java @@ -39,8 +39,7 @@ public class JoystickAxisBind implements IBind { } @Override - public void draw(PoseStack matrices, int x, int centerY, Controller controller) { - if (controller != joystick) return; + public void draw(PoseStack matrices, int x, int centerY) { JoystickMapping mapping = joystick.mapping(); String type = joystick.type().identifier(); @@ -77,6 +76,11 @@ public class JoystickAxisBind implements IBind { return object; } + @Override + public Controller controller() { + return joystick; + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/src/main/java/dev/isxander/controlify/bindings/JoystickButtonBind.java b/src/main/java/dev/isxander/controlify/bindings/JoystickButtonBind.java index 2c4a432..f40c4c0 100644 --- a/src/main/java/dev/isxander/controlify/bindings/JoystickButtonBind.java +++ b/src/main/java/dev/isxander/controlify/bindings/JoystickButtonBind.java @@ -31,9 +31,7 @@ public class JoystickButtonBind implements IBind { } @Override - public void draw(PoseStack matrices, int x, int centerY, Controller controller) { - if (controller != joystick) return; - + public void draw(PoseStack matrices, int x, int centerY) { String type = joystick.type().identifier(); String button = joystick.mapping().button(buttonIndex).identifier(); var texture = new ResourceLocation("controlify", "textures/gui/joystick/" + type + "/button_" + button + ".png"); @@ -56,6 +54,11 @@ public class JoystickButtonBind implements IBind { return object; } + @Override + public Controller controller() { + return joystick; + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/src/main/java/dev/isxander/controlify/bindings/JoystickHatBind.java b/src/main/java/dev/isxander/controlify/bindings/JoystickHatBind.java index c5d0fe5..5467be6 100644 --- a/src/main/java/dev/isxander/controlify/bindings/JoystickHatBind.java +++ b/src/main/java/dev/isxander/controlify/bindings/JoystickHatBind.java @@ -33,9 +33,7 @@ public class JoystickHatBind implements IBind { } @Override - public void draw(PoseStack matrices, int x, int centerY, Controller controller) { - if (controller != joystick) return; - + public void draw(PoseStack matrices, int x, int centerY) { String type = joystick.type().identifier(); String button = joystick.mapping().button(hatIndex).identifier(); String direction = "centered"; @@ -69,6 +67,11 @@ public class JoystickHatBind implements IBind { return object; } + @Override + public Controller controller() { + return joystick; + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/src/main/java/dev/isxander/controlify/config/gui/GamepadBindController.java b/src/main/java/dev/isxander/controlify/config/gui/GamepadBindController.java index ec9b6b4..5625289 100644 --- a/src/main/java/dev/isxander/controlify/config/gui/GamepadBindController.java +++ b/src/main/java/dev/isxander/controlify/config/gui/GamepadBindController.java @@ -2,6 +2,7 @@ package dev.isxander.controlify.config.gui; import com.mojang.blaze3d.vertex.PoseStack; import dev.isxander.controlify.bindings.GamepadBind; +import dev.isxander.controlify.bindings.GamepadBinds; import dev.isxander.controlify.bindings.IBind; import dev.isxander.controlify.controller.gamepad.GamepadController; import dev.isxander.controlify.controller.gamepad.GamepadState; @@ -56,7 +57,7 @@ public class GamepadBindController implements Controller> { 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); + bind.draw(matrices, getDimension().xLimit() - bind.drawSize().width(), getDimension().centerY()); } } @@ -97,8 +98,9 @@ public class GamepadBindController implements Controller> { var gamepad = control.controller; - for (var bind : GamepadBind.values()) { - if (bind.held(gamepad.state(), gamepad) && !bind.held(gamepad.prevState(), gamepad)) { + for (var bindType : GamepadBinds.values()) { + GamepadBind bind = bindType.forGamepad(gamepad); + if (bind.held(gamepad.state()) && !bind.held(gamepad.prevState())) { control.option().requestSet(bind); awaitingControllerInput = false; gamepad.consumeButtonState(); diff --git a/src/main/java/dev/isxander/controlify/config/gui/JoystickBindController.java b/src/main/java/dev/isxander/controlify/config/gui/JoystickBindController.java index d12ce29..3c87c80 100644 --- a/src/main/java/dev/isxander/controlify/config/gui/JoystickBindController.java +++ b/src/main/java/dev/isxander/controlify/config/gui/JoystickBindController.java @@ -59,7 +59,7 @@ public class JoystickBindController implements Controller> 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); + bind.draw(matrices, getDimension().xLimit() - bind.drawSize().width(), getDimension().centerY()); } } 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 54fa42a..65036e1 100644 --- a/src/main/java/dev/isxander/controlify/config/gui/YACLHelper.java +++ b/src/main/java/dev/isxander/controlify/config/gui/YACLHelper.java @@ -10,6 +10,7 @@ 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.controller.joystick.mapping.UnmappedJoystickMapping; import dev.isxander.controlify.gui.screen.ControllerDeadzoneCalibrationScreen; import dev.isxander.yacl.api.*; import dev.isxander.yacl.gui.controllers.ActionController; @@ -66,6 +67,10 @@ public class YACLHelper { yacl.category(globalCategory.build()); for (var controller : Controller.CONTROLLERS.values()) { +// if (controller instanceof JoystickController joystick && joystick.mapping() instanceof UnmappedJoystickMapping) { +// // PlaceholderCategory for onboarding +// } + var category = ConfigCategory.createBuilder(); category.name(Component.literal(controller.name())); diff --git a/src/main/java/dev/isxander/controlify/controller/ControllerType.java b/src/main/java/dev/isxander/controlify/controller/ControllerType.java index 49d1346..389e4fb 100644 --- a/src/main/java/dev/isxander/controlify/controller/ControllerType.java +++ b/src/main/java/dev/isxander/controlify/controller/ControllerType.java @@ -3,19 +3,20 @@ package dev.isxander.controlify.controller; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonArray; +import dev.isxander.controlify.Controlify; import dev.isxander.controlify.controller.hid.HIDIdentifier; import net.minecraft.client.Minecraft; import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.PackResources; import net.minecraft.server.packs.PackType; import net.minecraft.server.packs.resources.IoSupplier; +import org.apache.commons.io.function.IOSupplier; +import org.quiltmc.json5.JsonReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; +import java.util.*; public class ControllerType { public static final ControllerType UNKNOWN = new ControllerType("Unknown", "unknown"); @@ -45,27 +46,60 @@ public class ControllerType { typeMap = new HashMap<>(); try { - List> dbs = Minecraft.getInstance().getResourceManager().listPacks() - .map(pack -> pack.getResource(PackType.CLIENT_RESOURCES, hidDbLocation)) - .filter(Objects::nonNull) - .toList(); + List packs = Minecraft.getInstance().getResourceManager().listPacks().toList(); - for (var supplier : dbs) { - try (var hidDb = supplier.get()) { - var json = GSON.fromJson(new InputStreamReader(hidDb), JsonArray.class); - for (var typeElement : json) { - var typeObject = typeElement.getAsJsonObject(); + for (var pack : packs) { + String packName = pack.packId(); + IoSupplier isSupplier = pack.getResource(PackType.CLIENT_RESOURCES, hidDbLocation); + if (isSupplier == null) continue; + Controlify.LOGGER.info("Loading controller HID DB from pack " + packName); - ControllerType type = new ControllerType(typeObject.get("name").getAsString(), typeObject.get("identifier").getAsString()); + try (var hidDb = isSupplier.get()) { + JsonReader reader = JsonReader.json5(new InputStreamReader(hidDb)); - int vendorId = typeObject.get("vendor").getAsInt(); - for (var productIdEntry : typeObject.getAsJsonArray("product")) { - int productId = productIdEntry.getAsInt(); + reader.beginArray(); + while (reader.hasNext()) { + String friendlyName = null; + String identifier = null; + int vendorId = -1; + Set productIds = new HashSet<>(); + + reader.beginObject(); + while (reader.hasNext()) { + String name = reader.nextName(); + + switch (name) { + case "name" -> friendlyName = reader.nextString(); + case "identifier" -> identifier = reader.nextString(); + case "vendor" -> vendorId = reader.nextInt(); + case "product" -> { + reader.beginArray(); + while (reader.hasNext()) { + productIds.add(reader.nextInt()); + } + reader.endArray(); + } + default -> { + Controlify.LOGGER.warn("Unknown key in HID DB: " + name + ". Skipping..."); + reader.skipValue(); + } + } + } + reader.endObject(); + + if (friendlyName == null || identifier == null || vendorId == -1 || productIds.isEmpty()) { + Controlify.LOGGER.warn("Invalid entry in HID DB. Skipping..."); + continue; + } + + var type = new ControllerType(friendlyName, identifier); + for (int productId : productIds) { typeMap.put(new HIDIdentifier(vendorId, productId), type); } } + reader.endArray(); } catch (Exception e) { - e.printStackTrace(); + Controlify.LOGGER.error("Failed to load HID DB from pack " + packName, e); } } } catch (Exception e) { diff --git a/src/main/java/dev/isxander/controlify/event/ControlifyEvents.java b/src/main/java/dev/isxander/controlify/event/ControlifyEvents.java index 8a0ef3e..d28e194 100644 --- a/src/main/java/dev/isxander/controlify/event/ControlifyEvents.java +++ b/src/main/java/dev/isxander/controlify/event/ControlifyEvents.java @@ -26,9 +26,9 @@ public class ControlifyEvents { } }); - public static final Event BUTTON_GUIDE_REGISTRY = EventFactory.createArrayBacked(ButtonGuideRegistryEvent.class, callbacks -> registry -> { + public static final Event BUTTON_GUIDE_REGISTRY = EventFactory.createArrayBacked(ButtonGuideRegistryEvent.class, callbacks -> (bindings, registry) -> { for (ButtonGuideRegistryEvent callback : callbacks) { - callback.onRegisterButtonGuide(registry); + callback.onRegisterButtonGuide(bindings, registry); } }); @@ -55,7 +55,7 @@ public class ControlifyEvents { @FunctionalInterface public interface ButtonGuideRegistryEvent { - void onRegisterButtonGuide(ButtonGuideRegistry registry); + void onRegisterButtonGuide(ControllerBindings bindings, ButtonGuideRegistry registry); } @FunctionalInterface diff --git a/src/main/java/dev/isxander/controlify/ingame/guide/ButtonGuideRegistry.java b/src/main/java/dev/isxander/controlify/ingame/guide/ButtonGuideRegistry.java index 6a812fd..14dcecd 100644 --- a/src/main/java/dev/isxander/controlify/ingame/guide/ButtonGuideRegistry.java +++ b/src/main/java/dev/isxander/controlify/ingame/guide/ButtonGuideRegistry.java @@ -1,5 +1,7 @@ package dev.isxander.controlify.ingame.guide; +import dev.isxander.controlify.bindings.ControllerBinding; + public interface ButtonGuideRegistry { - void registerGuideAction(ButtonActionSupplier supplier); + void registerGuideAction(ControllerBinding binding, ActionLocation location, GuideActionNameSupplier supplier); } diff --git a/src/main/java/dev/isxander/controlify/ingame/guide/GuideAction.java b/src/main/java/dev/isxander/controlify/ingame/guide/GuideAction.java index 1b2e360..3c56c2a 100644 --- a/src/main/java/dev/isxander/controlify/ingame/guide/GuideAction.java +++ b/src/main/java/dev/isxander/controlify/ingame/guide/GuideAction.java @@ -4,9 +4,9 @@ import dev.isxander.controlify.bindings.ControllerBinding; import net.minecraft.network.chat.Component; import org.jetbrains.annotations.NotNull; -public record GuideAction(ControllerBinding binding, Component name, ActionLocation location, +public record GuideAction(ControllerBinding binding, Component name, ActionLocation location, ActionPriority priority) implements Comparable { - public GuideAction(ControllerBinding binding, Component name, ActionLocation location) { + public GuideAction(ControllerBinding binding, Component name, ActionLocation location) { this(binding, name, location, ActionPriority.NORMAL); } diff --git a/src/main/java/dev/isxander/controlify/ingame/guide/ButtonActionSupplier.java b/src/main/java/dev/isxander/controlify/ingame/guide/GuideActionNameSupplier.java similarity index 59% rename from src/main/java/dev/isxander/controlify/ingame/guide/ButtonActionSupplier.java rename to src/main/java/dev/isxander/controlify/ingame/guide/GuideActionNameSupplier.java index 3db4990..dcc08ba 100644 --- a/src/main/java/dev/isxander/controlify/ingame/guide/ButtonActionSupplier.java +++ b/src/main/java/dev/isxander/controlify/ingame/guide/GuideActionNameSupplier.java @@ -4,11 +4,12 @@ import dev.isxander.controlify.controller.Controller; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.player.LocalPlayer; +import net.minecraft.network.chat.Component; import net.minecraft.world.phys.HitResult; import java.util.Optional; @FunctionalInterface -public interface ButtonActionSupplier { - Optional supply(Minecraft client, LocalPlayer player, ClientLevel level, HitResult hitResult, Controller controller); +public interface GuideActionNameSupplier { + Optional supply(Minecraft client, LocalPlayer player, ClientLevel level, HitResult hitResult, Controller controller); } diff --git a/src/main/java/dev/isxander/controlify/ingame/guide/InGameButtonGuide.java b/src/main/java/dev/isxander/controlify/ingame/guide/InGameButtonGuide.java index d6df392..e9a497e 100644 --- a/src/main/java/dev/isxander/controlify/ingame/guide/InGameButtonGuide.java +++ b/src/main/java/dev/isxander/controlify/ingame/guide/InGameButtonGuide.java @@ -1,10 +1,12 @@ package dev.isxander.controlify.ingame.guide; import com.mojang.blaze3d.vertex.PoseStack; +import dev.isxander.controlify.bindings.ControllerBinding; import dev.isxander.controlify.controller.Controller; import dev.isxander.controlify.event.ControlifyEvents; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiComponent; +import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.player.LocalPlayer; import net.minecraft.network.chat.Component; import net.minecraft.world.effect.MobEffects; @@ -21,7 +23,7 @@ public class InGameButtonGuide implements ButtonGuideRegistry { private final LocalPlayer player; private final Minecraft minecraft = Minecraft.getInstance(); - private final List guidePredicates = new ArrayList<>(); + private final List guidePredicates = new ArrayList<>(); private final List leftGuides = new ArrayList<>(); private final List rightGuides = new ArrayList<>(); @@ -31,7 +33,7 @@ public class InGameButtonGuide implements ButtonGuideRegistry { this.player = localPlayer; registerDefaultActions(); - ControlifyEvents.BUTTON_GUIDE_REGISTRY.invoker().onRegisterButtonGuide(this); + ControlifyEvents.BUTTON_GUIDE_REGISTRY.invoker().onRegisterButtonGuide(controller.bindings(), this); } public void renderHud(PoseStack poseStack, float tickDelta, int width, int height) { @@ -49,7 +51,7 @@ public class InGameButtonGuide implements ButtonGuideRegistry { int x = 4; int y = 3 + offset; - bind.draw(poseStack, x, y, controller); + bind.draw(poseStack, x, y); int textX = x + drawSize.width() + 2; int textY = y - minecraft.font.lineHeight / 2; @@ -71,7 +73,7 @@ public class InGameButtonGuide implements ButtonGuideRegistry { int x = width - 4 - drawSize.width(); int y = 3 + offset; - bind.draw(poseStack, x, y, controller); + bind.draw(poseStack, x, y); int textX = x - minecraft.font.width(action.name()) - 2; int textY = y - minecraft.font.lineHeight / 2; @@ -92,7 +94,11 @@ public class InGameButtonGuide implements ButtonGuideRegistry { for (var actionPredicate : guidePredicates) { var action = actionPredicate.supply(Minecraft.getInstance(), player, minecraft.level, calculateHitResult(), controller); - if (action.isPresent()) { + if (action.isEmpty()) + continue; + + GuideAction guideAction = action.get(); + if (!guideAction.binding().unbound()) { if (action.get().location() == ActionLocation.LEFT) leftGuides.add(action.get()); else @@ -105,94 +111,97 @@ public class InGameButtonGuide implements ButtonGuideRegistry { } @Override - public void registerGuideAction(ButtonActionSupplier supplier) { - guidePredicates.add(supplier); + public void registerGuideAction(ControllerBinding binding, ActionLocation location, GuideActionNameSupplier supplier) { + guidePredicates.add(new GuideActionSupplier(binding, location, supplier)); } private void registerDefaultActions() { var options = Minecraft.getInstance().options; - registerGuideAction((client, player, level, hitResult, controller) -> { + registerGuideAction(controller.bindings().JUMP, ActionLocation.LEFT, (client, player, level, hitResult, controller) -> { if (player.getAbilities().flying) - return Optional.of(new GuideAction(controller.bindings().JUMP, Component.translatable("controlify.guide.fly_up"), ActionLocation.LEFT)); + return Optional.of(Component.translatable("controlify.guide.fly_up")); if (player.isOnGround()) - return Optional.of(new GuideAction(controller.bindings().JUMP, Component.translatable("key.jump"), ActionLocation.LEFT)); + return Optional.of(Component.translatable("key.jump")); if (player.isInWater()) - return Optional.of(new GuideAction(controller.bindings().JUMP, Component.translatable("controlify.guide.swim_up"), ActionLocation.LEFT)); + return Optional.of(Component.translatable("controlify.guide.swim_up")); if (!player.isOnGround() && !player.isFallFlying() && !player.isInWater() && !player.hasEffect(MobEffects.LEVITATION)) { var chestStack = player.getItemBySlot(EquipmentSlot.CHEST); if (chestStack.is(Items.ELYTRA) && ElytraItem.isFlyEnabled(chestStack)) - return Optional.of(new GuideAction(controller.bindings().JUMP, Component.translatable("controlify.guide.start_elytra"), ActionLocation.LEFT)); + return Optional.of(Component.translatable("controlify.guide.start_elytra")); } return Optional.empty(); }); - registerGuideAction((client, player, level, hitResult, controller) -> { + registerGuideAction(controller.bindings().SNEAK, ActionLocation.LEFT, (client, player, level, hitResult, controller) -> { if (player.getVehicle() != null) - return Optional.of(new GuideAction(controller.bindings().SNEAK, Component.translatable("controlify.guide.dismount"), ActionLocation.LEFT)); + return Optional.of(Component.translatable("controlify.guide.dismount")); if (player.getAbilities().flying) - return Optional.of(new GuideAction(controller.bindings().SNEAK, Component.translatable("controlify.guide.fly_down"), ActionLocation.LEFT)); + return Optional.of(Component.translatable("controlify.guide.fly_down")); if (player.isInWater()) - return Optional.of(new GuideAction(controller.bindings().SNEAK, Component.translatable("controlify.guide.swim_down"), ActionLocation.LEFT)); + return Optional.of(Component.translatable("controlify.guide.swim_down")); if (controller.config().toggleSneak) { if (player.input.shiftKeyDown) - return Optional.of(new GuideAction(controller.bindings().SNEAK, Component.translatable("controlify.guide.stop_sneaking"), ActionLocation.LEFT)); + return Optional.of(Component.translatable("controlify.guide.stop_sneaking")); else - return Optional.of(new GuideAction(controller.bindings().SNEAK, Component.translatable("controlify.guide.start_sneaking"), ActionLocation.LEFT)); + return Optional.of(Component.translatable("controlify.guide.start_sneaking")); } else { if (!player.input.shiftKeyDown) - return Optional.of(new GuideAction(controller.bindings().SNEAK, Component.translatable("controlify.guide.sneak"), ActionLocation.LEFT)); + return Optional.of(Component.translatable("controlify.guide.sneak")); } return Optional.empty(); }); - registerGuideAction((client, player, level, hitResult, controller) -> { + registerGuideAction(controller.bindings().SPRINT, ActionLocation.LEFT, (client, player, level, hitResult, controller) -> { if (!options.keySprint.isDown()) { if (!player.input.getMoveVector().equals(Vec2.ZERO)) { if (player.isUnderWater()) - return Optional.of(new GuideAction(controller.bindings().SPRINT, Component.translatable("controlify.guide.start_swimming"), ActionLocation.LEFT)); - return Optional.of(new GuideAction(controller.bindings().SPRINT, Component.translatable("controlify.guide.start_sprinting"), ActionLocation.LEFT)); + return Optional.of(Component.translatable("controlify.guide.start_swimming")); + return Optional.of(Component.translatable("controlify.guide.start_sprinting")); } } else if (controller.config().toggleSprint) { if (player.isUnderWater()) - return Optional.of(new GuideAction(controller.bindings().SPRINT, Component.translatable("controlify.guide.stop_swimming"), ActionLocation.LEFT)); - return Optional.of(new GuideAction(controller.bindings().SPRINT, Component.translatable("controlify.guide.stop_sprinting"), ActionLocation.LEFT)); + return Optional.of(Component.translatable("controlify.guide.stop_swimming")); + return Optional.of(Component.translatable("controlify.guide.stop_sprinting")); } return Optional.empty(); }); - registerGuideAction((client, player, level, hitResult, controller) -> { + registerGuideAction(controller.bindings().INVENTORY, ActionLocation.RIGHT, (client, player, level, hitResult, controller) -> { if (client.screen == null) - return Optional.of(new GuideAction(controller.bindings().INVENTORY, Component.translatable("controlify.guide.inventory"), ActionLocation.RIGHT)); + return Optional.of(Component.translatable("controlify.guide.inventory")); return Optional.empty(); }); - registerGuideAction((client, player, level, hitResult, controller) -> { + registerGuideAction(controller.bindings().ATTACK, ActionLocation.RIGHT, (client, player, level, hitResult, controller) -> { if (hitResult.getType() == HitResult.Type.ENTITY) - return Optional.of(new GuideAction(controller.bindings().ATTACK, Component.translatable("controlify.guide.attack"), ActionLocation.RIGHT)); + return Optional.of(Component.translatable("controlify.guide.attack")); if (hitResult.getType() == HitResult.Type.BLOCK) - return Optional.of(new GuideAction(controller.bindings().ATTACK, Component.translatable("controlify.guide.break"), ActionLocation.RIGHT)); + return Optional.of(Component.translatable("controlify.guide.break")); return Optional.empty(); }); - registerGuideAction((client, player, level, hitResult, controller) -> { + registerGuideAction(controller.bindings().USE, ActionLocation.RIGHT, (client, player, level, hitResult, controller) -> { if (hitResult.getType() == HitResult.Type.ENTITY) - return Optional.of(new GuideAction(controller.bindings().USE, Component.translatable("controlify.guide.interact"), ActionLocation.RIGHT)); + if (player.isSpectator()) + return Optional.of(Component.translatable("controlify.guide.spectate")); + else + return Optional.of(Component.translatable("controlify.guide.interact")); if (hitResult.getType() == HitResult.Type.BLOCK || player.hasItemInSlot(EquipmentSlot.MAINHAND) || player.hasItemInSlot(EquipmentSlot.OFFHAND)) - return Optional.of(new GuideAction(controller.bindings().USE, Component.translatable("controlify.guide.use"), ActionLocation.RIGHT)); + return Optional.of(Component.translatable("controlify.guide.use")); return Optional.empty(); }); - registerGuideAction((client, player, level, hitResult, controller) -> { + registerGuideAction(controller.bindings().DROP, ActionLocation.RIGHT, (client, player, level, hitResult, controller) -> { if (player.hasItemInSlot(EquipmentSlot.MAINHAND) || player.hasItemInSlot(EquipmentSlot.OFFHAND)) - return Optional.of(new GuideAction(controller.bindings().DROP, Component.translatable("controlify.guide.drop"), ActionLocation.RIGHT)); + return Optional.of(Component.translatable("controlify.guide.drop")); return Optional.empty(); }); - registerGuideAction((client, player, level, hitResult, controller) -> { + registerGuideAction(controller.bindings().SWAP_HANDS, ActionLocation.RIGHT, (client, player, level, hitResult, controller) -> { if (player.hasItemInSlot(EquipmentSlot.MAINHAND) || player.hasItemInSlot(EquipmentSlot.OFFHAND)) - return Optional.of(new GuideAction(controller.bindings().SWAP_HANDS, Component.translatable("controlify.guide.swap_hands"), ActionLocation.RIGHT)); + return Optional.of(Component.translatable("controlify.guide.swap_hands")); return Optional.empty(); }); - registerGuideAction((client, player, level, hitResult, controller) -> { + registerGuideAction(controller.bindings().PICK_BLOCK, ActionLocation.RIGHT, (client, player, level, hitResult, controller) -> { if (hitResult.getType() == HitResult.Type.BLOCK && player.isCreative()) - return Optional.of(new GuideAction(controller.bindings().PICK_BLOCK, Component.translatable("controlify.guide.pick_block"), ActionLocation.RIGHT)); + return Optional.of(Component.translatable("controlify.guide.pick_block")); return Optional.empty(); }); } @@ -223,4 +232,10 @@ public class InGameButtonGuide implements ButtonGuideRegistry { } } + private record GuideActionSupplier(ControllerBinding binding, ActionLocation location, GuideActionNameSupplier nameSupplier) { + public Optional supply(Minecraft client, LocalPlayer player, ClientLevel level, HitResult hitResult, Controller controller) { + return nameSupplier.supply(client, player, level, hitResult, controller) + .map(name -> new GuideAction(binding, name, location)); + } + } } diff --git a/src/main/resources/assets/controlify/hiddb.json5 b/src/main/resources/assets/controlify/hiddb.json5 index fb7db25..87e0958 100644 --- a/src/main/resources/assets/controlify/hiddb.json5 +++ b/src/main/resources/assets/controlify/hiddb.json5 @@ -1,43 +1,42 @@ -// THIS FILE IS PARSED BY LENIENT GSON PARSER AND IS NOT JSON5 COMPLIANT! [ -// { -// "name": "Xbox One Controller", -// "identifier": "xbox_one", -// -// "vendor": 1118, // 0x45e -// "product": [ -// 767, // 0x2ff -// 746, // 0x2ea -// 2834, // 0xb12 -// 733, // 0x2dd -// 739, // 0x2e3 -// 742, // 0x2e6 -// 765, // 0x2fd -// 721, // 0x2d1 -// 649, // 0x289 -// 514, // 0x202 -// 645, // 0x285 -// 648 // 0x288 -// ] -// }, + { + "name": "Xbox One Controller", + "identifier": "xbox_one", + + "vendor": 0x45e, + "product": [ + 0x2ff, + 0x2ea, + 0xb12, + 0x2dd, + 0x2e3, + 0x2e6, + 0x2fd, + 0x2d1, + 0x289, + 0x202, + 0x285, + 0x288, + ] + }, { "name": "Dualshock 4 Controller", "identifier": "dualshock4", - "vendor": 1356, // 0x54c + "vendor": 0x54c, "product": [ - 1476, // 0x5c4 - 2508, // 0x9cc - 2976 // 0xba0 + 0x5c4, + 0x9cc, + 0xba0, ] }, { "name": "Steam Deck", "identifier": "steam_deck", - "vendor": 10462, // 0x28de + "vendor": 0x28de, "product": [ - 4613 // 0x1205 + 0x1205, ] } ]