From 0d9ddc27fca93dbc88a71770f3e3dc80b26a0883 Mon Sep 17 00:00:00 2001 From: isXander Date: Wed, 29 Mar 2023 17:56:43 +0100 Subject: [PATCH] improve bindings --- build.gradle.kts | 1 + gradle/libs.versions.toml | 2 +- .../api/bind/ControlifyBindingsApi.java | 7 + .../api/bind/ControllerBindingBuilder.java | 38 ++ .../bindings/ControllerBinding.java | 114 +++++- .../bindings/ControllerBindings.java | 378 +++++++++++++++--- .../controlify/config/ControlifyConfig.java | 24 +- .../controlify/config/gui/YACLHelper.java | 46 ++- .../fapi/KeyBindingRegistryImplAccessor.java | 16 + .../bind/ToggleKeyMappingAccessor.java | 13 + .../feature/screenop/MinecraftMixin.java | 19 + .../mixins/feature/screenop/ScreenMixin.java | 6 - .../CreativeModeInventoryScreenAccessor.java | 4 +- .../CreativeModeInventoryScreenProcessor.java | 4 +- .../assets/controlify/lang/en_us.json | 7 +- src/main/resources/controlify.mixins.json | 3 + .../controlify/test/ControlifyTests.java | 6 +- 17 files changed, 606 insertions(+), 82 deletions(-) create mode 100644 src/main/java/dev/isxander/controlify/api/bind/ControllerBindingBuilder.java create mode 100644 src/main/java/dev/isxander/controlify/mixins/compat/fapi/KeyBindingRegistryImplAccessor.java create mode 100644 src/main/java/dev/isxander/controlify/mixins/feature/bind/ToggleKeyMappingAccessor.java create mode 100644 src/main/java/dev/isxander/controlify/mixins/feature/screenop/MinecraftMixin.java diff --git a/build.gradle.kts b/build.gradle.kts index 6e8f52f..2771bfd 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -68,6 +68,7 @@ dependencies { listOf( "fabric-resource-loader-v0", "fabric-lifecycle-events-v1", + "fabric-key-binding-api-v1", // sodium requirements "fabric-rendering-data-attachment-v1", diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index edc6fc7..f5e17eb 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -12,7 +12,7 @@ quilt_mappings = "1" fabric_loader = "0.14.17" fabric_api = "0.76.0+1.19.4" mixin_extras = "0.2.0-beta.1" -yet_another_config_lib = "2.3.0" +yet_another_config_lib = "2.3.1" mod_menu = "6.1.0-rc.1" hid4java = "0.7.0" quilt_json5 = "1.0.3" diff --git a/src/main/java/dev/isxander/controlify/api/bind/ControlifyBindingsApi.java b/src/main/java/dev/isxander/controlify/api/bind/ControlifyBindingsApi.java index 8f68fd6..0e4f7e3 100644 --- a/src/main/java/dev/isxander/controlify/api/bind/ControlifyBindingsApi.java +++ b/src/main/java/dev/isxander/controlify/api/bind/ControlifyBindingsApi.java @@ -8,6 +8,7 @@ import net.minecraft.client.KeyMapping; import net.minecraft.resources.ResourceLocation; import java.util.function.BooleanSupplier; +import java.util.function.UnaryOperator; /** * Handles registering new bindings for controllers. @@ -15,6 +16,8 @@ import java.util.function.BooleanSupplier; * Should be called within {@link dev.isxander.controlify.api.entrypoint.ControlifyEntrypoint#onControlifyPreInit(ControlifyApi)} */ public interface ControlifyBindingsApi { + BindingSupplier registerBind(ResourceLocation id, UnaryOperator> builder); + /** * Registers a custom binding for all available controllers. * If the controller is not a gamepad, the binding with be empty by default. @@ -23,6 +26,7 @@ public interface ControlifyBindingsApi { * @param id the identifier for the binding, the namespace should be your modid. * @return the binding supplier to fetch the binding for a specific controller. */ + @Deprecated BindingSupplier registerBind(GamepadBinds bind, ResourceLocation id); /** @@ -35,8 +39,11 @@ public interface ControlifyBindingsApi { * @param toggleOverride a supplier that returns true if the vanilla keybind should be treated as a {@link net.minecraft.client.ToggleKeyMapping} * @return the binding supplier to fetch the binding for a specific controller. */ + @Deprecated BindingSupplier registerBind(GamepadBinds bind, ResourceLocation id, KeyMapping override, BooleanSupplier toggleOverride); + void excludeVanillaBind(KeyMapping... keyMapping); + static ControlifyBindingsApi get() { return ControllerBindings.Api.INSTANCE; } diff --git a/src/main/java/dev/isxander/controlify/api/bind/ControllerBindingBuilder.java b/src/main/java/dev/isxander/controlify/api/bind/ControllerBindingBuilder.java new file mode 100644 index 0000000..90f4da7 --- /dev/null +++ b/src/main/java/dev/isxander/controlify/api/bind/ControllerBindingBuilder.java @@ -0,0 +1,38 @@ +package dev.isxander.controlify.api.bind; + +import dev.isxander.controlify.bindings.ControllerBinding; +import dev.isxander.controlify.bindings.GamepadBinds; +import dev.isxander.controlify.bindings.IBind; +import dev.isxander.controlify.controller.Controller; +import dev.isxander.controlify.controller.ControllerState; +import net.minecraft.client.KeyMapping; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; + +import java.util.function.BooleanSupplier; + +public interface ControllerBindingBuilder { + static ControllerBindingBuilder create(Controller controller) { + return new ControllerBinding.ControllerBindingBuilderImpl<>(controller); + } + + ControllerBindingBuilder identifier(ResourceLocation id); + + ControllerBindingBuilder identifier(String namespace, String path); + + ControllerBindingBuilder defaultBind(IBind bind); + + ControllerBindingBuilder defaultBind(GamepadBinds gamepadBind); + + ControllerBindingBuilder name(Component name); + + ControllerBindingBuilder description(Component description); + + ControllerBindingBuilder category(Component category); + + ControllerBindingBuilder vanillaOverride(KeyMapping keyMapping, BooleanSupplier toggleable); + + ControllerBindingBuilder vanillaOverride(KeyMapping keyMapping); + + ControllerBinding build(); +} diff --git a/src/main/java/dev/isxander/controlify/bindings/ControllerBinding.java b/src/main/java/dev/isxander/controlify/bindings/ControllerBinding.java index 4973091..57e2403 100644 --- a/src/main/java/dev/isxander/controlify/bindings/ControllerBinding.java +++ b/src/main/java/dev/isxander/controlify/bindings/ControllerBinding.java @@ -1,5 +1,6 @@ package dev.isxander.controlify.bindings; +import dev.isxander.controlify.api.bind.ControllerBindingBuilder; import dev.isxander.controlify.controller.Controller; import dev.isxander.controlify.controller.ControllerState; import dev.isxander.controlify.controller.gamepad.GamepadController; @@ -7,6 +8,8 @@ import net.minecraft.client.KeyMapping; import net.minecraft.locale.Language; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; +import org.apache.commons.lang3.Validate; +import org.jetbrains.annotations.ApiStatus; import java.util.HashMap; import java.util.HashSet; @@ -19,11 +22,22 @@ public class ControllerBinding { private IBind bind; private final IBind defaultBind; private final ResourceLocation id; - private final Component name, description; + private final Component name, description, category; private final KeyMappingOverride override; private static final Map, Set>> pressedBinds = new HashMap<>(); + private ControllerBinding(Controller controller, IBind defaultBind, ResourceLocation id, KeyMappingOverride vanillaOverride, Component name, Component description, Component category) { + this.controller = controller; + this.bind = this.defaultBind = defaultBind; + this.id = id; + this.override = vanillaOverride; + this.name = name; + this.description = description; + this.category = category; + } + + @Deprecated public ControllerBinding(Controller controller, IBind defaultBind, ResourceLocation id, KeyMapping override, BooleanSupplier toggleOverride) { this.controller = controller; this.bind = this.defaultBind = defaultBind; @@ -32,17 +46,21 @@ public class ControllerBinding { var descKey = "controlify.binding." + id.getNamespace() + "." + id.getPath() + ".desc"; this.description = Language.getInstance().has(descKey) ? Component.translatable(descKey) : Component.empty(); this.override = override != null ? new KeyMappingOverride(override, toggleOverride) : null; + this.category = null; } + @Deprecated public ControllerBinding(Controller controller, IBind defaultBind, ResourceLocation id) { this(controller, defaultBind, id, null, () -> false); } + @Deprecated @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); } + @Deprecated public ControllerBinding(Controller controller, GamepadBinds defaultBind, ResourceLocation id) { this(controller, defaultBind, id, null, () -> false); } @@ -109,6 +127,10 @@ public class ControllerBinding { return description; } + public Component category() { + return category; + } + public boolean unbound() { return bind instanceof EmptyBind; } @@ -140,4 +162,94 @@ public class ControllerBinding { public record KeyMappingOverride(KeyMapping keyMapping, BooleanSupplier toggleable) { } + + @ApiStatus.Internal + public static final class ControllerBindingBuilderImpl implements ControllerBindingBuilder { + private final Controller controller; + private IBind bind; + private ResourceLocation id; + private Component name = null, description = null, category = null; + private KeyMappingOverride override = null; + + public ControllerBindingBuilderImpl(Controller controller) { + this.controller = controller; + } + + @Override + public ControllerBindingBuilder identifier(ResourceLocation id) { + this.id = id; + return this; + } + + @Override + public ControllerBindingBuilder identifier(String namespace, String path) { + return identifier(new ResourceLocation(namespace, path)); + } + + @Override + public ControllerBindingBuilder defaultBind(IBind bind) { + this.bind = bind; + return this; + } + + @Override + @SuppressWarnings("unchecked") + public ControllerBindingBuilder defaultBind(GamepadBinds gamepadBind) { + if (controller instanceof GamepadController gamepad) { + this.bind = (IBind) gamepadBind.forGamepad(gamepad); + } else { + this.bind = new EmptyBind<>(); + } + return this; + } + + @Override + public ControllerBindingBuilder name(Component name) { + this.name = name; + return this; + } + + @Override + public ControllerBindingBuilder description(Component description) { + this.description = description; + return this; + } + + @Override + public ControllerBindingBuilder category(Component category) { + this.category = category; + return this; + } + + @Override + public ControllerBindingBuilder vanillaOverride(KeyMapping keyMapping, BooleanSupplier toggleable) { + this.override = new KeyMappingOverride(keyMapping, toggleable); + return this; + } + + @Override + public ControllerBindingBuilder vanillaOverride(KeyMapping keyMapping) { + return vanillaOverride(keyMapping, () -> false); + } + + @Override + public ControllerBinding build() { + Validate.notNull(id, "Identifier must be set"); + Validate.notNull(bind, "Default bind must be set"); + Validate.notNull(category, "Category must be set"); + + if (name == null) + name = Component.translatable("controlify.binding." + id.getNamespace() + "." + id.getPath()); + if (description == null) { + var descKey = "controlify.binding." + id.getNamespace() + "." + id.getPath() + ".desc"; + if (Language.getInstance().has(descKey)) { + description = Component.translatable(descKey); + } else { + description = Component.empty(); + } + } + + return new ControllerBinding<>(controller, bind, id, override, name, description, category); + } + } } diff --git a/src/main/java/dev/isxander/controlify/bindings/ControllerBindings.java b/src/main/java/dev/isxander/controlify/bindings/ControllerBindings.java index f96172f..bce38b9 100644 --- a/src/main/java/dev/isxander/controlify/bindings/ControllerBindings.java +++ b/src/main/java/dev/isxander/controlify/bindings/ControllerBindings.java @@ -4,20 +4,36 @@ import com.google.gson.JsonObject; import dev.isxander.controlify.Controlify; import dev.isxander.controlify.InputMode; import dev.isxander.controlify.api.bind.ControlifyBindingsApi; +import dev.isxander.controlify.api.bind.ControllerBindingBuilder; import dev.isxander.controlify.controller.Controller; import dev.isxander.controlify.controller.ControllerState; import dev.isxander.controlify.api.event.ControlifyEvents; +import dev.isxander.controlify.mixins.compat.fapi.KeyBindingRegistryImplAccessor; import dev.isxander.controlify.mixins.feature.bind.KeyMappingAccessor; +import dev.isxander.controlify.mixins.feature.bind.ToggleKeyMappingAccessor; +import net.minecraft.ChatFormatting; import net.minecraft.client.KeyMapping; import net.minecraft.client.Minecraft; +import net.minecraft.client.ToggleKeyMapping; +import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import java.util.*; import java.util.function.BooleanSupplier; import java.util.function.Function; +import java.util.function.UnaryOperator; public class ControllerBindings { private static final Map, ControllerBinding>> CUSTOM_BINDS = new LinkedHashMap<>(); + private static final Set EXCLUDED_VANILLA_BINDS = new HashSet<>(); + + public static final Component MOVEMENT_CATEGORY = Component.translatable("key.categories.movement"); + public static final Component GAMEPLAY_CATEGORY = Component.translatable("key.categories.gameplay"); + public static final Component INVENTORY_CATEGORY = Component.translatable("key.categories.inventory"); + public static final Component CREATIVE_CATEGORY = Component.translatable("key.categories.creative"); + public static final Component VMOUSE_CATEGORY = Component.translatable("controlify.binding_category.vmouse"); + public static final Component GUI_CATEGORY = Component.translatable("controlify.binding_category.gui"); + public static final Component MISC_CATEGORY = Component.translatable("key.categories.misc"); public final ControllerBinding WALK_FORWARD, WALK_BACKWARD, WALK_LEFT, WALK_RIGHT, @@ -47,65 +63,271 @@ public class ControllerBindings { CYCLE_OPT_FORWARD, CYCLE_OPT_BACKWARD; private final Map> registry = new LinkedHashMap<>(); + private final Controller controller; public ControllerBindings(Controller controller) { this.controller = controller; var options = Minecraft.getInstance().options; - register(WALK_FORWARD = new ControllerBinding<>(controller, 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"))); - 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(GUI_ABSTRACT_ACTION_1 = new ControllerBinding<>(controller, GamepadBinds.X_BUTTON, new ResourceLocation("controlify", "gui_abstract_action_1"))); - register(GUI_ABSTRACT_ACTION_2 = new ControllerBinding<>(controller, GamepadBinds.Y_BUTTON, new ResourceLocation("controlify", "gui_abstract_action_2"))); - 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, 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(CYCLE_OPT_FORWARD = new ControllerBinding<>(controller, GamepadBinds.RIGHT_STICK_RIGHT, new ResourceLocation("controlify", "cycle_opt_forward"))); - register(CYCLE_OPT_BACKWARD = new ControllerBinding<>(controller, GamepadBinds.RIGHT_STICK_LEFT, new ResourceLocation("controlify", "cycle_opt_backward"))); + register(WALK_FORWARD = ControllerBindingBuilder.create(controller) + .identifier("controlify", "walk_forward") + .defaultBind(GamepadBinds.LEFT_STICK_FORWARD) + .category(MOVEMENT_CATEGORY) + .build()); + register(WALK_BACKWARD = ControllerBindingBuilder.create(controller) + .identifier("controlify", "walk_backward") + .defaultBind(GamepadBinds.LEFT_STICK_BACKWARD) + .category(MOVEMENT_CATEGORY) + .build()); + register(WALK_LEFT = ControllerBindingBuilder.create(controller) + .identifier("controlify", "strafe_left") + .defaultBind(GamepadBinds.LEFT_STICK_LEFT) + .category(MOVEMENT_CATEGORY) + .build()); + register(WALK_RIGHT = ControllerBindingBuilder.create(controller) + .identifier("controlify", "strafe_right") + .defaultBind(GamepadBinds.LEFT_STICK_RIGHT) + .category(MOVEMENT_CATEGORY) + .build()); + register(LOOK_UP = ControllerBindingBuilder.create(controller) + .identifier("controlify", "look_up") + .defaultBind(GamepadBinds.RIGHT_STICK_FORWARD) + .category(MOVEMENT_CATEGORY) + .build()); + register(LOOK_DOWN = ControllerBindingBuilder.create(controller) + .identifier("controlify", "look_down") + .defaultBind(GamepadBinds.RIGHT_STICK_BACKWARD) + .category(MOVEMENT_CATEGORY) + .build()); + register(LOOK_LEFT = ControllerBindingBuilder.create(controller) + .identifier("controlify", "look_left") + .defaultBind(GamepadBinds.RIGHT_STICK_LEFT) + .category(MOVEMENT_CATEGORY) + .build()); + register(LOOK_RIGHT = ControllerBindingBuilder.create(controller) + .identifier("controlify", "look_right") + .defaultBind(GamepadBinds.RIGHT_STICK_RIGHT) + .category(MOVEMENT_CATEGORY) + .build()); + register(JUMP = ControllerBindingBuilder.create(controller) + .identifier("controlify", "jump") + .defaultBind(GamepadBinds.A_BUTTON) + .category(MOVEMENT_CATEGORY) + .vanillaOverride(options.keyJump, () -> false) + .build()); + register(SPRINT = ControllerBindingBuilder.create(controller) + .identifier("controlify", "sprint") + .defaultBind(GamepadBinds.LEFT_STICK_PRESS) + .category(MOVEMENT_CATEGORY) + .vanillaOverride(options.keySprint, () -> controller.config().toggleSprint) + .build()); + register(SNEAK = ControllerBindingBuilder.create(controller) + .identifier("controlify", "sneak") + .defaultBind(GamepadBinds.RIGHT_STICK_PRESS) + .category(MOVEMENT_CATEGORY) + .vanillaOverride(options.keyShift, () -> controller.config().toggleSneak) + .build()); + register(ATTACK = ControllerBindingBuilder.create(controller) + .identifier("controlify", "attack") + .defaultBind(GamepadBinds.RIGHT_TRIGGER) + .category(GAMEPLAY_CATEGORY) + .vanillaOverride(options.keyAttack, () -> false) + .build()); + register(USE = ControllerBindingBuilder.create(controller) + .identifier("controlify", "use") + .defaultBind(GamepadBinds.LEFT_TRIGGER) + .category(GAMEPLAY_CATEGORY) + .vanillaOverride(options.keyUse, () -> false) + .build()); + register(DROP = ControllerBindingBuilder.create(controller) + .identifier("controlify", "drop") + .defaultBind(GamepadBinds.DPAD_DOWN) + .category(GAMEPLAY_CATEGORY) + .build()); + register(NEXT_SLOT = ControllerBindingBuilder.create(controller) + .identifier("controlify", "next_slot") + .defaultBind(GamepadBinds.RIGHT_BUMPER) + .category(INVENTORY_CATEGORY) + .build()); + register(PREV_SLOT = ControllerBindingBuilder.create(controller) + .identifier("controlify", "prev_slot") + .defaultBind(GamepadBinds.LEFT_BUMPER) + .category(INVENTORY_CATEGORY) + .build()); + register(PAUSE = ControllerBindingBuilder.create(controller) + .identifier("controlify", "pause") + .defaultBind(GamepadBinds.START) + .category(GAMEPLAY_CATEGORY) + .build()); + register(INVENTORY = ControllerBindingBuilder.create(controller) + .identifier("controlify", "inventory") + .defaultBind(GamepadBinds.Y_BUTTON) + .category(INVENTORY_CATEGORY) + .vanillaOverride(options.keyInventory, () -> false) + .build()); + register(CHANGE_PERSPECTIVE = ControllerBindingBuilder.create(controller) + .identifier("controlify", "change_perspective") + .defaultBind(GamepadBinds.BACK) + .category(GAMEPLAY_CATEGORY) + .vanillaOverride(options.keyTogglePerspective, () -> false) + .build()); + register(SWAP_HANDS = ControllerBindingBuilder.create(controller) + .identifier("controlify", "swap_hands") + .defaultBind(GamepadBinds.X_BUTTON) + .category(INVENTORY_CATEGORY) + .vanillaOverride(options.keySwapOffhand, () -> false) + .build()); + register(OPEN_CHAT = ControllerBindingBuilder.create(controller) + .identifier("controlify", "open_chat") + .defaultBind(GamepadBinds.DPAD_UP) + .category(MISC_CATEGORY) + .vanillaOverride(options.keyChat, () -> false) + .build()); + register(GUI_PRESS = ControllerBindingBuilder.create(controller) + .identifier("controlify", "gui_press") + .defaultBind(GamepadBinds.A_BUTTON) + .category(GUI_CATEGORY) + .build()); + register(GUI_BACK = ControllerBindingBuilder.create(controller) + .identifier("controlify", "gui_back") + .defaultBind(GamepadBinds.B_BUTTON) + .category(GUI_CATEGORY) + .build()); + register(GUI_NEXT_TAB = ControllerBindingBuilder.create(controller) + .identifier("controlify", "gui_next_tab") + .defaultBind(GamepadBinds.RIGHT_BUMPER) + .category(GUI_CATEGORY) + .build()); + register(GUI_PREV_TAB = ControllerBindingBuilder.create(controller) + .identifier("controlify", "gui_prev_tab") + .defaultBind(GamepadBinds.LEFT_BUMPER) + .category(GUI_CATEGORY) + .build()); + register(GUI_ABSTRACT_ACTION_1 = ControllerBindingBuilder.create(controller) + .identifier("controlify", "gui_abstract_action_1") + .defaultBind(GamepadBinds.X_BUTTON) + .category(GUI_CATEGORY) + .build()); + register(GUI_ABSTRACT_ACTION_2 = ControllerBindingBuilder.create(controller) + .identifier("controlify", "gui_abstract_action_1") + .defaultBind(GamepadBinds.Y_BUTTON) + .category(GUI_CATEGORY) + .build()); + register(PICK_BLOCK = ControllerBindingBuilder.create(controller) + .identifier("controlify", "pick_block") + .defaultBind(GamepadBinds.DPAD_LEFT) + .category(GAMEPLAY_CATEGORY) + .vanillaOverride(options.keyPickItem, () -> false) + .build()); + register(TOGGLE_HUD_VISIBILITY = ControllerBindingBuilder.create(controller) + .identifier("controlify", "toggle_hud_visibility") + .defaultBind(new EmptyBind<>()) + .category(MISC_CATEGORY) + .build()); + register(SHOW_PLAYER_LIST = ControllerBindingBuilder.create(controller) + .identifier("controlify", "show_player_list") + .defaultBind(GamepadBinds.DPAD_RIGHT) + .category(MISC_CATEGORY) + .vanillaOverride(options.keyPlayerList, () -> false) + .build()); + register(VMOUSE_MOVE_UP = ControllerBindingBuilder.create(controller) + .identifier("controlify", "vmouse_move_up") + .defaultBind(GamepadBinds.LEFT_STICK_FORWARD) + .category(VMOUSE_CATEGORY) + .build()); + register(VMOUSE_MOVE_DOWN = ControllerBindingBuilder.create(controller) + .identifier("controlify", "vmouse_move_down") + .defaultBind(GamepadBinds.LEFT_STICK_BACKWARD) + .category(VMOUSE_CATEGORY) + .build()); + register(VMOUSE_MOVE_LEFT = ControllerBindingBuilder.create(controller) + .identifier("controlify", "vmouse_move_left") + .defaultBind(GamepadBinds.LEFT_STICK_LEFT) + .category(VMOUSE_CATEGORY) + .build()); + register(VMOUSE_MOVE_RIGHT = ControllerBindingBuilder.create(controller) + .identifier("controlify", "vmouse_move_right") + .defaultBind(GamepadBinds.LEFT_STICK_RIGHT) + .category(VMOUSE_CATEGORY) + .build()); + register(VMOUSE_LCLICK = ControllerBindingBuilder.create(controller) + .identifier("controlify", "vmouse_lclick") + .defaultBind(GamepadBinds.A_BUTTON) + .category(VMOUSE_CATEGORY) + .build()); + register(VMOUSE_RCLICK = ControllerBindingBuilder.create(controller) + .identifier("controlify", "vmouse_rclick") + .defaultBind(GamepadBinds.X_BUTTON) + .category(VMOUSE_CATEGORY) + .build()); + register(VMOUSE_SHIFT_CLICK = ControllerBindingBuilder.create(controller) + .identifier("controlify", "vmouse_shift_click") + .defaultBind(GamepadBinds.Y_BUTTON) + .category(VMOUSE_CATEGORY) + .build()); + register(VMOUSE_SCROLL_UP = ControllerBindingBuilder.create(controller) + .identifier("controlify", "vmouse_scroll_up") + .defaultBind(GamepadBinds.RIGHT_STICK_FORWARD) + .category(VMOUSE_CATEGORY) + .build()); + register(VMOUSE_SCROLL_DOWN = ControllerBindingBuilder.create(controller) + .identifier("controlify", "vmouse_scroll_down") + .defaultBind(GamepadBinds.RIGHT_STICK_BACKWARD) + .category(VMOUSE_CATEGORY) + .build()); + register(VMOUSE_ESCAPE = ControllerBindingBuilder.create(controller) + .identifier("controlify", "vmouse_escape") + .defaultBind(GamepadBinds.B_BUTTON) + .category(VMOUSE_CATEGORY) + .build()); + register(VMOUSE_SHIFT = ControllerBindingBuilder.create(controller) + .identifier("controlify", "vmouse_shift") + .defaultBind(GamepadBinds.LEFT_STICK_PRESS) + .category(VMOUSE_CATEGORY) + .build()); + register(VMOUSE_TOGGLE = ControllerBindingBuilder.create(controller) + .identifier("controlify", "vmouse_toggle") + .defaultBind(GamepadBinds.BACK) + .category(VMOUSE_CATEGORY) + .build()); + register(GUI_NAVI_UP = ControllerBindingBuilder.create(controller) + .identifier("controlify", "gui_navi_up") + .defaultBind(GamepadBinds.LEFT_STICK_FORWARD) + .category(GUI_CATEGORY) + .build()); + register(GUI_NAVI_DOWN = ControllerBindingBuilder.create(controller) + .identifier("controlify", "gui_navi_down") + .defaultBind(GamepadBinds.LEFT_STICK_BACKWARD) + .category(GUI_CATEGORY) + .build()); + register(GUI_NAVI_LEFT = ControllerBindingBuilder.create(controller) + .identifier("controlify", "gui_navi_left") + .defaultBind(GamepadBinds.LEFT_STICK_LEFT) + .category(GUI_CATEGORY) + .build()); + register(GUI_NAVI_RIGHT = ControllerBindingBuilder.create(controller) + .identifier("controlify", "gui_navi_right") + .defaultBind(GamepadBinds.LEFT_STICK_RIGHT) + .category(GUI_CATEGORY) + .build()); + register(CYCLE_OPT_FORWARD = ControllerBindingBuilder.create(controller) + .identifier("controlify", "cycle_opt_forward") + .defaultBind(GamepadBinds.RIGHT_STICK_RIGHT) + .category(GUI_CATEGORY) + .build()); + register(CYCLE_OPT_BACKWARD = ControllerBindingBuilder.create(controller) + .identifier("controlify", "cycle_opt_backward") + .defaultBind(GamepadBinds.RIGHT_STICK_LEFT) + .category(GUI_CATEGORY) + .build()); for (var constructor : CUSTOM_BINDS.values()) { register((ControllerBinding) constructor.apply(this)); } + registerModdedKeybinds(); + ControlifyEvents.CONTROLLER_STATE_UPDATED.register(this::onControllerUpdate); ControlifyEvents.INPUT_MODE_CHANGED.register(mode -> KeyMapping.releaseAll()); } @@ -115,10 +337,16 @@ public class ControllerBindings { return binding; } + private ControllerBinding create(UnaryOperator> builder) { + return builder.apply(ControllerBindingBuilder.create(controller)).build(); + } + + @Deprecated private ControllerBinding create(GamepadBinds bind, ResourceLocation id) { return new ControllerBinding<>(controller, bind, id); } + @Deprecated private ControllerBinding create(GamepadBinds bind, ResourceLocation id, KeyMapping override, BooleanSupplier toggleOverride) { return new ControllerBinding<>(controller, bind, id, override, toggleOverride); } @@ -139,20 +367,25 @@ public class ControllerBindings { return json; } - public void fromJson(JsonObject json) { + public boolean fromJson(JsonObject json) { + boolean clean = true; for (var binding : registry().values()) { if (!json.has(binding.id().toString())) { - Controlify.LOGGER.warn("Missing control: " + binding.id() + " in config file. Skipping!"); + Controlify.LOGGER.warn("Missing binding: " + binding.id() + " in config file. Skipping!"); + clean = false; continue; } var bind = json.get(binding.id().toString()).getAsJsonObject(); if (bind == null) { - Controlify.LOGGER.warn("Unknown control: " + binding.id() + " in config file. Skipping!"); + Controlify.LOGGER.warn("Unknown binding: " + binding.id() + " in config file. Skipping!"); + clean = false; continue; } binding.setCurrentBind(IBind.fromJson(bind, controller)); } + + return clean; } public void onControllerUpdate(Controller controller) { @@ -161,6 +394,34 @@ public class ControllerBindings { imitateVanillaClick(); } + private void registerModdedKeybinds() { + for (KeyMapping keyMapping : KeyBindingRegistryImplAccessor.getCustomKeys()) { + if (EXCLUDED_VANILLA_BINDS.contains(keyMapping)) + continue; + + try { + var identifier = new ResourceLocation("fabric-key-binding-api-v1", keyMapping.getName()); + BooleanSupplier toggleOverride = () -> false; + if (keyMapping instanceof ToggleKeyMapping toggleKeyMapping) { + toggleOverride = ((ToggleKeyMappingAccessor) toggleKeyMapping).getNeedsToggle(); + } + + ControllerBinding binding = ControllerBindingBuilder.create(controller) + .identifier(identifier) + .defaultBind(new EmptyBind<>()) + .name(Component.translatable(keyMapping.getName())) + .description(Component.translatable("controlify.custom_binding.vanilla_description").withStyle(ChatFormatting.GRAY)) + .category(Component.translatable(keyMapping.getCategory())) + .vanillaOverride(keyMapping, toggleOverride) + .build(); + + register(binding); + } catch (Exception e) { + Controlify.LOGGER.error("Failed to automatically register modded keybind: " + keyMapping.getName(), e); + } + } + } + private void imitateVanillaClick() { ControllerBinding.clearPressedBinds(controller); @@ -191,14 +452,29 @@ public class ControllerBindings { public static final class Api implements ControlifyBindingsApi { public static final Api INSTANCE = new Api(); + @Override + public BindingSupplier registerBind(ResourceLocation id, UnaryOperator> builder) { + CUSTOM_BINDS.put(id, bindings -> bindings.create(b -> builder.apply(b).identifier(id))); + return controller -> controller.bindings().get(id); + } + + @Deprecated + @Override public BindingSupplier registerBind(GamepadBinds bind, ResourceLocation id) { CUSTOM_BINDS.put(id, bindings -> bindings.create(bind, id)); return controller -> controller.bindings().get(id); } + @Deprecated + @Override public BindingSupplier registerBind(GamepadBinds bind, ResourceLocation id, KeyMapping override, BooleanSupplier toggleOverride) { CUSTOM_BINDS.put(id, bindings -> bindings.create(bind, id, override, toggleOverride)); return controller -> controller.bindings().get(id); } + + @Override + public void excludeVanillaBind(KeyMapping... keyMappings) { + EXCLUDED_VANILLA_BINDS.addAll(Arrays.asList(keyMappings)); + } } } diff --git a/src/main/java/dev/isxander/controlify/config/ControlifyConfig.java b/src/main/java/dev/isxander/controlify/config/ControlifyConfig.java index 76540c0..f15c335 100644 --- a/src/main/java/dev/isxander/controlify/config/ControlifyConfig.java +++ b/src/main/java/dev/isxander/controlify/config/ControlifyConfig.java @@ -32,6 +32,7 @@ public class ControlifyConfig { private Map compoundJoysticks = Map.of(); private GlobalSettings globalSettings = new GlobalSettings(); private boolean firstLaunch; + private boolean dirty; public ControlifyConfig(Controlify controlify) { this.controlify = controlify; @@ -43,6 +44,7 @@ public class ControlifyConfig { try { Files.deleteIfExists(CONFIG_PATH); Files.writeString(CONFIG_PATH, GSON.toJson(generateConfig()), StandardOpenOption.CREATE_NEW, StandardOpenOption.TRUNCATE_EXISTING); + dirty = false; } catch (IOException e) { throw new IllegalStateException("Failed to save config!", e); } @@ -62,6 +64,11 @@ public class ControlifyConfig { } catch (Exception e) { Controlify.LOGGER.error("Failed to load Controlify config!", e); } + + if (dirty) { + Controlify.LOGGER.info("Config was dirty after load, saving..."); + save(); + } } private JsonObject generateConfig() { @@ -100,7 +107,7 @@ public class ControlifyConfig { if (controllers != null) { this.controllerData = controllers; for (var controller : Controller.CONTROLLERS.values()) { - loadOrCreateControllerData(controller); + _loadOrCreateControllerData(controller); } } @@ -119,6 +126,12 @@ public class ControlifyConfig { } public boolean loadOrCreateControllerData(Controller controller) { + boolean result = _loadOrCreateControllerData(controller); + saveIfDirty(); + return result; + } + + private boolean _loadOrCreateControllerData(Controller controller) { var uid = controller.uid(); if (controllerData.has(uid)) { Controlify.LOGGER.info("Loading controller data for " + uid); @@ -134,7 +147,7 @@ public class ControlifyConfig { private void applyControllerConfig(Controller controller, JsonObject object) { try { controller.setConfig(GSON, object.getAsJsonObject("config")); - controller.bindings().fromJson(object.getAsJsonObject("bindings")); + dirty |= !controller.bindings().fromJson(object.getAsJsonObject("bindings")); } catch (Exception e) { Controlify.LOGGER.error("Failed to load controller data for " + controller.uid() + ". Resetting to default!", e); controller.resetConfig(); @@ -142,6 +155,13 @@ public class ControlifyConfig { } } + private void saveIfDirty() { + if (dirty) { + Controlify.LOGGER.info("Config is dirty. Saving..."); + save(); + } + } + public Optional getLoadedControllerConfig(String uid) { return Optional.ofNullable(controllerData.getAsJsonObject(uid)); } 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 dd58ff4..9885f37 100644 --- a/src/main/java/dev/isxander/controlify/config/gui/YACLHelper.java +++ b/src/main/java/dev/isxander/controlify/config/gui/YACLHelper.java @@ -2,9 +2,11 @@ package dev.isxander.controlify.config.gui; import com.google.common.collect.Iterables; import dev.isxander.controlify.Controlify; +import dev.isxander.controlify.bindings.ControllerBinding; import dev.isxander.controlify.bindings.IBind; import dev.isxander.controlify.config.GlobalSettings; import dev.isxander.controlify.controller.Controller; +import dev.isxander.controlify.controller.ControllerState; import dev.isxander.controlify.controller.gamepad.GamepadController; import dev.isxander.controlify.controller.gamepad.GamepadState; import dev.isxander.controlify.controller.gamepad.BuiltinGamepadTheme; @@ -30,6 +32,7 @@ import net.minecraft.network.chat.Component; import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -263,27 +266,38 @@ public class YACLHelper { var controlsGroup = OptionGroup.createBuilder() .name(Component.translatable("controlify.gui.group.controls")); if (controller instanceof GamepadController gamepad) { - for (var binding : gamepad.bindings().registry().values()) { - controlsGroup.option(Option.createBuilder((Class>) (Class) IBind.class) - .name(binding.name()) - .binding(binding.defaultBind(), binding::currentBind, binding::setCurrentBind) - .controller(opt -> new GamepadBindController(opt, gamepad)) - .tooltip(binding.description()) - .build()); - } + groupBindings(gamepad.bindings().registry().values()).forEach((categoryName, bindGroup) -> { + controlsGroup.option(LabelOption.create(categoryName)); + for (var binding : bindGroup) { + controlsGroup.option(Option.createBuilder((Class>) (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>) (Class) IBind.class) - .name(binding.name()) - .binding(binding.defaultBind(), binding::currentBind, binding::setCurrentBind) - .controller(opt -> new JoystickBindController(opt, joystick)) - .tooltip(binding.description()) - .build()); - } + groupBindings(joystick.bindings().registry().values()).forEach((categoryName, bindGroup) -> { + controlsGroup.option(LabelOption.create(categoryName)); + for (var binding : bindGroup) { + controlsGroup.option(Option.createBuilder((Class>) (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()); return category.build(); } + + private static Map>> groupBindings(Collection> bindings) { + return bindings.stream() + .collect(Collectors.groupingBy(ControllerBinding::category, LinkedHashMap::new, Collectors.toList())); + } } diff --git a/src/main/java/dev/isxander/controlify/mixins/compat/fapi/KeyBindingRegistryImplAccessor.java b/src/main/java/dev/isxander/controlify/mixins/compat/fapi/KeyBindingRegistryImplAccessor.java new file mode 100644 index 0000000..fdac4d9 --- /dev/null +++ b/src/main/java/dev/isxander/controlify/mixins/compat/fapi/KeyBindingRegistryImplAccessor.java @@ -0,0 +1,16 @@ +package dev.isxander.controlify.mixins.compat.fapi; + +import net.fabricmc.fabric.impl.client.keybinding.KeyBindingRegistryImpl; +import net.minecraft.client.KeyMapping; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.List; + +@Mixin(KeyBindingRegistryImpl.class) +public interface KeyBindingRegistryImplAccessor { + @Accessor("MODDED_KEY_BINDINGS") + static List getCustomKeys() { + throw new AssertionError(); + } +} diff --git a/src/main/java/dev/isxander/controlify/mixins/feature/bind/ToggleKeyMappingAccessor.java b/src/main/java/dev/isxander/controlify/mixins/feature/bind/ToggleKeyMappingAccessor.java new file mode 100644 index 0000000..727e2ab --- /dev/null +++ b/src/main/java/dev/isxander/controlify/mixins/feature/bind/ToggleKeyMappingAccessor.java @@ -0,0 +1,13 @@ +package dev.isxander.controlify.mixins.feature.bind; + +import net.minecraft.client.ToggleKeyMapping; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.function.BooleanSupplier; + +@Mixin(ToggleKeyMapping.class) +public interface ToggleKeyMappingAccessor { + @Accessor + BooleanSupplier getNeedsToggle(); +} diff --git a/src/main/java/dev/isxander/controlify/mixins/feature/screenop/MinecraftMixin.java b/src/main/java/dev/isxander/controlify/mixins/feature/screenop/MinecraftMixin.java new file mode 100644 index 0000000..fe2b37d --- /dev/null +++ b/src/main/java/dev/isxander/controlify/mixins/feature/screenop/MinecraftMixin.java @@ -0,0 +1,19 @@ +package dev.isxander.controlify.mixins.feature.screenop; + +import dev.isxander.controlify.screenop.ComponentProcessorProvider; +import dev.isxander.controlify.screenop.ScreenProcessorProvider; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.Screen; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(Minecraft.class) +public class MinecraftMixin { + @Inject(method = "setScreen", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/vertex/BufferUploader;reset()V")) + private void changeScreen(Screen screen, CallbackInfo ci) { + ScreenProcessorProvider.REGISTRY.clearCache(); + ComponentProcessorProvider.REGISTRY.clearCache(); + } +} diff --git a/src/main/java/dev/isxander/controlify/mixins/feature/screenop/ScreenMixin.java b/src/main/java/dev/isxander/controlify/mixins/feature/screenop/ScreenMixin.java index 8c782fd..a59b3e6 100644 --- a/src/main/java/dev/isxander/controlify/mixins/feature/screenop/ScreenMixin.java +++ b/src/main/java/dev/isxander/controlify/mixins/feature/screenop/ScreenMixin.java @@ -26,10 +26,4 @@ public class ScreenMixin implements ScreenProcessorProvider { // cannot use screenProcessor() because it may be overriden by registry ScreenProcessorProvider.provide((Screen) (Object) this).onWidgetRebuild(); } - - @Inject(method = "init(Lnet/minecraft/client/Minecraft;II)V", at = @At("HEAD")) - private void clearRegistryCaches(Minecraft client, int width, int height, CallbackInfo ci) { - ScreenProcessorProvider.REGISTRY.clearCache(); - ComponentProcessorProvider.REGISTRY.clearCache(); - } } diff --git a/src/main/java/dev/isxander/controlify/mixins/feature/screenop/vanilla/CreativeModeInventoryScreenAccessor.java b/src/main/java/dev/isxander/controlify/mixins/feature/screenop/vanilla/CreativeModeInventoryScreenAccessor.java index f2d102c..d517863 100644 --- a/src/main/java/dev/isxander/controlify/mixins/feature/screenop/vanilla/CreativeModeInventoryScreenAccessor.java +++ b/src/main/java/dev/isxander/controlify/mixins/feature/screenop/vanilla/CreativeModeInventoryScreenAccessor.java @@ -9,7 +9,9 @@ import org.spongepowered.asm.mixin.gen.Invoker; @Mixin(CreativeModeInventoryScreen.class) public interface CreativeModeInventoryScreenAccessor { @Accessor - CreativeModeTab getSelectedTab(); + static CreativeModeTab getSelectedTab() { + throw new AssertionError(); + } @Invoker void invokeSelectTab(CreativeModeTab tab); diff --git a/src/main/java/dev/isxander/controlify/screenop/compat/vanilla/CreativeModeInventoryScreenProcessor.java b/src/main/java/dev/isxander/controlify/screenop/compat/vanilla/CreativeModeInventoryScreenProcessor.java index 7ba3271..0f38c9b 100644 --- a/src/main/java/dev/isxander/controlify/screenop/compat/vanilla/CreativeModeInventoryScreenProcessor.java +++ b/src/main/java/dev/isxander/controlify/screenop/compat/vanilla/CreativeModeInventoryScreenProcessor.java @@ -20,13 +20,13 @@ public class CreativeModeInventoryScreenProcessor extends AbstractContainerScree if (controller.bindings().GUI_NEXT_TAB.justPressed()) { var tabs = CreativeModeTabs.tabs(); - int newIndex = tabs.indexOf(accessor.getSelectedTab()) + 1; + int newIndex = tabs.indexOf(CreativeModeInventoryScreenAccessor.getSelectedTab()) + 1; if (newIndex >= tabs.size()) newIndex = 0; accessor.invokeSelectTab(tabs.get(newIndex)); } if (controller.bindings().GUI_PREV_TAB.justPressed()) { var tabs = CreativeModeTabs.tabs(); - int newIndex = tabs.indexOf(accessor.getSelectedTab()) - 1; + int newIndex = tabs.indexOf(CreativeModeInventoryScreenAccessor.getSelectedTab()) - 1; if (newIndex < 0) newIndex = tabs.size() - 1; accessor.invokeSelectTab(tabs.get(newIndex)); } diff --git a/src/main/resources/assets/controlify/lang/en_us.json b/src/main/resources/assets/controlify/lang/en_us.json index 5b5361d..fc959d5 100644 --- a/src/main/resources/assets/controlify/lang/en_us.json +++ b/src/main/resources/assets/controlify/lang/en_us.json @@ -31,7 +31,7 @@ "controlify.gui.controller_theme": "Controller Theme", "controlify.gui.controller_theme.tooltip": "The theme to use for rendering controller buttons.", "controlify.gui.reduce_bow_sensitivity": "Reduce Bow Sensitivity", - "controlify.gui.reduce_bow_sensitivity.tooltip": "Reduce the sensitivity of bow-like items when aiming.", + "controlify.gui.reduce_bow_sensitivity.tooltip": "Reduce the sensitivity of bow-like items when aiming.", "controlify.gui.custom_name": "Display Name", "controlify.gui.custom_name.tooltip": "Name to display for this controller throughout Minecraft.", "controlify.gui.group.advanced": "Advanced", @@ -128,6 +128,11 @@ "controlify.binding.controlify.cycle_opt_forward": "Cycle Option Forward", "controlify.binding.controlify.cycle_opt_backward": "Cycle Option Backward", + "controlify.binding_category.gui": "GUI", + "controlify.binding_category.vmouse": "Virtual Mouse", + + "controlify.custom_binding.vanilla_description": "Automatically generated key binding from Fabric API.", + "controlify.guide.inventory": "Open Inventory", "controlify.guide.swim_up": "Swim Up", "controlify.guide.start_elytra": "Open Elytra Wings", diff --git a/src/main/resources/controlify.mixins.json b/src/main/resources/controlify.mixins.json index 1651d78..0e7c2f9 100644 --- a/src/main/resources/controlify.mixins.json +++ b/src/main/resources/controlify.mixins.json @@ -11,6 +11,7 @@ "core.GLXMixin" ], "client": [ + "compat.fapi.KeyBindingRegistryImplAccessor", "compat.sodium.SodiumOptionsGUIAccessor", "compat.sodium.SodiumOptionsGUIMixin", "compat.yacl.CyclingControllerElementMixin", @@ -23,6 +24,7 @@ "feature.accessibility.LocalPlayerMixin", "feature.autoswitch.ToastComponentAccessor", "feature.bind.KeyMappingAccessor", + "feature.bind.ToggleKeyMappingAccessor", "feature.chatkbheight.ChatComponentMixin", "feature.chatkbheight.ChatScreenMixin", "feature.guide.ingame.ClientPacketListenerMixin", @@ -30,6 +32,7 @@ "feature.guide.screen.AbstractButtonMixin", "feature.guide.screen.AbstractWidgetMixin", "feature.guide.screen.TabNavigationBarMixin", + "feature.screenop.MinecraftMixin", "feature.screenop.ScreenMixin", "feature.screenop.vanilla.AbstractButtonMixin", "feature.screenop.vanilla.AbstractContainerEventHandlerMixin", diff --git a/src/testmod/java/dev/isxander/controlify/test/ControlifyTests.java b/src/testmod/java/dev/isxander/controlify/test/ControlifyTests.java index 002d45b..0f628a6 100644 --- a/src/testmod/java/dev/isxander/controlify/test/ControlifyTests.java +++ b/src/testmod/java/dev/isxander/controlify/test/ControlifyTests.java @@ -5,6 +5,7 @@ import dev.isxander.controlify.api.ControlifyApi; import dev.isxander.controlify.api.bind.ControlifyBindingsApi; import dev.isxander.controlify.api.event.ControlifyEvents; import dev.isxander.controlify.bindings.BindingSupplier; +import dev.isxander.controlify.bindings.EmptyBind; import dev.isxander.controlify.bindings.GamepadBinds; import dev.isxander.controlify.screenop.ScreenProcessor; import dev.isxander.controlify.screenop.ScreenProcessorProvider; @@ -25,7 +26,10 @@ public class ControlifyTests { void bindingRegistryTest() { var registry = ControlifyBindingsApi.get(); assertNotNull(registry, "Binding registry is null"); - binding = registry.registerBind(GamepadBinds.A_BUTTON, new ResourceLocation("controlify", "test_bind")); + binding = registry.registerBind( + new ResourceLocation("controlify", "test_bind"), + builder -> builder.defaultBind(new EmptyBind<>()) + ); assertNotNull(binding, "Bind registry failed - BindingSupplier is null"); }