From eeaf35564a01a100cefea1060fadcfd5c9662827 Mon Sep 17 00:00:00 2001 From: LambdAurora Date: Wed, 27 Nov 2019 16:06:16 +0100 Subject: [PATCH] :sparkles: Add touchscreen support but still WIP. --- .../lambdaurora/lambdacontrols/HudSide.java | 66 +++++++ .../lambdacontrols/LambdaControlsConfig.java | 24 ++- .../lambdacontrols/gui/LambdaControlsHud.java | 24 ++- .../gui/TouchscreenButtonWidget.java | 54 ++++++ .../gui/TouchscreenOverlay.java | 163 ++++++++++++++++++ .../lambdacontrols/mixin/InGameHudMixin.java | 45 +++++ .../mixin/MinecraftClientMixin.java | 25 +++ .../lambdacontrols/mixin/MouseMixin.java | 42 +++++ .../lambdacontrols/util/CustomInGameHud.java | 21 +++ .../lambdacontrols/textures/gui/widgets.png | Bin 0 -> 9123 bytes src/main/resources/config.toml | 4 +- src/main/resources/fabric.mod.json | 3 +- src/main/resources/lambdacontrols.mixins.json | 4 +- 13 files changed, 468 insertions(+), 7 deletions(-) create mode 100644 src/main/java/me/lambdaurora/lambdacontrols/HudSide.java create mode 100644 src/main/java/me/lambdaurora/lambdacontrols/gui/TouchscreenButtonWidget.java create mode 100644 src/main/java/me/lambdaurora/lambdacontrols/gui/TouchscreenOverlay.java create mode 100644 src/main/java/me/lambdaurora/lambdacontrols/mixin/InGameHudMixin.java create mode 100644 src/main/java/me/lambdaurora/lambdacontrols/mixin/MouseMixin.java create mode 100644 src/main/java/me/lambdaurora/lambdacontrols/util/CustomInGameHud.java create mode 100644 src/main/resources/assets/lambdacontrols/textures/gui/widgets.png diff --git a/src/main/java/me/lambdaurora/lambdacontrols/HudSide.java b/src/main/java/me/lambdaurora/lambdacontrols/HudSide.java new file mode 100644 index 0000000..19d1c3f --- /dev/null +++ b/src/main/java/me/lambdaurora/lambdacontrols/HudSide.java @@ -0,0 +1,66 @@ +/* + * Copyright © 2019 LambdAurora + * + * This file is part of LambdaControls. + * + * Licensed under the MIT license. For more information, + * see the LICENSE file. + */ + +package me.lambdaurora.lambdacontrols; + +import net.minecraft.client.resource.language.I18n; +import org.aperlambda.lambdacommon.utils.Nameable; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; +import java.util.Optional; + +/** + * Represents the hud side which is the side where the movements buttons are. + */ +public enum HudSide implements Nameable +{ + LEFT, + RIGHT; + + /** + * Returns the next side available. + * + * @return The next available side. + */ + public HudSide next() + { + HudSide[] v = values(); + if (v.length == this.ordinal() + 1) + return v[0]; + return v[this.ordinal() + 1]; + } + + /** + * Gets the translated name of this hud side. + * + * @return The translated name of this hud side. + */ + public String get_translated_name() + { + return I18n.translate("lambdacontrols.hud_side." + this.get_name()); + } + + @Override + public @NotNull String get_name() + { + return this.name().toLowerCase(); + } + + /** + * Gets the hud side from its identifier. + * + * @param id The identifier of the hud side. + * @return The hud side if found, else empty. + */ + public static Optional by_id(@NotNull String id) + { + return Arrays.stream(values()).filter(mode -> mode.get_name().equalsIgnoreCase(id)).findFirst(); + } +} diff --git a/src/main/java/me/lambdaurora/lambdacontrols/LambdaControlsConfig.java b/src/main/java/me/lambdaurora/lambdacontrols/LambdaControlsConfig.java index 8941579..11020b8 100644 --- a/src/main/java/me/lambdaurora/lambdacontrols/LambdaControlsConfig.java +++ b/src/main/java/me/lambdaurora/lambdacontrols/LambdaControlsConfig.java @@ -10,7 +10,6 @@ package me.lambdaurora.lambdacontrols; import com.electronwill.nightconfig.core.file.FileConfig; -import net.minecraft.client.MinecraftClient; import net.minecraft.client.options.GameOptions; import net.minecraft.client.options.KeyBinding; import org.jetbrains.annotations.NotNull; @@ -28,6 +27,7 @@ public class LambdaControlsConfig private final Map keybinding_mappings = new HashMap<>(); private final LambdaControls mod; private ControlsMode controls_mode; + private HudSide hud_side; public LambdaControlsConfig(@NotNull LambdaControls mod) { @@ -40,6 +40,7 @@ public class LambdaControlsConfig this.config.load(); this.mod.log("Configuration loaded."); this.controls_mode = ControlsMode.by_id(this.config.getOrElse("controls", "default")).orElse(ControlsMode.DEFAULT); + this.hud_side = HudSide.by_id(this.config.getOrElse("hud.side", "left")).orElse(HudSide.LEFT); } public void init_keybindings(GameOptions options) @@ -106,6 +107,27 @@ public class LambdaControlsConfig this.config.set("controls", controls_mode.get_name()); } + /** + * Returns the HUD side from the configuration. + * + * @return The HUD side. + */ + public @NotNull HudSide get_hud_side() + { + return this.hud_side; + } + + /** + * Sets the HUD side in the configuration. + * + * @param hud_side The HUD side. + */ + public void set_hud_side(@NotNull HudSide hud_side) + { + this.hud_side = hud_side; + this.config.set("hud.side", hud_side.get_name()); + } + /** * Returns the keybindings. * diff --git a/src/main/java/me/lambdaurora/lambdacontrols/gui/LambdaControlsHud.java b/src/main/java/me/lambdaurora/lambdacontrols/gui/LambdaControlsHud.java index 79947e9..3aabfa5 100644 --- a/src/main/java/me/lambdaurora/lambdacontrols/gui/LambdaControlsHud.java +++ b/src/main/java/me/lambdaurora/lambdacontrols/gui/LambdaControlsHud.java @@ -9,9 +9,13 @@ package me.lambdaurora.lambdacontrols.gui; +import me.lambdaurora.lambdacontrols.ControlsMode; import me.lambdaurora.lambdacontrols.LambdaControls; +import me.lambdaurora.lambdacontrols.util.LambdaKeyBinding; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.widget.ButtonWidget; import org.jetbrains.annotations.NotNull; +import org.lwjgl.glfw.GLFW; /** * Represents the LambdaControls HUD. @@ -19,15 +23,31 @@ import org.jetbrains.annotations.NotNull; public class LambdaControlsHud { private final MinecraftClient client; - private final LambdaControls mod; + private final LambdaControls mod; + private ButtonWidget jump_button; public LambdaControlsHud(@NotNull MinecraftClient client, @NotNull LambdaControls mod) { this.client = client; this.mod = mod; + this.jump_button = new ButtonWidget(50, 50, 20, 20, "J", button-> {}); } - public void render() { + public void render(float delta) + { + if (this.mod.config.get_controls_mode() == ControlsMode.TOUCHSCREEN) + this.render_touchscreen(delta); + } + public void render_touchscreen(float delta) + { + //this.jump_button.render((int) this.client.mouse.getX(), (int) this.client.mouse.getY(), delta); + } + + public void on_input(double x, double y, int button, int action) + { + if (this.jump_button.mouseClicked(x, y, button)) { + ((LambdaKeyBinding) this.client.options.keyJump).handle_press_state(action != GLFW.GLFW_RELEASE); + } } } diff --git a/src/main/java/me/lambdaurora/lambdacontrols/gui/TouchscreenButtonWidget.java b/src/main/java/me/lambdaurora/lambdacontrols/gui/TouchscreenButtonWidget.java new file mode 100644 index 0000000..b8352f9 --- /dev/null +++ b/src/main/java/me/lambdaurora/lambdacontrols/gui/TouchscreenButtonWidget.java @@ -0,0 +1,54 @@ +/* + * Copyright © 2019 LambdAurora + * + * This file is part of LambdaControls. + * + * Licensed under the MIT license. For more information, + * see the LICENSE file. + */ + +package me.lambdaurora.lambdacontrols.gui; + +import net.minecraft.client.gui.widget.TexturedButtonWidget; +import net.minecraft.util.Identifier; +import org.jetbrains.annotations.NotNull; + +import java.util.function.Consumer; + +/** + * Represents a touchscreen button widget. + */ +public class TouchscreenButtonWidget extends TexturedButtonWidget +{ + private final Consumer on_change_state; + + public TouchscreenButtonWidget(int x, int y, int width, int height, int u, int v, int hovered_v_offset, Identifier texture, @NotNull Consumer on_changed_state) + { + super(x, y, width, height, u, v, hovered_v_offset, texture, 256, 256, btn -> on_changed_state.accept(true)); + this.on_change_state = on_changed_state; + } + + @Override + public void onRelease(double mouseX, double mouseY) + { + super.onRelease(mouseX, mouseY); + this.on_change_state.accept(false); + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) + { + if (this.active && this.visible) { + if (this.isValidClickButton(button)) { + boolean clicked = this.clicked(mouseX, mouseY); + if (clicked) { + this.onClick(mouseX, mouseY); + return true; + } + } + + return false; + } else + return false; + } +} diff --git a/src/main/java/me/lambdaurora/lambdacontrols/gui/TouchscreenOverlay.java b/src/main/java/me/lambdaurora/lambdacontrols/gui/TouchscreenOverlay.java new file mode 100644 index 0000000..8472456 --- /dev/null +++ b/src/main/java/me/lambdaurora/lambdacontrols/gui/TouchscreenOverlay.java @@ -0,0 +1,163 @@ +/* + * Copyright © 2019 LambdAurora + * + * This file is part of LambdaControls. + * + * Licensed under the MIT license. For more information, + * see the LICENSE file. + */ + +package me.lambdaurora.lambdacontrols.gui; + +import me.lambdaurora.lambdacontrols.HudSide; +import me.lambdaurora.lambdacontrols.LambdaControls; +import me.lambdaurora.lambdacontrols.util.LambdaKeyBinding; +import net.minecraft.client.gui.screen.ChatScreen; +import net.minecraft.client.gui.screen.GameMenuScreen; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.screen.ingame.InventoryScreen; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.gui.widget.TexturedButtonWidget; +import net.minecraft.server.network.packet.PlayerActionC2SPacket; +import net.minecraft.text.LiteralText; +import net.minecraft.util.Arm; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import org.jetbrains.annotations.NotNull; + +/** + * Represents the touchscreen overlay + */ +public class TouchscreenOverlay extends Screen +{ + public static final Identifier WIDGETS_LOCATION = new Identifier("lambdacontrols", "textures/gui/widgets.png"); + private LambdaControls mod; + private TouchscreenButtonWidget start_sneak_button; + private TouchscreenButtonWidget end_sneak_button; + + public TouchscreenOverlay(@NotNull LambdaControls mod) + { + super(new LiteralText("Touchscreen overlay")); + this.mod = mod; + this.passEvents = true; + } + + @Override + public boolean shouldCloseOnEsc() + { + return false; + } + + @Override + public boolean isPauseScreen() + { + return false; + } + + @Override + public void onClose() + { + super.onClose(); + } + + private void pause_game(boolean bl) + { + if (this.minecraft == null) + return; + boolean bl2 = this.minecraft.isIntegratedServerRunning() && !this.minecraft.getServer().isRemote(); + if (bl2) { + this.minecraft.openScreen(new GameMenuScreen(!bl)); + this.minecraft.getSoundManager().pauseAll(); + } else { + this.minecraft.openScreen(new GameMenuScreen(true)); + } + } + + @Override + protected void init() + { + super.init(); + int scaled_width = this.minecraft.window.getScaledWidth(); + int scaled_height = this.minecraft.window.getScaledHeight(); + this.addButton(new TexturedButtonWidget(scaled_width / 2 - 20, 0, 20, 20, 0, 106, 20, ButtonWidget.WIDGETS_LOCATION, 256, 256, + btn -> this.minecraft.openScreen(new ChatScreen("")), "")); + this.addButton(new TexturedButtonWidget(scaled_width / 2, 0, 20, 20, 0, 0, 20, WIDGETS_LOCATION, 256, 256, + btn -> this.pause_game(false))); + // Inventory buttons. + int inventory_button_x = scaled_width / 2; + int inventory_button_y = scaled_height - 16 - 5; + if (this.minecraft.options.mainArm == Arm.LEFT) { + inventory_button_x = inventory_button_x - 91 - 24; + } else { + inventory_button_x = inventory_button_x + 91 + 4; + } + this.addButton(new TexturedButtonWidget(inventory_button_x, inventory_button_y, 20, 20, 20, 0, 20, WIDGETS_LOCATION, 256, 256, + btn -> { + if (this.minecraft.interactionManager.hasRidingInventory()) { + this.minecraft.player.openRidingInventory(); + } else { + this.minecraft.getTutorialManager().onInventoryOpened(); + this.minecraft.openScreen(new InventoryScreen(this.minecraft.player)); + } + })); + int jump_button_x, swap_hands_x, sneak_button_x; + int sneak_button_y = scaled_height - 10 - 40 - 5; + if (this.mod.config.get_hud_side() == HudSide.LEFT) { + jump_button_x = scaled_width - 20 - 20; + swap_hands_x = jump_button_x - 5 - 20; + sneak_button_x = 10 + 20 + 5; + } else { + jump_button_x = 20; + swap_hands_x = jump_button_x + 5 + 20; + sneak_button_x = scaled_width - 10 - 40 - 5; + } + // Swap items hand. + this.addButton(new TouchscreenButtonWidget(swap_hands_x, scaled_height - 5 - 20 - 40, 20, 20, 0, 0, 20, WIDGETS_LOCATION, + state -> { + if (state) { + if (!this.minecraft.player.isSpectator()) { + this.minecraft.getNetworkHandler().sendPacket(new PlayerActionC2SPacket(PlayerActionC2SPacket.Action.SWAP_HELD_ITEMS, BlockPos.ORIGIN, Direction.DOWN)); + } + } + })); + // Drop + this.addButton(new TouchscreenButtonWidget(swap_hands_x, scaled_height - 40, 20, 20, 0, 0, 20, WIDGETS_LOCATION, + state -> ((LambdaKeyBinding) this.minecraft.options.keyDrop).handle_press_state(state))); + // Jump keys + this.addButton(new TouchscreenButtonWidget(jump_button_x, scaled_height - 40, 20, 20, 0, 40, 20, WIDGETS_LOCATION, + state -> ((LambdaKeyBinding) this.minecraft.options.keyJump).handle_press_state(state))); + // Movements keys + this.addButton((this.start_sneak_button = new TouchscreenButtonWidget(sneak_button_x, sneak_button_y, 20, 20, 0, 120, 20, WIDGETS_LOCATION, + state -> { + if (state) { + ((LambdaKeyBinding) this.minecraft.options.keySneak).handle_press_state(true); + this.start_sneak_button.visible = false; + this.end_sneak_button.visible = true; + } + }))); + this.addButton((this.end_sneak_button = new TouchscreenButtonWidget(sneak_button_x, sneak_button_y, 20, 20, 20, 120, 20, WIDGETS_LOCATION, + state -> { + if (state) { + ((LambdaKeyBinding) this.minecraft.options.keySneak).handle_press_state(false); + this.end_sneak_button.visible = false; + this.start_sneak_button.visible = true; + } + }))); + this.end_sneak_button.visible = false; + this.addButton(new TouchscreenButtonWidget(sneak_button_x, sneak_button_y - 5 - 20, 20, 20, 0, 80, 20, WIDGETS_LOCATION, + state -> ((LambdaKeyBinding) this.minecraft.options.keyForward).handle_press_state(state))); + this.addButton(new TouchscreenButtonWidget(sneak_button_x + 20 + 5, sneak_button_y, 20, 20, 20, 80, 20, WIDGETS_LOCATION, + state -> ((LambdaKeyBinding) this.minecraft.options.keyRight).handle_press_state(state))); + this.addButton(new TouchscreenButtonWidget(sneak_button_x, sneak_button_y + 20 + 5, 20, 20, 40, 80, 20, WIDGETS_LOCATION, + state -> ((LambdaKeyBinding) this.minecraft.options.keyBack).handle_press_state(state))); + this.addButton(new TouchscreenButtonWidget(sneak_button_x - 20 - 5, sneak_button_y, 20, 20, 60, 80, 20, WIDGETS_LOCATION, + state -> ((LambdaKeyBinding) this.minecraft.options.keyLeft).handle_press_state(state))); + } + + @Override + public void render(int mouseX, int mouseY, float delta) + { + super.render(mouseX, mouseY, delta); + } +} diff --git a/src/main/java/me/lambdaurora/lambdacontrols/mixin/InGameHudMixin.java b/src/main/java/me/lambdaurora/lambdacontrols/mixin/InGameHudMixin.java new file mode 100644 index 0000000..adfcdee --- /dev/null +++ b/src/main/java/me/lambdaurora/lambdacontrols/mixin/InGameHudMixin.java @@ -0,0 +1,45 @@ +/* + * Copyright © 2019 LambdAurora + * + * This file is part of LambdaControls. + * + * Licensed under the MIT license. For more information, + * see the LICENSE file. + */ + +package me.lambdaurora.lambdacontrols.mixin; + +import me.lambdaurora.lambdacontrols.LambdaControls; +import me.lambdaurora.lambdacontrols.gui.LambdaControlsHud; +import me.lambdaurora.lambdacontrols.util.CustomInGameHud; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.hud.InGameHud; +import org.jetbrains.annotations.NotNull; +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(InGameHud.class) +public class InGameHudMixin implements CustomInGameHud +{ + private LambdaControlsHud lambdacontrols_hud; + + @Inject(method = "", at = @At("RETURN")) + public void on_new(MinecraftClient client, CallbackInfo ci) + { + this.lambdacontrols_hud = new LambdaControlsHud(client, LambdaControls.get()); + } + + @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/hud/InGameHud;renderMountHealth()V")) + public void on_render(float tick_delta, CallbackInfo ci) + { + lambdacontrols_hud.render(tick_delta); + } + + @Override + public @NotNull LambdaControlsHud get_lambdacontrols_hud() + { + return this.lambdacontrols_hud; + } +} diff --git a/src/main/java/me/lambdaurora/lambdacontrols/mixin/MinecraftClientMixin.java b/src/main/java/me/lambdaurora/lambdacontrols/mixin/MinecraftClientMixin.java index 2134920..fbec21f 100644 --- a/src/main/java/me/lambdaurora/lambdacontrols/mixin/MinecraftClientMixin.java +++ b/src/main/java/me/lambdaurora/lambdacontrols/mixin/MinecraftClientMixin.java @@ -11,8 +11,13 @@ package me.lambdaurora.lambdacontrols.mixin; import me.lambdaurora.lambdacontrols.ControlsMode; import me.lambdaurora.lambdacontrols.LambdaControls; +import me.lambdaurora.lambdacontrols.gui.TouchscreenOverlay; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.util.Window; +import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -20,6 +25,14 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(MinecraftClient.class) public abstract class MinecraftClientMixin { + @Shadow + public Window window; + + @Shadow + public boolean skipGameRender; + + @Shadow public Screen currentScreen; + @Inject(method = "init", at = @At("RETURN")) private void on_init(CallbackInfo ci) { @@ -32,4 +45,16 @@ public abstract class MinecraftClientMixin if (LambdaControls.get().config.get_controls_mode() == ControlsMode.CONTROLLER) LambdaControls.get().on_tick((MinecraftClient) (Object) this); } + + @Inject(method = "openScreen", at = @At("RETURN")) + private void on_open_screen(@Nullable Screen screen, CallbackInfo ci) + { + LambdaControls mod = LambdaControls.get(); + if (screen == null && mod.config.get_controls_mode() == ControlsMode.TOUCHSCREEN) { + screen = new TouchscreenOverlay(mod); + screen.init(((MinecraftClient) (Object) this), this.window.getScaledWidth(), this.window.getScaledHeight()); + this.skipGameRender = false; + this.currentScreen = screen; + } + } } diff --git a/src/main/java/me/lambdaurora/lambdacontrols/mixin/MouseMixin.java b/src/main/java/me/lambdaurora/lambdacontrols/mixin/MouseMixin.java new file mode 100644 index 0000000..7015368 --- /dev/null +++ b/src/main/java/me/lambdaurora/lambdacontrols/mixin/MouseMixin.java @@ -0,0 +1,42 @@ +/* + * Copyright © 2019 LambdAurora + * + * This file is part of LambdaControls. + * + * Licensed under the MIT license. For more information, + * see the LICENSE file. + */ + +package me.lambdaurora.lambdacontrols.mixin; + +import me.lambdaurora.lambdacontrols.ControlsMode; +import me.lambdaurora.lambdacontrols.LambdaControls; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.Mouse; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(Mouse.class) +public class MouseMixin +{ + @Shadow + @Final + private MinecraftClient client; + + @Shadow + private double x; + + @Shadow + private double y; + + @Inject(method = "lockCursor", at = @At("HEAD"), cancellable = true) + private void on_mouse_locked(CallbackInfo ci) + { + if (LambdaControls.get().config.get_controls_mode() == ControlsMode.TOUCHSCREEN) + ci.cancel(); + } +} diff --git a/src/main/java/me/lambdaurora/lambdacontrols/util/CustomInGameHud.java b/src/main/java/me/lambdaurora/lambdacontrols/util/CustomInGameHud.java new file mode 100644 index 0000000..942e4f6 --- /dev/null +++ b/src/main/java/me/lambdaurora/lambdacontrols/util/CustomInGameHud.java @@ -0,0 +1,21 @@ +/* + * Copyright © 2019 LambdAurora + * + * This file is part of LambdaControls. + * + * Licensed under the MIT license. For more information, + * see the LICENSE file. + */ + +package me.lambdaurora.lambdacontrols.util; + +import me.lambdaurora.lambdacontrols.gui.LambdaControlsHud; +import org.jetbrains.annotations.NotNull; + +/** + * Represents a custom ingame hud with an accessor to an added hud. + */ +public interface CustomInGameHud +{ + @NotNull LambdaControlsHud get_lambdacontrols_hud(); +} diff --git a/src/main/resources/assets/lambdacontrols/textures/gui/widgets.png b/src/main/resources/assets/lambdacontrols/textures/gui/widgets.png new file mode 100644 index 0000000000000000000000000000000000000000..71398909a4fc88f19cd2fa427b1a495f9cd8a05c GIT binary patch literal 9123 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 Xk1kipZ0Z3|-GB@)BlSLBLOu8&3HgCz literal 0 HcmV?d00001 diff --git a/src/main/resources/config.toml b/src/main/resources/config.toml index 5221aee..ea7d3a4 100644 --- a/src/main/resources/config.toml +++ b/src/main/resources/config.toml @@ -4,8 +4,8 @@ controls = "default" [hud] -# Dertermines which side is used depending of the main hand. -side = "right_handed" +# Dertermines where the movements buttons are. +side = "left" # Controller settings [controller] diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index e13dedb..5b1dd37 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -26,7 +26,8 @@ "depends": { "fabricloader": ">=0.4.0", "fabric": "*", - "minecraft": "1.14.x" + "minecraft": "1.14.x", + "cotton-client-commands": ">=0.4.2+1.14.3-SNAPSHOT" }, "suggests": { "flamingo": "*" diff --git a/src/main/resources/lambdacontrols.mixins.json b/src/main/resources/lambdacontrols.mixins.json index 807bad4..1b94c2c 100644 --- a/src/main/resources/lambdacontrols.mixins.json +++ b/src/main/resources/lambdacontrols.mixins.json @@ -3,8 +3,10 @@ "package": "me.lambdaurora.lambdacontrols.mixin", "compatibilityLevel": "JAVA_8", "client": [ + "InGameHudMixin", + "KeyBindingMixin", "MinecraftClientMixin", - "KeyBindingMixin" + "MouseMixin" ], "injectors": { "defaultRequire": 1