From 1f0ddab36b48874e770785cb155639b5c4e00dec Mon Sep 17 00:00:00 2001 From: LambdAurora Date: Wed, 19 Aug 2020 17:58:50 +0200 Subject: [PATCH] Fix lot of bugs and update to 1.16.2. --- fabric/build.gradle | 6 +- .../lambdacontrols/client/ControllerType.java | 28 ++-- .../client/LambdaControlsClient.java | 15 +- .../client/LambdaControlsConfig.java | 22 +++ .../lambdacontrols/client/LambdaInput.java | 14 +- .../client/compat/OkZoomerCompat.java | 8 +- .../client/controller/ButtonBinding.java | 4 +- .../client/controller/Controller.java | 50 ++++++- .../client/controller/InputHandlers.java | 17 ++- .../client/controller/PressAction.java | 10 +- .../client/gui/ControllerControlsScreen.java | 8 +- .../gui/LambdaControlsSettingsScreen.java | 12 +- .../client/gui/MappingsStringInputScreen.java | 128 ++++++++++++++++++ .../gui/ReloadControllerMappingsOption.java | 37 ++--- .../lambdacontrols/client/gui/RingScreen.java | 60 ++++++++ .../client/ring/DummyRingAction.java | 35 +++++ .../client/ring/KeyBindingRingAction.java | 9 ++ .../client/ring/LambdaRing.java | 7 +- .../client/ring/RingAction.java | 22 ++- .../lambdacontrols/client/ring/RingPage.java | 67 ++++++++- .../assets/lambdacontrols/lang/en_us.json | 5 + .../assets/lambdacontrols/lang/fr_ca.json | 6 +- .../assets/lambdacontrols/lang/fr_fr.json | 10 +- .../textures/gui/controller_axis.png | Bin 5987 -> 1688 bytes .../textures/gui/controller_buttons.png | Bin 8810 -> 3508 bytes .../lambdacontrols/textures/gui/cursor.png | Bin 1087 -> 334 bytes .../lambdacontrols/textures/gui/widgets.png | Bin 13435 -> 4345 bytes fabric/src/main/resources/config.toml | 2 + fabric/src/main/resources/fabric.mod.json | 7 +- gradle.properties | 22 +-- 30 files changed, 508 insertions(+), 103 deletions(-) create mode 100644 fabric/src/main/java/me/lambdaurora/lambdacontrols/client/gui/MappingsStringInputScreen.java create mode 100644 fabric/src/main/java/me/lambdaurora/lambdacontrols/client/gui/RingScreen.java create mode 100644 fabric/src/main/java/me/lambdaurora/lambdacontrols/client/ring/DummyRingAction.java diff --git a/fabric/build.gradle b/fabric/build.gradle index 64d6bd0..e48dc38 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -31,7 +31,7 @@ configurations { dependencies { //to change the versions see the gradle.properties file minecraft "com.mojang:minecraft:${project.minecraft_version}" - mappings "net.fabricmc:yarn:${project.yarn_mappings}" + mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" // Fabric API. This is technically optional, but you probably want it anyway. @@ -43,11 +43,11 @@ dependencies { // Compatibility mods modImplementation "com.github.joaoh1:okzoomer:e13183c59b" - modImplementation "me.shedaniel:RoughlyEnoughItems:4.5.5" + modImplementation "me.shedaniel:RoughlyEnoughItems:5.2.3" api project(":core") shadowInternal project(":core") - shadow("org.aperlambda:lambdajcommon:1.8.0") { + shadow("org.aperlambda:lambdajcommon:1.8.1") { // Minecraft already has all that google crap. exclude group: 'com.google.code.gson' exclude group: 'com.google.guava' diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/ControllerType.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/ControllerType.java index be024c2..3de6295 100644 --- a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/ControllerType.java +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/ControllerType.java @@ -9,6 +9,7 @@ package me.lambdaurora.lambdacontrols.client; +import net.minecraft.text.LiteralText; import net.minecraft.text.Text; import net.minecraft.text.TranslatableText; import org.aperlambda.lambdacommon.utils.Nameable; @@ -21,7 +22,7 @@ import java.util.Optional; * Represents a controller type. * * @author LambdAurora - * @version 1.4.0 + * @version 1.4.3 * @since 1.0.0 */ public enum ControllerType implements Nameable @@ -29,9 +30,10 @@ public enum ControllerType implements Nameable DEFAULT(0), DUALSHOCK(1), SWITCH(2), - XBOX(3), - STEAM(4), - OUYA(5); + XBOX_360(3, new LiteralText("Xbox 360")), + XBOX(4), + STEAM(5), + OUYA(6); private final int id; private final Text text; @@ -39,7 +41,13 @@ public enum ControllerType implements Nameable ControllerType(int id) { this.id = id; - this.text = new TranslatableText(this.getTranslationKey()); + this.text = new TranslatableText("lambdacontrols.controller_type." + this.getName()); + } + + ControllerType(int id, @NotNull Text text) + { + this.id = id; + this.text = text; } /** @@ -65,16 +73,6 @@ public enum ControllerType implements Nameable return v[this.ordinal() + 1]; } - /** - * Returns the translation key of this controller type. - * - * @return The translation key. - */ - public @NotNull String getTranslationKey() - { - return "lambdacontrols.controller_type." + this.getName(); - } - /** * Gets the translated text of this controller type. * diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaControlsClient.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaControlsClient.java index e8fd643..42ca107 100644 --- a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaControlsClient.java +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaControlsClient.java @@ -18,7 +18,9 @@ import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding; import me.lambdaurora.lambdacontrols.client.controller.Controller; import me.lambdaurora.lambdacontrols.client.controller.InputManager; import me.lambdaurora.lambdacontrols.client.gui.LambdaControlsHud; +import me.lambdaurora.lambdacontrols.client.gui.RingScreen; import me.lambdaurora.lambdacontrols.client.gui.TouchscreenOverlay; +import me.lambdaurora.lambdacontrols.client.ring.LambdaRing; import me.lambdaurora.spruceui.event.OpenScreenCallback; import me.lambdaurora.spruceui.hud.HudManager; import net.fabricmc.api.ClientModInitializer; @@ -35,11 +37,13 @@ import net.minecraft.util.Identifier; import org.jetbrains.annotations.NotNull; import org.lwjgl.glfw.GLFW; +import java.io.File; + /** * Represents the LambdaControls client mod. * * @author LambdAurora - * @version 1.3.2 + * @version 1.4.3 * @since 1.1.0 */ public class LambdaControlsClient extends LambdaControls implements ClientModInitializer @@ -53,11 +57,15 @@ public class LambdaControlsClient extends LambdaControls implements ClientModIni InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_2, "key.categories.movement"); public static final KeyBinding BINDING_LOOK_LEFT = InputManager.makeKeyBinding(new Identifier(LambdaControlsConstants.NAMESPACE, "look_left"), InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_4, "key.categories.movement"); + public static final KeyBinding BINDING_RING = InputManager.makeKeyBinding(new Identifier(LambdaControlsConstants.NAMESPACE, "ring"), + InputUtil.Type.MOUSE, GLFW.GLFW_MOUSE_BUTTON_5, "key.categories.misc"); public static final Identifier CONTROLLER_BUTTONS = new Identifier(LambdaControlsConstants.NAMESPACE, "textures/gui/controller_buttons.png"); public static final Identifier CONTROLLER_AXIS = new Identifier(LambdaControlsConstants.NAMESPACE, "textures/gui/controller_axis.png"); public static final Identifier CURSOR_TEXTURE = new Identifier(LambdaControlsConstants.NAMESPACE, "textures/gui/cursor.png"); + public final static File MAPPINGS_FILE = new File("config/gamecontrollerdb.txt"); public final LambdaControlsConfig config = new LambdaControlsConfig(this); public final LambdaInput input = new LambdaInput(this); + public final LambdaRing ring = new LambdaRing(); public final LambdaReacharound reacharound = new LambdaReacharound(); private LambdaControlsHud hud; private ControlsMode previousControlsMode; @@ -70,6 +78,7 @@ public class LambdaControlsClient extends LambdaControls implements ClientModIni KeyBindingHelper.registerKeyBinding(BINDING_LOOK_RIGHT); KeyBindingHelper.registerKeyBinding(BINDING_LOOK_DOWN); KeyBindingHelper.registerKeyBinding(BINDING_LOOK_LEFT); + //KeyBindingHelper.registerKeyBinding(BINDING_RING); ClientSidePacketRegistry.INSTANCE.register(CONTROLS_MODE_CHANNEL, (context, attachedData) -> context.getTaskQueue() .execute(() -> ClientSidePacketRegistry.INSTANCE.sendToServer(CONTROLS_MODE_CHANNEL, this.makeControlsModeBuffer(this.config.getControlsMode())))); @@ -131,6 +140,10 @@ public class LambdaControlsClient extends LambdaControls implements ClientModIni this.input.onTick(client); if (this.config.getControlsMode() == ControlsMode.CONTROLLER && (client.isWindowFocused() || this.config.hasUnfocusedInput())) this.input.onControllerTick(client); + + if (BINDING_RING.wasPressed()) { + client.openScreen(new RingScreen()); + } } public void onRender(MinecraftClient client) diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaControlsConfig.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaControlsConfig.java index 4e03200..3bdb1c0 100644 --- a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaControlsConfig.java +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaControlsConfig.java @@ -36,6 +36,7 @@ public class LambdaControlsConfig // General private static final ControlsMode DEFAULT_CONTROLS_MODE = ControlsMode.DEFAULT; private static final boolean DEFAULT_AUTO_SWITCH_MODE = false; + private static final boolean DEFAULT_DEBUG = false; // HUD private static final boolean DEFAULT_HUD_ENABLE = true; private static final HudSide DEFAULT_HUD_SIDE = HudSide.LEFT; @@ -172,6 +173,7 @@ public class LambdaControlsConfig // General this.setControlsMode(DEFAULT_CONTROLS_MODE); this.setAutoSwitchMode(DEFAULT_AUTO_SWITCH_MODE); + this.setDebug(DEFAULT_DEBUG); // Gameplay this.setFastBlockPlacing(DEFAULT_FAST_BLOCK_INTERACTION); this.setFlyDrifting(DEFAULT_FLY_DRIFTING); @@ -236,6 +238,26 @@ public class LambdaControlsConfig this.config.set("auto_switch_mode", autoSwitchMode); } + /** + * Returns whether the mod has debug enabled or not. + * + * @return True if debug is enabled, else false. + */ + public boolean hasDebug() + { + return this.config.getOrElse("debug", DEFAULT_DEBUG); + } + + /** + * Sets whether the mod has debug enabled or not. + * + * @param debug True if debug is enabled, else false. + */ + protected void setDebug(boolean debug) + { + this.config.set("debug", debug); + } + /* HUD settings */ diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaInput.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaInput.java index bae20eb..fdcd041 100644 --- a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaInput.java +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaInput.java @@ -32,7 +32,7 @@ import net.minecraft.client.gui.screen.ingame.CreativeInventoryScreen; import net.minecraft.client.gui.screen.ingame.HandledScreen; import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen; import net.minecraft.client.gui.screen.multiplayer.MultiplayerServerListWidget; -import net.minecraft.client.gui.screen.pack.ResourcePackScreen; +import net.minecraft.client.gui.screen.pack.PackScreen; import net.minecraft.client.gui.screen.world.WorldListWidget; import net.minecraft.client.gui.widget.AbstractPressableButtonWidget; import net.minecraft.client.gui.widget.AlwaysSelectedEntryListWidget; @@ -64,7 +64,7 @@ import static org.lwjgl.glfw.GLFW.*; * Represents the LambdaControls' input handler. * * @author LambdAurora - * @version 1.4.0 + * @version 1.4.3 * @since 1.0.0 */ public class LambdaInput @@ -669,16 +669,16 @@ public class LambdaInput double powValue = Math.pow(value, 2.0); if (axis == GLFW_GAMEPAD_AXIS_RIGHT_Y) { if (state == 2) { - this.targetPitch = -this.config.getRightYAxisSign() * (this.config.getRotationSpeed() * powValue) * 0.33D; + this.targetPitch = -this.config.getRightYAxisSign() * (this.config.getRotationSpeed() * powValue) * 0.11D; } else if (state == 1) { - this.targetPitch = this.config.getRightYAxisSign() * (this.config.getRotationSpeed() * powValue) * 0.33D; + this.targetPitch = this.config.getRightYAxisSign() * (this.config.getRotationSpeed() * powValue) * 0.11D; } } if (axis == GLFW_GAMEPAD_AXIS_RIGHT_X) { if (state == 2) { - this.targetYaw = -this.config.getRightXAxisSign() * (this.config.getRotationSpeed() * powValue) * 0.33D; + this.targetYaw = -this.config.getRightXAxisSign() * (this.config.getRotationSpeed() * powValue) * 0.11D; } else if (state == 1) { - this.targetYaw = this.config.getRightXAxisSign() * (this.config.getRotationSpeed() * powValue) * 0.33D; + this.targetYaw = this.config.getRightXAxisSign() * (this.config.getRotationSpeed() * powValue) * 0.11D; } } } @@ -700,7 +700,7 @@ public class LambdaInput public static boolean isScreenInteractive(@NotNull Screen screen) { - return !(screen instanceof AdvancementsScreen || screen instanceof HandledScreen || screen instanceof ResourcePackScreen || LambdaControlsCompat.requireMouseOnScreen(screen)); + return !(screen instanceof AdvancementsScreen || screen instanceof HandledScreen || screen instanceof PackScreen || LambdaControlsCompat.requireMouseOnScreen(screen)); } // Inspired from https://github.com/MrCrayfish/Controllable/blob/1.14.X/src/main/java/com/mrcrayfish/controllable/client/ControllerInput.java#L686. diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/compat/OkZoomerCompat.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/compat/OkZoomerCompat.java index 6aa7815..1a9c4dd 100644 --- a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/compat/OkZoomerCompat.java +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/compat/OkZoomerCompat.java @@ -19,7 +19,7 @@ import org.lwjgl.glfw.GLFW; * Represents a compatibility handler for OkZoomer. * * @author LambdAurora - * @version 1.3.0 + * @version 1.4.3 * @since 1.1.0 */ public class OkZoomerCompat implements CompatHandler @@ -36,21 +36,21 @@ public class OkZoomerCompat implements CompatHandler .register(); if (ZoomKeybinds.areExtraKeybindsEnabled()) { - new ButtonBinding.Builder("zoom.in") + new ButtonBinding.Builder("zoom_in") .buttons(GLFW.GLFW_GAMEPAD_BUTTON_DPAD_UP, ButtonBinding.axisAsButton(GLFW.GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER, true)) .onlyInGame() .cooldown(true) .category(ButtonBinding.MISC_CATEGORY) .linkKeybind(ZoomKeybinds.increaseZoomKey) .register(); - new ButtonBinding.Builder("zoom.out") + new ButtonBinding.Builder("zoom_out") .buttons(GLFW.GLFW_GAMEPAD_BUTTON_DPAD_UP, ButtonBinding.axisAsButton(GLFW.GLFW_GAMEPAD_AXIS_LEFT_TRIGGER, true)) .onlyInGame() .cooldown(true) .category(ButtonBinding.MISC_CATEGORY) .linkKeybind(ZoomKeybinds.decreaseZoomKey) .register(); - new ButtonBinding.Builder("zoom.reset") + new ButtonBinding.Builder("zoom_reset") .onlyInGame() .cooldown(true) .category(ButtonBinding.MISC_CATEGORY) diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/controller/ButtonBinding.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/controller/ButtonBinding.java index 1cd9fb1..f84e2e5 100644 --- a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/controller/ButtonBinding.java +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/controller/ButtonBinding.java @@ -32,7 +32,7 @@ import static org.lwjgl.glfw.GLFW.*; * Represents a button binding. * * @author LambdAurora - * @version 1.4.0 + * @version 1.4.3 * @since 1.0.0 */ public class ButtonBinding implements Nameable @@ -75,7 +75,7 @@ public class ButtonBinding implements Nameable .action(InputHandlers.handleInventorySlotPad(0)).onlyInInventory().cooldown(true).register(); public static final ButtonBinding SMOOTH_CAMERA = new Builder("toggle_smooth_camera").cooldown(true).register(); public static final ButtonBinding SNEAK = new Builder("sneak").buttons(GLFW_GAMEPAD_BUTTON_RIGHT_THUMB) - .actions(PressAction.DEFAULT_ACTION, InputHandlers::handleToggleSneak).onlyInGame().cooldown(true).register(); + .actions(InputHandlers::handleToggleSneak).onlyInGame().cooldown(true).register(); public static final ButtonBinding SPRINT = new Builder("sprint").buttons(GLFW_GAMEPAD_BUTTON_LEFT_THUMB).register(); public static final ButtonBinding SWAP_HANDS = new Builder("swap_hands").buttons(GLFW_GAMEPAD_BUTTON_X).cooldown(true).register(); public static final ButtonBinding TAB_LEFT = new Builder("tab_back").buttons(GLFW_GAMEPAD_BUTTON_LEFT_BUMPER) diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/controller/Controller.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/controller/Controller.java index 6908ea6..f8cd6ce 100644 --- a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/controller/Controller.java +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/controller/Controller.java @@ -9,13 +9,20 @@ package me.lambdaurora.lambdacontrols.client.controller; +import me.lambdaurora.lambdacontrols.LambdaControls; import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.toast.SystemToast; +import net.minecraft.text.LiteralText; +import net.minecraft.text.TranslatableText; import org.aperlambda.lambdacommon.utils.Nameable; import org.jetbrains.annotations.NotNull; +import org.lwjgl.PointerBuffer; import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFWGamepadState; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.system.MemoryUtil; -import java.io.File; import java.io.IOException; import java.nio.Buffer; import java.nio.ByteBuffer; @@ -34,7 +41,7 @@ import static org.lwjgl.BufferUtils.createByteBuffer; * Represents a controller. * * @author LambdAurora - * @version 1.0.0 + * @version 1.4.3 * @since 1.0.0 */ public class Controller implements Nameable @@ -167,14 +174,47 @@ public class Controller implements Nameable public static void updateMappings() { try { - File mappingsFile = new File("config/gamecontrollerdb.txt"); - if (!mappingsFile.exists()) + if (!LambdaControlsClient.MAPPINGS_FILE.exists()) return; LambdaControlsClient.get().log("Updating controller mappings..."); - ByteBuffer buffer = ioResourceToBuffer(mappingsFile.getPath(), 1024); + ByteBuffer buffer = ioResourceToBuffer(LambdaControlsClient.MAPPINGS_FILE.getPath(), 1024); GLFW.glfwUpdateGamepadMappings(buffer); } catch (IOException e) { e.printStackTrace(); } + + MemoryStack memoryStack = MemoryStack.stackPush(); + try { + PointerBuffer pointerBuffer = memoryStack.mallocPointer(1); + int i = GLFW.glfwGetError(pointerBuffer); + if (i != 0) { + long l = pointerBuffer.get(); + String string = l == 0L ? "" : MemoryUtil.memUTF8(l); + MinecraftClient client = MinecraftClient.getInstance(); + if (client != null) { + client.getToastManager().add(SystemToast.create(client, SystemToast.Type.TUTORIAL_HINT, + new TranslatableText("lambdacontrols.controller.mappings.error"), new LiteralText(string))); + } + } + } catch (Throwable e) { + /* Ignored :concern: */ + } finally { + memoryStack.close(); + } + + if (LambdaControlsClient.get().config.hasDebug()) { + for (int i = GLFW.GLFW_JOYSTICK_1; i <= GLFW.GLFW_JOYSTICK_16; i++) { + Controller controller = byId(i); + + if (!controller.isConnected()) + continue; + + LambdaControls.get().log(String.format("Controller #%d name: \"%s\"\n GUID: %s\n Gamepad: %s", + controller.id, + controller.getName(), + controller.getGuid(), + controller.isGamepad())); + } + } } } diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/controller/InputHandlers.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/controller/InputHandlers.java index 9683d87..9e0b45a 100644 --- a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/controller/InputHandlers.java +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/controller/InputHandlers.java @@ -23,6 +23,7 @@ import net.minecraft.client.gui.screen.ingame.CreativeInventoryScreen; import net.minecraft.client.gui.screen.ingame.HandledScreen; import net.minecraft.client.gui.screen.ingame.InventoryScreen; import net.minecraft.client.gui.screen.recipebook.RecipeGroupButtonWidget; +import net.minecraft.client.options.Option; import net.minecraft.client.util.ScreenshotUtils; import net.minecraft.item.ItemGroup; import net.minecraft.screen.slot.Slot; @@ -39,7 +40,7 @@ import java.util.stream.Collectors; * Represents some input handlers. * * @author LambdAurora - * @version 1.4.0 + * @version 1.4.3 * @since 1.1.0 */ public class InputHandlers @@ -142,11 +143,15 @@ public class InputHandlers public static boolean handleToggleSneak(@NotNull MinecraftClient client, @NotNull ButtonBinding button, float value, @NotNull ButtonState action) { - if (client.player != null && !client.player.abilities.flying) { - button.asKeyBinding().filter(binding -> action == ButtonState.PRESS).ifPresent(binding -> ((KeyBindingAccessor) binding).lambdacontrols_handlePressState(!binding.isPressed())); - return true; - } - return false; + button.asKeyBinding().ifPresent(binding -> { + boolean sneakToggled = client.options.sneakToggled; + if (client.player.abilities.flying && sneakToggled) + client.options.sneakToggled = false; + binding.setPressed(button.pressed); + if (client.player.abilities.flying && sneakToggled) + client.options.sneakToggled = true; + }); + return true; } public static PressAction handleInventorySlotPad(int direction) diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/controller/PressAction.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/controller/PressAction.java index 4bf5f15..295d67d 100644 --- a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/controller/PressAction.java +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/controller/PressAction.java @@ -12,13 +12,14 @@ package me.lambdaurora.lambdacontrols.client.controller; import me.lambdaurora.lambdacontrols.client.ButtonState; import me.lambdaurora.lambdacontrols.client.util.KeyBindingAccessor; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.options.StickyKeyBinding; import org.jetbrains.annotations.NotNull; /** * Represents a press action callback. * * @author LambdAurora - * @version 1.4.0 + * @version 1.4.3 * @since 1.0.0 */ @FunctionalInterface @@ -27,7 +28,12 @@ public interface PressAction PressAction DEFAULT_ACTION = (client, button, value, action) -> { if (action == ButtonState.REPEAT || client.currentScreen != null) return false; - button.asKeyBinding().ifPresent(binding -> ((KeyBindingAccessor) binding).lambdacontrols_handlePressState(button.isButtonDown())); + button.asKeyBinding().ifPresent(binding -> { + if (binding instanceof StickyKeyBinding) + binding.setPressed(button.pressed); + else + ((KeyBindingAccessor) binding).lambdacontrols_handlePressState(button.isButtonDown()); + }); return true; }; diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/gui/ControllerControlsScreen.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/gui/ControllerControlsScreen.java index 01a11e7..79d8be0 100644 --- a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/gui/ControllerControlsScreen.java +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/gui/ControllerControlsScreen.java @@ -14,6 +14,7 @@ import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding; import me.lambdaurora.lambdacontrols.client.controller.InputManager; import me.lambdaurora.spruceui.SpruceButtonWidget; import me.lambdaurora.spruceui.SpruceTexts; +import net.minecraft.client.gui.DrawableHelper; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.options.ControlsOptionsScreen; import net.minecraft.client.gui.widget.ButtonWidget; @@ -24,6 +25,7 @@ import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; /** * Represents the controls screen. @@ -67,8 +69,8 @@ public class ControllerControlsScreen extends Screen this.bindingsListWidget = new ControlsListWidget(this, this.client); this.children.add(this.bindingsListWidget); this.resetButton = this.addButton(new ButtonWidget(this.width / 2 - 155, this.height - 29, 150, 20, - new TranslatableText("controls.resetAll"), - btn -> InputManager.streamBindings().forEach(binding -> this.mod.config.setButtonBinding(binding, binding.getDefaultButton())))); + SpruceTexts.CONTROLS_RESET_ALL, + btn -> InputManager.streamBindings().collect(Collectors.toSet()).forEach(binding -> this.mod.config.setButtonBinding(binding, binding.getDefaultButton())))); this.addButton(new ButtonWidget(this.width / 2 - 155 + 160, this.height - 29, 150, 20, SpruceTexts.GUI_DONE, btn -> this.client.openScreen(this.parent))); @@ -79,7 +81,7 @@ public class ControllerControlsScreen extends Screen { this.renderBackground(matrices); this.bindingsListWidget.render(matrices, mouseX, mouseY, delta); - this.drawCenteredText(matrices, this.textRenderer, this.title, this.width / 2, 8, 16777215); + drawCenteredText(matrices, this.textRenderer, this.title, this.width / 2, 8, 16777215); this.resetButton.active = InputManager.streamBindings().anyMatch(Predicates.not(ButtonBinding::isDefault)); super.render(matrices, mouseX, mouseY, delta); } diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/gui/LambdaControlsSettingsScreen.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/gui/LambdaControlsSettingsScreen.java index ed51b14..a60092d 100644 --- a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/gui/LambdaControlsSettingsScreen.java +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/gui/LambdaControlsSettingsScreen.java @@ -20,6 +20,7 @@ import me.lambdaurora.spruceui.Tooltip; import me.lambdaurora.spruceui.option.*; import net.fabricmc.fabric.api.network.ClientSidePacketRegistry; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.DrawableHelper; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.options.ControlsOptionsScreen; import net.minecraft.client.gui.widget.ButtonListWidget; @@ -247,6 +248,7 @@ public class LambdaControlsSettingsScreen extends Screen this.list.addOptionEntry(this.frontBlockPlacingOption, this.verticalReacharoundOption); this.list.addSingleOptionEntry(this.flyDriftingOption); this.list.addSingleOptionEntry(this.flyVerticalDriftingOption); + this.list.addOptionEntry(Option.SNEAK_TOGGLED, Option.SPRINT_TOGGLED); // Controller options this.list.addSingleOptionEntry(new SpruceSeparatorOption("lambdacontrols.menu.title.controller", true, null)); this.list.addSingleOptionEntry(this.controllerOption); @@ -256,6 +258,8 @@ public class LambdaControlsSettingsScreen extends Screen this.list.addOptionEntry(this.unfocusedInputOption, this.virtualMouseOption); this.list.addSingleOptionEntry(this.virtualMouseSkinOption); this.list.addSingleOptionEntry(new ReloadControllerMappingsOption()); + this.list.addSingleOptionEntry(new SpruceSimpleActionOption("lambdacontrols.menu.mappings.open_input_str", + btn -> this.client.openScreen(new MappingsStringInputScreen(this)))); // HUD options this.list.addSingleOptionEntry(new SpruceSeparatorOption("lambdacontrols.menu.title.hud", true, null)); this.list.addOptionEntry(this.hudEnableOption, this.hudSideOption); @@ -268,7 +272,7 @@ public class LambdaControlsSettingsScreen extends Screen this.addButton(this.resetOption.createButton(this.client.options, this.width / 2 - 155, this.height - 29, 150)); this.addButton(new ButtonWidget(this.width / 2 - 155 + 160, this.height - 29, 150, buttonHeight, SpruceTexts.GUI_DONE, - (buttonWidget) -> this.client.openScreen(this.parent))); + btn -> this.client.openScreen(this.parent))); } @Override @@ -277,10 +281,10 @@ public class LambdaControlsSettingsScreen extends Screen this.renderBackground(matrices); this.list.render(matrices, mouseX, mouseY, delta); super.render(matrices, mouseX, mouseY, delta); - this.drawCenteredString(matrices, this.textRenderer, I18n.translate("lambdacontrols.menu.title"), this.width / 2, 8, 16777215); - this.drawCenteredString(matrices, this.textRenderer, I18n.translate("lambdacontrols.controller.mappings.1", Formatting.GREEN.toString(), Formatting.RESET.toString()), this.width / 2, this.height - 29 - (5 + this.textRenderer.fontHeight) * 3, 10526880); + drawCenteredString(matrices, this.textRenderer, I18n.translate("lambdacontrols.menu.title"), this.width / 2, 8, 16777215); + drawCenteredString(matrices, this.textRenderer, I18n.translate("lambdacontrols.controller.mappings.1", Formatting.GREEN.toString(), Formatting.RESET.toString()), this.width / 2, this.height - 29 - (5 + this.textRenderer.fontHeight) * 3, 10526880); this.gamepadToolUrlLabel.render(matrices, mouseX, mouseY, delta); - this.drawCenteredString(matrices, this.textRenderer, I18n.translate("lambdacontrols.controller.mappings.3", Formatting.GREEN.toString(), Formatting.RESET.toString()), this.width / 2, this.height - 29 - (5 + this.textRenderer.fontHeight), 10526880); + drawCenteredString(matrices, this.textRenderer, I18n.translate("lambdacontrols.controller.mappings.3", Formatting.GREEN.toString(), Formatting.RESET.toString()), this.width / 2, this.height - 29 - (5 + this.textRenderer.fontHeight), 10526880); Tooltip.renderAll(matrices); } diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/gui/MappingsStringInputScreen.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/gui/MappingsStringInputScreen.java new file mode 100644 index 0000000..1db8456 --- /dev/null +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/gui/MappingsStringInputScreen.java @@ -0,0 +1,128 @@ +/* + * Copyright © 2020 LambdAurora + * + * This file is part of LambdaControls. + * + * Licensed under the MIT license. For more information, + * see the LICENSE file. + */ + +package me.lambdaurora.lambdacontrols.client.gui; + +import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; +import me.lambdaurora.lambdacontrols.client.controller.Controller; +import me.lambdaurora.spruceui.SpruceTextAreaWidget; +import me.lambdaurora.spruceui.SpruceTexts; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.options.Option; +import net.minecraft.client.toast.SystemToast; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.text.LiteralText; +import net.minecraft.text.TranslatableText; +import org.jetbrains.annotations.Nullable; + +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Files; + +/** + * Represents the controller mappings file editor screen. + * + * @author LambdAurora + * @version 1.4.3 + * @since 1.4.3 + */ +public class MappingsStringInputScreen extends Screen +{ + private final Screen parent; + private final Option reloadMappingsOption; + private String mappings; + private SpruceTextAreaWidget textArea; + + protected MappingsStringInputScreen(@Nullable Screen parent) + { + super(new TranslatableText("lambdacontrols.menu.title.mappings.string")); + this.parent = parent; + + this.reloadMappingsOption = new ReloadControllerMappingsOption(btn -> { + this.writeMappings(); + }); + } + + + @Override + public void removed() + { + this.writeMappings(); + Controller.updateMappings(); + super.removed(); + } + + @Override + public void onClose() + { + this.removed(); + super.onClose(); + } + + public void writeMappings() + { + if (this.textArea != null) { + this.mappings = this.textArea.getText(); + System.out.println(this.mappings); + try { + FileWriter fw = new FileWriter(LambdaControlsClient.MAPPINGS_FILE, false); + fw.write(this.mappings); + fw.close(); + } catch (IOException e) { + if (this.client != null) + this.client.getToastManager().add(SystemToast.create(this.client, SystemToast.Type.TUTORIAL_HINT, + new TranslatableText("lambdacontrols.controller.mappings.error.write"), LiteralText.EMPTY)); + e.printStackTrace(); + } + } + } + + @Override + protected void init() + { + super.init(); + + if (this.textArea != null) { + this.mappings = this.textArea.getText(); + } + + String mappings = ""; + + if (this.mappings != null) + mappings = this.mappings; + else if (LambdaControlsClient.MAPPINGS_FILE.exists()) { + try { + mappings = String.join("\n", Files.readAllLines(LambdaControlsClient.MAPPINGS_FILE.toPath())); + this.mappings = mappings; + } catch (IOException e) { + /* Ignored */ + } + } + + int textFieldWidth = (int) (this.width * (3.0 / 4.0)); + this.textArea = new SpruceTextAreaWidget(this.textRenderer, this.width / 2 - textFieldWidth / 2, 50, textFieldWidth, this.height - 100, new LiteralText(mappings)); + this.textArea.setText(mappings); + // Display as many lines as possible + this.textArea.setDisplayedLines(this.textArea.getInnerHeight() / this.textRenderer.fontHeight); + this.addButton(this.textArea); + + this.addButton(this.reloadMappingsOption.createButton(this.client.options, this.width / 2 - 155, this.height - 29, 150)); + this.addButton(new ButtonWidget(this.width / 2 - 155 + 160, this.height - 29, 150, 20, SpruceTexts.GUI_DONE, + (buttonWidget) -> this.client.openScreen(this.parent))); + } + + @Override + public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) + { + this.renderBackground(matrices); + super.render(matrices, mouseX, mouseY, delta); + drawCenteredText(matrices, this.textRenderer, this.title, this.width / 2, 8, 16777215); + } +} diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/gui/ReloadControllerMappingsOption.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/gui/ReloadControllerMappingsOption.java index d88aab5..bbbf662 100644 --- a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/gui/ReloadControllerMappingsOption.java +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/gui/ReloadControllerMappingsOption.java @@ -10,46 +10,39 @@ package me.lambdaurora.lambdacontrols.client.gui; import me.lambdaurora.lambdacontrols.client.controller.Controller; -import me.lambdaurora.spruceui.SpruceButtonWidget; +import me.lambdaurora.spruceui.option.SpruceSimpleActionOption; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.widget.AbstractButtonWidget; -import net.minecraft.client.options.GameOptions; -import net.minecraft.client.options.Option; -import net.minecraft.client.resource.language.I18n; import net.minecraft.client.toast.SystemToast; +import net.minecraft.text.LiteralText; import net.minecraft.text.TranslatableText; -import org.aperlambda.lambdacommon.utils.Nameable; -import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Consumer; /** * Represents the option to reload the controller mappings. */ -public class ReloadControllerMappingsOption extends Option implements Nameable +public class ReloadControllerMappingsOption extends SpruceSimpleActionOption { private static final String KEY = "lambdacontrols.menu.reload_controller_mappings"; public ReloadControllerMappingsOption() { - super(KEY); + this(null); } - @Override - public AbstractButtonWidget createButton(GameOptions options, int x, int y, int width) + public ReloadControllerMappingsOption(@Nullable Consumer before) { - SpruceButtonWidget button = new SpruceButtonWidget(x, y, width, 20, new TranslatableText(KEY), btn -> { + super(KEY, btn -> { MinecraftClient client = MinecraftClient.getInstance(); + if (before != null) + before.accept(btn); Controller.updateMappings(); - if (client.currentScreen != null) + if (client.currentScreen instanceof LambdaControlsSettingsScreen) client.currentScreen.init(client, client.getWindow().getScaledWidth(), client.getWindow().getScaledHeight()); - client.getToastManager().add(new SystemToast(SystemToast.Type.TUTORIAL_HINT, new TranslatableText("lambdacontrols.controller.mappings.updated"), null)); - }); - button.setTooltip(new TranslatableText("lambdacontrols.tooltip.reload_controller_mappings")); - return button; - } - - @Override - public @NotNull String getName() - { - return I18n.translate(KEY); + client.getToastManager().add(SystemToast.create(client, SystemToast.Type.TUTORIAL_HINT, + new TranslatableText("lambdacontrols.controller.mappings.updated"), LiteralText.EMPTY)); + }, new TranslatableText("lambdacontrols.tooltip.reload_controller_mappings")); } } diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/gui/RingScreen.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/gui/RingScreen.java new file mode 100644 index 0000000..5f67e5d --- /dev/null +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/gui/RingScreen.java @@ -0,0 +1,60 @@ +/* + * Copyright © 2020 LambdAurora + * + * This file is part of LambdaControls. + * + * Licensed under the MIT license. For more information, + * see the LICENSE file. + */ + +package me.lambdaurora.lambdacontrols.client.gui; + +import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; +import me.lambdaurora.lambdacontrols.client.ring.RingPage; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.text.TranslatableText; + +/** + * Represents the controls ring screen. + * + * @author LambdAurora + * @version 1.4.3 + * @since 1.4.3 + */ +public class RingScreen extends Screen +{ + protected final LambdaControlsClient mod; + + public RingScreen() + { + super(new TranslatableText("lambdacontrols.menu.title.ring")); + this.mod = LambdaControlsClient.get(); + } + + @Override + public boolean isPauseScreen() + { + return false; + } + + @Override + public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) + { + super.render(matrices, mouseX, mouseY, delta); + + RingPage page = this.mod.ring.getCurrentPage(); + + page.render(matrices, this.textRenderer, this.width, this.height, mouseX, mouseY, delta); + } + + @Override + public boolean mouseReleased(double mouseX, double mouseY, int button) + { + if (LambdaControlsClient.BINDING_RING.matchesMouse(button)) { + this.onClose(); + return true; + } + return false; + } +} diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/ring/DummyRingAction.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/ring/DummyRingAction.java new file mode 100644 index 0000000..a8d39d4 --- /dev/null +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/ring/DummyRingAction.java @@ -0,0 +1,35 @@ +/* + * Copyright © 2020 LambdAurora + * + * This file is part of LambdaControls. + * + * Licensed under the MIT license. For more information, + * see the LICENSE file. + */ + +package me.lambdaurora.lambdacontrols.client.ring; + +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.util.math.MatrixStack; +import org.jetbrains.annotations.NotNull; + +public class DummyRingAction extends RingAction +{ + @Override + public @NotNull String getName() + { + return "dummy"; + } + + @Override + public void onAction(@NotNull RingButtonMode mode) + { + + } + + @Override + public void drawIcon(@NotNull MatrixStack matrices, @NotNull TextRenderer textRenderer, int x, int y, boolean hovered) + { + drawCenteredString(matrices, textRenderer, this.getName(), x + 25, y + 25 - textRenderer.fontHeight / 2, 0xffffff); + } +} diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/ring/KeyBindingRingAction.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/ring/KeyBindingRingAction.java index 311e76b..11a8ca0 100644 --- a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/ring/KeyBindingRingAction.java +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/ring/KeyBindingRingAction.java @@ -10,7 +10,10 @@ package me.lambdaurora.lambdacontrols.client.ring; import me.lambdaurora.lambdacontrols.client.util.KeyBindingAccessor; +import net.minecraft.client.font.TextRenderer; import net.minecraft.client.options.KeyBinding; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.text.TranslatableText; import org.jetbrains.annotations.NotNull; public class KeyBindingRingAction extends RingAction @@ -43,4 +46,10 @@ public class KeyBindingRingAction extends RingAction break; } } + + @Override + public void drawIcon(@NotNull MatrixStack matrices, @NotNull TextRenderer textRenderer, int x, int y, boolean hovered) + { + drawCenteredText(matrices, textRenderer, new TranslatableText(this.getName()), x + 25, y + 25 - textRenderer.fontHeight / 2, 0xffffff); + } } diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/ring/LambdaRing.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/ring/LambdaRing.java index f4dff00..e35753e 100644 --- a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/ring/LambdaRing.java +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/ring/LambdaRing.java @@ -19,13 +19,14 @@ import java.util.List; * Represents a key binding ring. * * @author LambdAurora - * @version 1.4.0 + * @version 1.4.3 * @since 1.4.0 */ public class LambdaRing { - private final List pages = new ArrayList<>(Collections.singletonList(new RingPage())); - private int currentPage = 0; + public static final int ELEMENT_SIZE = 50; + private final List pages = new ArrayList<>(Collections.singletonList(new RingPage())); + private int currentPage = 0; public LambdaRing() { diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/ring/RingAction.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/ring/RingAction.java index 5fd883e..cfbd3d5 100644 --- a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/ring/RingAction.java +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/ring/RingAction.java @@ -9,6 +9,10 @@ package me.lambdaurora.lambdacontrols.client.ring; +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.DrawableHelper; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.text.Text; import net.minecraft.text.TranslatableText; import org.aperlambda.lambdacommon.utils.Nameable; import org.jetbrains.annotations.NotNull; @@ -17,19 +21,19 @@ import org.jetbrains.annotations.NotNull; * Represents a ring action. * * @author LambdAurora - * @version 1.4.0 + * @version 1.4.3 * @since 1.4.0 */ -public abstract class RingAction implements Nameable +public abstract class RingAction extends DrawableHelper implements Nameable { protected boolean activated = false; /** - * Gets the translated name of the ring action. + * Gets the text name of the ring action. * - * @return The translated name. + * @return The text name. */ - public TranslatableText getTranslatedName() + public Text getTextName() { return new TranslatableText(this.getName()); } @@ -52,4 +56,12 @@ public abstract class RingAction implements Nameable } public abstract void onAction(@NotNull RingButtonMode mode); + + public void render(@NotNull MatrixStack matrices, @NotNull TextRenderer textRenderer, int x, int y, boolean hovered) + { + fill(matrices, x, y, x + LambdaRing.ELEMENT_SIZE, y + LambdaRing.ELEMENT_SIZE, hovered ? 0xbb777777 : 0xbb000000); + drawIcon(matrices, textRenderer, x, y, hovered); + } + + public abstract void drawIcon(@NotNull MatrixStack matrices, @NotNull TextRenderer textRenderer, int x, int y, boolean hovered); } diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/ring/RingPage.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/ring/RingPage.java index a3b9c58..6d080d9 100644 --- a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/ring/RingPage.java +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/ring/RingPage.java @@ -9,16 +9,79 @@ package me.lambdaurora.lambdacontrols.client.ring; +import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.DrawableHelper; +import net.minecraft.client.util.math.MatrixStack; +import org.jetbrains.annotations.NotNull; + /** * Represents a ring page. * * @author LambdAurora - * @version 1.4.0 + * @version 1.4.3 * @since 1.4.0 */ -public class RingPage +public class RingPage extends DrawableHelper { private RingAction[] actions = new RingAction[8]; + public RingPage() + { + for (int i = 0; i < 8; i++) { + this.actions[i] = new DummyRingAction(); + } + this.actions[1] = new KeyBindingRingAction(LambdaControlsClient.BINDING_LOOK_UP); + this.actions[3] = new KeyBindingRingAction(LambdaControlsClient.BINDING_LOOK_LEFT); + this.actions[4] = new KeyBindingRingAction(LambdaControlsClient.BINDING_LOOK_RIGHT); + this.actions[6] = new KeyBindingRingAction(LambdaControlsClient.BINDING_LOOK_DOWN); + } + /** + * Renders the ring page. + * + * @param matrices The matrices. + * @param width The screen width. + * @param height The screen height. + * @param mouseX The mouse X-coordinate. + * @param mouseY The mouse Y-coordinate. + * @param tickDelta The tick delta. + */ + public void render(@NotNull MatrixStack matrices, @NotNull TextRenderer textRenderer, int width, int height, int mouseX, int mouseY, float tickDelta) + { + int centerX = width / 2; + int centerY = height / 2; + + int offset = LambdaRing.ELEMENT_SIZE + (LambdaRing.ELEMENT_SIZE / 2) + 5; + + int y = centerY - offset; + int x = centerX - offset; + for (int i = 0; i < 3; i++) { + RingAction ringAction = this.actions[i]; + if (ringAction != null) + ringAction.render(matrices, textRenderer, x, y, isHovered(x, y, mouseX, mouseY)); + x += 55; + } + y += 55; + x = centerX - offset; + for (int i = 3; i < 5; i++) { + RingAction ringAction = this.actions[i]; + if (ringAction != null) + ringAction.render(matrices, textRenderer, x, y, isHovered(x, y, mouseX, mouseY)); + x += 55 * 2; + } + y += 55; + x = centerX - offset; + for (int i = 5; i < 8; i++) { + RingAction ringAction = this.actions[i]; + if (ringAction != null) + ringAction.render(matrices, textRenderer, x, y, isHovered(x, y, mouseX, mouseY)); + x += 55; + } + } + + private static boolean isHovered(int x, int y, int mouseX, int mouseY) + { + return mouseX >= x && mouseY >= y && mouseX <= x + LambdaRing.ELEMENT_SIZE && mouseY <= y + LambdaRing.ELEMENT_SIZE; + } } diff --git a/fabric/src/main/resources/assets/lambdacontrols/lang/en_us.json b/fabric/src/main/resources/assets/lambdacontrols/lang/en_us.json index 526457a..1b48dd6 100644 --- a/fabric/src/main/resources/assets/lambdacontrols/lang/en_us.json +++ b/fabric/src/main/resources/assets/lambdacontrols/lang/en_us.json @@ -3,6 +3,7 @@ "key.lambdacontrols.look_left": "Look left", "key.lambdacontrols.look_right": "Look right", "key.lambdacontrols.look_up": "Look up", + "key.lambdacontrols.ring": "Show controls ring", "lambdacontrols.action.attack": "Attack", "lambdacontrols.action.back": "Back", "lambdacontrols.action.chat": "Open Chat", @@ -64,6 +65,8 @@ "lambdacontrols.controller.disconnected": "Controller %d disconnected.", "lambdacontrols.controller.mappings.1": "To configure the controller mappings, please use %sSDL2 Gamepad Tool%s", "lambdacontrols.controller.mappings.3": "and put the mapping in `%s.minecraft/config/gamecontrollerdb.txt%s`.", + "lambdacontrols.controller.mappings.error": "Error while loading mappings.", + "lambdacontrols.controller.mappings.error.write": "Error while writing mappings to file.", "lambdacontrols.controller.mappings.updated": "Updated mappings!", "lambdacontrols.controller_type.default": "default", "lambdacontrols.controller_type.dualshock": "DualShock", @@ -90,6 +93,7 @@ "lambdacontrols.menu.invert_right_x_axis": "Invert Right X", "lambdacontrols.menu.invert_right_y_axis": "Invert Right Y", "lambdacontrols.menu.keyboard_controls": "Keyboard Controls...", + "lambdacontrols.menu.mappings.open_input_str": "Open Mappings File Editor", "lambdacontrols.menu.mouse_speed": "Mouse Speed", "lambdacontrols.menu.reacharound.horizontal": "Front Block Placing", "lambdacontrols.menu.reacharound.vertical": "Vertical Reacharound", @@ -101,6 +105,7 @@ "lambdacontrols.menu.title.gameplay": "Gameplay Options", "lambdacontrols.menu.title.general": "General Options", "lambdacontrols.menu.title.hud": "HUD Options", + "lambdacontrols.menu.title.mappings.string": "Mappings File Editor", "lambdacontrols.menu.unfocused_input": "Unfocused Input", "lambdacontrols.menu.virtual_mouse": "Virtual Mouse", "lambdacontrols.menu.virtual_mouse.skin": "Virtual Mouse Skin", diff --git a/fabric/src/main/resources/assets/lambdacontrols/lang/fr_ca.json b/fabric/src/main/resources/assets/lambdacontrols/lang/fr_ca.json index 1ac3331..3cced37 100644 --- a/fabric/src/main/resources/assets/lambdacontrols/lang/fr_ca.json +++ b/fabric/src/main/resources/assets/lambdacontrols/lang/fr_ca.json @@ -61,6 +61,8 @@ "lambdacontrols.controller.disconnected": "Manette %d déconnecté.", "lambdacontrols.controller.mappings.1": "Pour configurer les correspondances de la manette, veuillez utiliser %sSDL2 Gamepad Tool%s", "lambdacontrols.controller.mappings.3": "et mettez les correspondances dans le fichier `%s.minecraft/config/gamecontrollerdb.txt%s`.", + "lambdacontrols.controller.mappings.error": "Une erreur est apparue pendant le chargement des manettes.", + "lambdacontrols.controller.mappings.error.write": "Une erreur est apparue pendant l'écriture des manettes au fichier.", "lambdacontrols.controller.mappings.updated": "Configuration des manettes mise à jour!", "lambdacontrols.controller_type.default": "default", "lambdacontrols.controller_type.dualshock": "DualShock", @@ -86,10 +88,11 @@ "lambdacontrols.menu.invert_right_x_axis": "Inverser le stick droit (X)", "lambdacontrols.menu.invert_right_y_axis": "Inverser le stick droit (Y)", "lambdacontrols.menu.keyboard_controls": "Contrôles clavier...", + "lambdacontrols.menu.mappings.open_input_str": "Ouvrir l'éditeur de fichier des manettes", "lambdacontrols.menu.mouse_speed": "Vitesse de la souris", "lambdacontrols.menu.reacharound.horizontal": "Placement avant de bloc", "lambdacontrols.menu.reacharound.vertical": "Placement vertical", - "lambdacontrols.menu.reload_controller_mappings": "Recharge la configuration des manettes", + "lambdacontrols.menu.reload_controller_mappings": "Recharger les manettes", "lambdacontrols.menu.rotation_speed": "Vitesse de rotation", "lambdacontrols.menu.title": "LambdaControls - Paramètres", "lambdacontrols.menu.title.controller": "Options de manettes", @@ -97,6 +100,7 @@ "lambdacontrols.menu.title.gameplay": "Options de Gameplay", "lambdacontrols.menu.title.general": "Options générales", "lambdacontrols.menu.title.hud": "Options du HUD", + "lambdacontrols.menu.title.mappings.string": "Éditeur du fichier des manettes", "lambdacontrols.menu.unfocused_input": "Entrée en fond", "lambdacontrols.menu.virtual_mouse": "Souris virtuelle", "lambdacontrols.menu.virtual_mouse.skin": "Apparence souris virtuelle", diff --git a/fabric/src/main/resources/assets/lambdacontrols/lang/fr_fr.json b/fabric/src/main/resources/assets/lambdacontrols/lang/fr_fr.json index 1ac3331..0aaa057 100644 --- a/fabric/src/main/resources/assets/lambdacontrols/lang/fr_fr.json +++ b/fabric/src/main/resources/assets/lambdacontrols/lang/fr_fr.json @@ -35,8 +35,8 @@ "lambdacontrols.button.b": "B", "lambdacontrols.button.x": "X", "lambdacontrols.button.y": "Y", - "lambdacontrols.button.left_bumper": "Gâchette haute gauche", - "lambdacontrols.button.right_bumper": "Gâchette haute droite", + "lambdacontrols.button.left_bumper": "Gâchette gauche", + "lambdacontrols.button.right_bumper": "Gâchette droite", "lambdacontrols.button.back": "Retour", "lambdacontrols.button.start": "Touche Menu", "lambdacontrols.button.guide": "Guide", @@ -61,6 +61,8 @@ "lambdacontrols.controller.disconnected": "Manette %d déconnecté.", "lambdacontrols.controller.mappings.1": "Pour configurer les correspondances de la manette, veuillez utiliser %sSDL2 Gamepad Tool%s", "lambdacontrols.controller.mappings.3": "et mettez les correspondances dans le fichier `%s.minecraft/config/gamecontrollerdb.txt%s`.", + "lambdacontrols.controller.mappings.error": "Une erreur est apparue pendant le chargement des manettes.", + "lambdacontrols.controller.mappings.error.write": "Une erreur est apparue pendant l'écriture des manettes au fichier.", "lambdacontrols.controller.mappings.updated": "Configuration des manettes mise à jour!", "lambdacontrols.controller_type.default": "default", "lambdacontrols.controller_type.dualshock": "DualShock", @@ -86,10 +88,11 @@ "lambdacontrols.menu.invert_right_x_axis": "Inverser le stick droit (X)", "lambdacontrols.menu.invert_right_y_axis": "Inverser le stick droit (Y)", "lambdacontrols.menu.keyboard_controls": "Contrôles clavier...", + "lambdacontrols.menu.mappings.open_input_str": "Ouvrir l'éditeur de fichier des manettes", "lambdacontrols.menu.mouse_speed": "Vitesse de la souris", "lambdacontrols.menu.reacharound.horizontal": "Placement avant de bloc", "lambdacontrols.menu.reacharound.vertical": "Placement vertical", - "lambdacontrols.menu.reload_controller_mappings": "Recharge la configuration des manettes", + "lambdacontrols.menu.reload_controller_mappings": "Recharger les manettes", "lambdacontrols.menu.rotation_speed": "Vitesse de rotation", "lambdacontrols.menu.title": "LambdaControls - Paramètres", "lambdacontrols.menu.title.controller": "Options de manettes", @@ -97,6 +100,7 @@ "lambdacontrols.menu.title.gameplay": "Options de Gameplay", "lambdacontrols.menu.title.general": "Options générales", "lambdacontrols.menu.title.hud": "Options du HUD", + "lambdacontrols.menu.title.mappings.string": "Éditeur du fichier des manettes", "lambdacontrols.menu.unfocused_input": "Entrée en fond", "lambdacontrols.menu.virtual_mouse": "Souris virtuelle", "lambdacontrols.menu.virtual_mouse.skin": "Apparence souris virtuelle", diff --git a/fabric/src/main/resources/assets/lambdacontrols/textures/gui/controller_axis.png b/fabric/src/main/resources/assets/lambdacontrols/textures/gui/controller_axis.png index ccc6a5985484ff06e8f5437f743808b06a01f52b..c6dcfaecd5f6f8d0b86438c7ca7664fd0cecc65f 100644 GIT binary patch literal 1688 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 PEx=IM6jpxo-qZg9>ojC| diff --git a/fabric/src/main/resources/assets/lambdacontrols/textures/gui/controller_buttons.png b/fabric/src/main/resources/assets/lambdacontrols/textures/gui/controller_buttons.png index 770023e2707f1ce97e3984803a2338945a39fa17..4da37521b706cdd519e2aa605e802a9200e19ab0 100644 GIT binary patch literal 3508 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 F@n19lO4I-V literal 8810 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 I>zopr0P)X@zyJUM delta 1077 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 literal 13435 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.8.0", + "fabricloader": ">=0.9.0", "fabric": ">=0.4.0", - "minecraft": ">=1.16", - "spruceui": ">=1.5.2" + "minecraft": ">=1.16.2", + "spruceui": ">=1.6.3" }, "recommends": { "modmenu": ">=1.12.2" @@ -49,7 +49,6 @@ "optifabric": "*" }, "custom": { - "modmenu:clientsideOnly": true, "modupdater": { "strategy": "curseforge", "projectID": 354231 diff --git a/gradle.properties b/gradle.properties index 372e244..c53b346 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,18 +2,18 @@ org.gradle.jvmargs=-Xmx1G # Fabric Properties - # check these on https://fabricmc.net/use - minecraft_version=1.16.1 - yarn_mappings=1.16.1+build.21:v2 - loader_version=0.9.0+build.204 +# check these on https://fabricmc.net/use +minecraft_version=1.16.2 +yarn_mappings=1.16.2+build.6 +loader_version=0.9.1+build.205 # Mod Properties - mod_version = 1.4.2 - maven_group = me.lambdaurora.lambdacontrols - archives_base_name = lambdacontrols +mod_version = 1.4.3 +maven_group = me.lambdaurora.lambdacontrols +archives_base_name = lambdacontrols # Dependencies - # currently not on the main fabric site, check on the maven: https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api - fabric_version=0.15.0+build.379-1.16.1 - spruceui_version=1.5.11 - modmenu_version=1.12.2+build.17 +# currently not on the main fabric site, check on the maven: https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api +fabric_version=0.17.2+build.396-1.16 +spruceui_version=1.6.4 +modmenu_version=1.14.6+build.31