diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..1256956 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,35 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: bug +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. Linux] + - Minecraft [e.g. 1.14.4] + - Fabric [e.g. fabric 0.7.2+build.174] + - Mods [e.g. aurora_keystrokes v1.0.0, modmenu v1.7.15] + - Version [e.g. 1.0.0] + - Branch [e.g. dev] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..11fc491 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: enhancement +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..f156cab --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,76 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at aurora42lambda@gmail.com. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..0a4aef5 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,103 @@ +# Contributing to LambdaControls + +:tada: First of all, thanks for taking time to contribute! :tada: + +The following is a set of guidelines for contributing to LambdaControls. +Feel free to propose changes to this document in a pull request. + +**Table of Contents** + +[Code of Conduct](#code-of-conduct) + +[What should I know before I get started?](#what-should-i-know-before-i-get-started) + +[How can I contribute?](#how-can-i-contribute) + +[Styleguides](#styleguides) + +## Code of Conduct + +This project and everyone participating in it is governed by the [Code of Conduct](https://github.com/LambdAurora/LambdaControls/blob/master/CODE_OF_CONDUCT.md). +By participating, you are expected to uphold this code. Please report unacceptable behavior at [aurora42lambda@gmail.com](mailto:aurora42lambda@gmail.com). + +## What should I know before I get started? + +### Fabric + +[Fabric](https://fabricmc.net/) is the mod loader and the software which allows Gradle to setup the workspace. + +### Java 8 + +Java is the main language used to make LambdaControls alive. +Knowing how to code in Java is necessary if you contribute to the code. + +### Minecraft + +As it is a Minecraft mod you should know a bit how Minecraft works and how modding works. + +### Mixins + +[Mixins](https://github.com/SpongePowered/Mixin/wiki) are a main part in this mod, they allow the necessary modifications to the Minecraft Client. + +### Gradle + +[Gradle](https://gradle.org/) is the build tool used for this project. + +### Git + +Git is the control version software we use for LambdaControls, please know how to use it if you consider contributing to the code. + +Git commits should be and must be signed. + +## How can I contribute? + +### Reporting Bugs + +#### Before submitting a bug report + +- Check if you can reproduce it on other platforms, on multiple web browsers. +- Perform a search to see if the problem has already been reported. If it has **and the issue is still open**, add a comment to the existing issue instead of opening a new one. + +#### How do I submit a bug report? + +Go in the issues tab in GitHub and read the [bug report guide](https://github.com/LambdAurora/LambdaControls/blob/master/.github/ISSUE_TEMPLATE/bug_report.md) + +### Suggesting enhancements + +Enhancement suggestions are tracked as [GitHub issues](https://github.com/LambdAurora/LambdaControls/issues). +Check out the [feature request](https://github.com/LambdAurora/LambdaControls/blob/master/.github/ISSUE_TEMPLATE/feature_request.md) guide. + +### Do pull requests + +You can help LambdaControls by writing code and submit it with pull requests. + +Pull requests will be accepted if they follow the [styleguide](#styleguides), if they are useful, etc... +We can refuse a pull request if the commits are not signed, so don't forget to [sign them](https://help.github.com/en/articles/signing-commits)! + +Feel free to pull request! + +## Styleguides + +### Git commit messages + +* Use the imperative mood ("Move cursor to..." not "Moves cursor to...") +* Consider starting the commit message with an emote, emotes for your commit can be found at the [gitmoji guide](https://gitmoji.carloscuesta.me/). +* (Not for the message) Don't forget to sign the commit. + +### Naming convention + +Names in the code should be explicit and always in `snake_case`, `camelCase` will not be allowed. +`PascalCase` can be used for class name. + +We chose `snake_case` because it is more accessible for everyone: for people who don't speak English as their native language it is more easy to see the words when they are separated, +it also allows the correct use of screen reader on the code with `snake_case` due to the absence of upper case characters. + +### Brace placement + +Every braces should be at the end of the line of function declaration, etc... +The only exception is class declarations: braces must be on the next line. + +### Quick note for users of the Intellij IDEA IDE + +As a user of the Intellij IDEA IDE you have the format code shortcut which use a codestyle described by a file. +You can import the codestyle file here: [LambdAurora's dotfiles](https://github.com/LambdAurora/dotfiles/blob/master/jetbrains/lambdacodestyle2.xml). diff --git a/README.md b/README.md index 96168f6..0ab3089 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,7 @@ # LambdaControls +![JS and HTML/CSS](https://img.shields.io/badge/language-Java%208-9B599A.svg?style=flat-square) +[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)](https://raw.githubusercontent.com/LambdAurora/LambdaControls/master/LICENSE) + A Fabric Minecraft mod which add better controls. It allows the use of a controller or the touchscreen. diff --git a/src/main/java/me/lambdaurora/lambdacontrols/ButtonBinding.java b/src/main/java/me/lambdaurora/lambdacontrols/ButtonBinding.java index 2246036..6021ad8 100644 --- a/src/main/java/me/lambdaurora/lambdacontrols/ButtonBinding.java +++ b/src/main/java/me/lambdaurora/lambdacontrols/ButtonBinding.java @@ -10,16 +10,18 @@ package me.lambdaurora.lambdacontrols; import me.lambdaurora.lambdacontrols.util.KeyBindingAccessor; +import net.minecraft.client.MinecraftClient; import net.minecraft.client.options.GameOptions; import net.minecraft.client.options.KeyBinding; +import net.minecraft.client.resource.language.I18n; +import net.minecraft.client.util.ScreenshotUtils; import org.aperlambda.lambdacommon.utils.Nameable; +import org.aperlambda.lambdacommon.utils.Pair; import org.jetbrains.annotations.NotNull; import org.lwjgl.glfw.GLFW; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.Optional; +import java.util.*; +import java.util.stream.Stream; /** * Represents a button binding. @@ -28,28 +30,59 @@ import java.util.Optional; */ public class ButtonBinding implements Nameable { - private static final List BINDINGS = new ArrayList<>(); - public static final ButtonBinding ATTACK = new ButtonBinding(axis_as_button(GLFW.GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER, true), "attack"); - public static final ButtonBinding BACK = new ButtonBinding(axis_as_button(GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y, false), "back"); - public static final ButtonBinding DROP_ITEM = new ButtonBinding(GLFW.GLFW_GAMEPAD_BUTTON_B, "drop_item"); - public static final ButtonBinding FORWARD = new ButtonBinding(axis_as_button(GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y, true), "forward"); - public static final ButtonBinding INVENTORY = new ButtonBinding(GLFW.GLFW_GAMEPAD_BUTTON_Y, "inventory"); - public static final ButtonBinding JUMP = new ButtonBinding(GLFW.GLFW_GAMEPAD_BUTTON_A, "jump"); - public static final ButtonBinding PAUSE_GAME = new ButtonBinding(GLFW.GLFW_GAMEPAD_BUTTON_START, "pause_game"); - public static final ButtonBinding SNEAK = new ButtonBinding(GLFW.GLFW_GAMEPAD_BUTTON_RIGHT_THUMB, "sneak"); - public static final ButtonBinding SPRINT = new ButtonBinding(GLFW.GLFW_GAMEPAD_BUTTON_LEFT_THUMB, "sprint"); - public static final ButtonBinding SWAP_HANDS = new ButtonBinding(GLFW.GLFW_GAMEPAD_BUTTON_X, "swap_hands"); + private static final List BINDINGS = new ArrayList<>(); + private static final Map, List> CATEGORIES = new HashMap<>(); + public static final String MOVEMENT_CATEGORY = "key.categories.movement"; + public static final String GAMEPLAY_CATEGORY = "key.categories.gameplay"; + public static final String INVENTORY_CATEGORY = "key.categories.inventory"; + public static final String MULTIPLAYER_CATEGORY = "key.categories.multiplayer"; + public static final String MISC_CATEGORY = "key.categories.misc"; + public static final ButtonBinding ATTACK = new ButtonBinding(axis_as_button(GLFW.GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER, true), "attack"); + public static final ButtonBinding BACK = new ButtonBinding(axis_as_button(GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y, false), "back"); + public static final ButtonBinding CHAT = new ButtonBinding(GLFW.GLFW_GAMEPAD_BUTTON_DPAD_RIGHT, "chat"); + public static final ButtonBinding DROP_ITEM = new ButtonBinding(GLFW.GLFW_GAMEPAD_BUTTON_B, "drop_item"); + public static final ButtonBinding FORWARD = new ButtonBinding(axis_as_button(GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y, true), "forward"); + public static final ButtonBinding INVENTORY = new ButtonBinding(GLFW.GLFW_GAMEPAD_BUTTON_Y, "inventory"); + public static final ButtonBinding JUMP = new ButtonBinding(GLFW.GLFW_GAMEPAD_BUTTON_A, "jump"); + public static final ButtonBinding LEFT = new ButtonBinding(axis_as_button(GLFW.GLFW_GAMEPAD_AXIS_LEFT_X, false), "left"); + public static final ButtonBinding PAUSE_GAME = new ButtonBinding(GLFW.GLFW_GAMEPAD_BUTTON_START, "pause_game"); + public static final ButtonBinding PICK_BLOCK = new ButtonBinding(GLFW.GLFW_GAMEPAD_BUTTON_DPAD_LEFT, "pick_block"); + public static final ButtonBinding PLAYER_LIST = new ButtonBinding(GLFW.GLFW_GAMEPAD_BUTTON_BACK, "player_list"); + public static final ButtonBinding RIGHT = new ButtonBinding(axis_as_button(GLFW.GLFW_GAMEPAD_AXIS_LEFT_X, true), "right"); + public static final ButtonBinding SCREENSHOT = new ButtonBinding(GLFW.GLFW_GAMEPAD_BUTTON_DPAD_DOWN, "screenshot", + Collections.singletonList((client, action) -> { + ScreenshotUtils.method_1659(client.runDirectory, client.window.getFramebufferWidth(), client.window.getFramebufferHeight(), client.getFramebuffer(), + text -> client.execute(() -> client.inGameHud.getChatHud().addMessage(text))); + return true; + })); + public static final ButtonBinding SMOOTH_CAMERA = new ButtonBinding(-1, "toggle_smooth_camera"); + public static final ButtonBinding SNEAK = new ButtonBinding(GLFW.GLFW_GAMEPAD_BUTTON_RIGHT_THUMB, "sneak"); + public static final ButtonBinding SPRINT = new ButtonBinding(GLFW.GLFW_GAMEPAD_BUTTON_LEFT_THUMB, "sprint"); + public static final ButtonBinding SWAP_HANDS = new ButtonBinding(GLFW.GLFW_GAMEPAD_BUTTON_X, "swap_hands"); + public static final ButtonBinding TOGGLE_PERSPECTIVE = new ButtonBinding(GLFW.GLFW_GAMEPAD_BUTTON_DPAD_UP, "toggle_perspective"); + public static final ButtonBinding USE = new ButtonBinding(axis_as_button(GLFW.GLFW_GAMEPAD_AXIS_LEFT_TRIGGER, true), "use"); - private int button; - private String key; - private KeyBinding minecraft_key_binding = null; - private boolean pressed = false; + private int button; + private int default_button; + private String key; + private KeyBinding minecraft_key_binding = null; + private List actions = new ArrayList<>(Collections.singletonList((client, action) -> { + this.as_key_binding().ifPresent(key_binding -> ((KeyBindingAccessor) key_binding).handle_press_state(this.is_button_down())); + return true; + })); + private boolean pressed = false; + + public ButtonBinding(int button, @NotNull String key, @NotNull List actions) + { + this.default_button = this.button = button; + this.key = key; + this.actions.addAll(actions); + BINDINGS.add(this); + } public ButtonBinding(int button, @NotNull String key) { - this.button = button; - this.key = key; - BINDINGS.add(this); + this(button, key, Collections.emptyList()); } /** @@ -62,6 +95,11 @@ public class ButtonBinding implements Nameable return this.button; } + /** + * Sets the bound button. + * + * @param button The bound button. + */ public void set_button(int button) { this.button = button; @@ -88,6 +126,36 @@ public class ButtonBinding implements Nameable return this.pressed; } + /** + * Returns whether this button binding is bound or not. + * + * @return True if this button binding is bound, else false. + */ + public boolean is_not_bound() + { + return this.button == -1; + } + + /** + * Gets the default button assigned to this binding. + * + * @return The default button. + */ + public int get_default_button() + { + return this.default_button; + } + + /** + * Returns whether the assigned button is the default button. + * + * @return True if the assigned button is the default button, else false. + */ + public boolean is_default() + { + return this.button == this.default_button; + } + @Override public @NotNull String get_name() { @@ -139,13 +207,29 @@ public class ButtonBinding implements Nameable public static void init(@NotNull GameOptions options) { + ATTACK.minecraft_key_binding = options.keyAttack; BACK.minecraft_key_binding = options.keyBack; + CHAT.minecraft_key_binding = options.keyChat; DROP_ITEM.minecraft_key_binding = options.keyDrop; FORWARD.minecraft_key_binding = options.keyForward; INVENTORY.minecraft_key_binding = options.keyInventory; JUMP.minecraft_key_binding = options.keyJump; + LEFT.minecraft_key_binding = options.keyLeft; + PICK_BLOCK.minecraft_key_binding = options.keyPickItem; + PLAYER_LIST.minecraft_key_binding = options.keyPlayerList; + RIGHT.minecraft_key_binding = options.keyRight; + SCREENSHOT.minecraft_key_binding = options.keyScreenshot; + SMOOTH_CAMERA.minecraft_key_binding = options.keySmoothCamera; + SNEAK.minecraft_key_binding = options.keySneak; SPRINT.minecraft_key_binding = options.keySprint; SWAP_HANDS.minecraft_key_binding = options.keySwapHands; + TOGGLE_PERSPECTIVE.minecraft_key_binding = options.keyTogglePerspective; + USE.minecraft_key_binding = options.keyUse; + } + + public static void load_from_config(@NotNull LambdaControlsConfig config) + { + BINDINGS.forEach(config::load_button_binding); } public static void set_button_state(int button, boolean state) @@ -154,10 +238,144 @@ public class ButtonBinding implements Nameable .forEach(binding -> binding.pressed = state); } - public static void handle_button(int button, boolean state) + public static void handle_button(@NotNull MinecraftClient client, int button, int action) { BINDINGS.parallelStream().filter(binding -> binding.button == button) - .map(ButtonBinding::as_key_binding) - .forEach(binding -> binding.ifPresent(key_binding -> ((KeyBindingAccessor) key_binding).handle_press_state(state))); + .forEach(binding -> { + for (int i = binding.actions.size() - 1; i >= 0; i--) { + if (binding.actions.get(i).press(client, action)) + break; + } + }); + } + + /** + * Returns whether the button has duplicated bindings. + * + * @param button The button to check. + * @return True if the button has duplicated bindings, else false. + */ + public static boolean has_duplicates(int button) + { + return BINDINGS.parallelStream().filter(binding -> binding.button == button).count() > 1; + } + + /** + * Returns the localized name of the specified button. + * + * @param button The button. + * @return The localized name of the button. + */ + public static @NotNull String get_localized_button_name(int button) + { + switch (button) { + case -1: + return I18n.translate("key.keyboard.unknown"); + case GLFW.GLFW_GAMEPAD_BUTTON_A: + return I18n.translate("lambdacontrols.button.a"); + case GLFW.GLFW_GAMEPAD_BUTTON_B: + return I18n.translate("lambdacontrols.button.b"); + case GLFW.GLFW_GAMEPAD_BUTTON_X: + return I18n.translate("lambdacontrols.button.x"); + case GLFW.GLFW_GAMEPAD_BUTTON_Y: + return I18n.translate("lambdacontrols.button.y"); + case GLFW.GLFW_GAMEPAD_BUTTON_LEFT_BUMPER: + return I18n.translate("lambdacontrols.button.left_bumper"); + case GLFW.GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER: + return I18n.translate("lambdacontrols.button.right_bumper"); + case GLFW.GLFW_GAMEPAD_BUTTON_BACK: + return I18n.translate("lambdacontrols.button.back"); + case GLFW.GLFW_GAMEPAD_BUTTON_START: + return I18n.translate("lambdacontrols.button.start"); + case GLFW.GLFW_GAMEPAD_BUTTON_GUIDE: + return I18n.translate("lambdacontrols.button.guide"); + case GLFW.GLFW_GAMEPAD_BUTTON_LEFT_THUMB: + return I18n.translate("lambdacontrols.button.left_thumb"); + case GLFW.GLFW_GAMEPAD_BUTTON_RIGHT_THUMB: + return I18n.translate("lambdacontrols.button.right_thumb"); + case GLFW.GLFW_GAMEPAD_BUTTON_DPAD_UP: + return I18n.translate("lambdacontrols.button.dpad_up"); + case GLFW.GLFW_GAMEPAD_BUTTON_DPAD_RIGHT: + return I18n.translate("lambdacontrols.button.dpad_right"); + case GLFW.GLFW_GAMEPAD_BUTTON_DPAD_DOWN: + return I18n.translate("lambdacontrols.button.dpad_down"); + case GLFW.GLFW_GAMEPAD_BUTTON_DPAD_LEFT: + return I18n.translate("lambdacontrols.button.dpad_left"); + case 100: + return I18n.translate("lambdacontrols.axis.left_x+"); + case 101: + return I18n.translate("lambdacontrols.axis.left_y+"); + case 102: + return I18n.translate("lambdacontrols.axis.right_x+"); + case 103: + return I18n.translate("lambdacontrols.axis.right_y+"); + case 104: + return I18n.translate("lambdacontrols.axis.left_trigger"); + case 105: + return I18n.translate("lambdacontrols.axis.right_trigger"); + case 200: + return I18n.translate("lambdacontrols.axis.left_x-"); + case 201: + return I18n.translate("lambdacontrols.axis.left_y-"); + case 202: + return I18n.translate("lambdacontrols.axis.right_x-"); + case 203: + return I18n.translate("lambdacontrols.axis.right_y-"); + default: + return I18n.translate("lambdacontrols.button.unknown", button); + } + } + + public static @NotNull Stream stream() + { + return BINDINGS.stream(); + } + + public static @NotNull Stream, List>> stream_categories() + { + return CATEGORIES.entrySet().stream(); + } + + static { + CATEGORIES.put(Pair.of(MOVEMENT_CATEGORY, 0), Arrays.asList( + FORWARD, + BACK, + LEFT, + RIGHT, + JUMP, + SNEAK, + SPRINT + )); + CATEGORIES.put(Pair.of(GAMEPLAY_CATEGORY, 1), Arrays.asList( + ATTACK, + PICK_BLOCK, + USE + )); + CATEGORIES.put(Pair.of(INVENTORY_CATEGORY, 2), Arrays.asList( + DROP_ITEM, + INVENTORY, + SWAP_HANDS + )); + CATEGORIES.put(Pair.of(MULTIPLAYER_CATEGORY, 2), Arrays.asList( + CHAT, + PLAYER_LIST + )); + CATEGORIES.put(Pair.of(MISC_CATEGORY, 3), Arrays.asList( + SCREENSHOT, + //SMOOTH_CAMERA, + TOGGLE_PERSPECTIVE + )); + } + + @FunctionalInterface + public static interface PressAction + { + /** + * Handles when there is a press action on the button. + * + * @param client The client instance. + * @param action The action done. + */ + boolean press(@NotNull MinecraftClient client, int action); } } diff --git a/src/main/java/me/lambdaurora/lambdacontrols/Controller.java b/src/main/java/me/lambdaurora/lambdacontrols/Controller.java index b7aec85..ef7f367 100644 --- a/src/main/java/me/lambdaurora/lambdacontrols/Controller.java +++ b/src/main/java/me/lambdaurora/lambdacontrols/Controller.java @@ -147,7 +147,6 @@ public class Controller implements Nameable try (SeekableByteChannel fc = Files.newByteChannel(path)) { buffer = createByteBuffer((int) fc.size() + 2); while (fc.read(buffer) != -1) { - ; } buffer.put((byte) 0); } diff --git a/src/main/java/me/lambdaurora/lambdacontrols/ControllerInput.java b/src/main/java/me/lambdaurora/lambdacontrols/ControllerInput.java index 68af7aa..16dfa15 100644 --- a/src/main/java/me/lambdaurora/lambdacontrols/ControllerInput.java +++ b/src/main/java/me/lambdaurora/lambdacontrols/ControllerInput.java @@ -9,6 +9,8 @@ package me.lambdaurora.lambdacontrols; +import me.lambdaurora.lambdacontrols.gui.LambdaControlsControlsScreen; +import me.lambdaurora.lambdacontrols.mixin.EntryListWidgetAccessor; import me.lambdaurora.lambdacontrols.util.AbstractContainerScreenAccessor; import me.lambdaurora.lambdacontrols.util.CreativeInventoryScreenAccessor; import me.lambdaurora.lambdacontrols.util.KeyBindingAccessor; @@ -20,8 +22,11 @@ import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.advancement.AdvancementsScreen; import net.minecraft.client.gui.screen.ingame.AbstractContainerScreen; import net.minecraft.client.gui.screen.ingame.CreativeInventoryScreen; +import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen; +import net.minecraft.client.gui.screen.multiplayer.MultiplayerServerListWidget; import net.minecraft.client.gui.screen.world.WorldListWidget; import net.minecraft.client.gui.widget.AbstractPressableButtonWidget; +import net.minecraft.client.gui.widget.AlwaysSelectedEntryListWidget; import net.minecraft.client.gui.widget.SliderWidget; import net.minecraft.container.Slot; import net.minecraft.container.SlotActionType; @@ -40,8 +45,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Optional; -import static me.lambdaurora.lambdacontrols.ButtonBinding.PAUSE_GAME; -import static me.lambdaurora.lambdacontrols.ButtonBinding.SNEAK; +import static me.lambdaurora.lambdacontrols.ButtonBinding.*; import static org.lwjgl.glfw.GLFW.GLFW_GAMEPAD_AXIS_RIGHT_X; import static org.lwjgl.glfw.GLFW.GLFW_GAMEPAD_AXIS_RIGHT_Y; @@ -109,7 +113,7 @@ public class ControllerInput public void on_pre_render_screen(@NotNull MinecraftClient client, @NotNull Screen screen) { - if (!this.is_screen_interactive(screen)) { + if (!is_screen_interactive(screen)) { if (this.prev_target_mouse_x != this.target_mouse_x || this.prev_target_mouse_y != this.target_mouse_y) { double mouse_x = this.prev_target_mouse_x + (this.target_mouse_x - this.prev_target_mouse_x) * client.getTickDelta() + 0.5; double mouse_y = this.prev_target_mouse_y + (this.target_mouse_y - this.prev_target_mouse_y) * client.getTickDelta() + 0.5; @@ -172,6 +176,12 @@ public class ControllerInput float value = buffer.get(); float abs_value = Math.abs(value); + if (i == GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y) + value *= -1.0F; + + ButtonBinding.set_button_state(axis_as_button(i, true), value > 0.5F); + ButtonBinding.set_button_state(axis_as_button(i, false), value < -0.5F); + int state = value > this.config.get_dead_zone() ? 1 : (value < -this.config.get_dead_zone() ? 2 : 0); this.handle_axe(client, i, value, abs_value, state); } @@ -179,12 +189,38 @@ public class ControllerInput private void handle_button(@NotNull MinecraftClient client, int button, int action, boolean state) { + if (client.currentScreen instanceof LambdaControlsControlsScreen && action == 0) { + LambdaControlsControlsScreen controls_screen = (LambdaControlsControlsScreen) client.currentScreen; + if (controls_screen.focused_binding != null) { + this.config.set_button_binding(controls_screen.focused_binding, button); + controls_screen.focused_binding = null; + return; + } + } + if (action == 0 || action == 2) { // Handles RB and LB buttons. if (button == GLFW.GLFW_GAMEPAD_BUTTON_LEFT_BUMPER || button == GLFW.GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER) { this.handle_rb_lb(client, button == GLFW.GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER); return; } + + if (client.currentScreen != null && is_screen_interactive(client.currentScreen) + && (button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_UP || button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_DOWN + || button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_LEFT || button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_RIGHT)) { + if (this.action_gui_cooldown == 0) { + if (button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_UP) { + this.change_focus(client.currentScreen, false); + } else if (button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_DOWN) { + this.change_focus(client.currentScreen, true); + } else if (button == GLFW.GLFW_GAMEPAD_BUTTON_DPAD_LEFT) { + this.handle_left_right(client.currentScreen, false); + } else { + this.handle_left_right(client.currentScreen, true); + } + } + return; + } } if (action == 0) { @@ -203,8 +239,8 @@ public class ControllerInput if (button == GLFW.GLFW_GAMEPAD_BUTTON_A && client.currentScreen != null) { if (this.action_gui_cooldown == 0) { Element focused = client.currentScreen.getFocused(); - if (focused != null && this.is_screen_interactive(client.currentScreen)) { - if (this.handle_a_button(focused)) { + if (focused != null && is_screen_interactive(client.currentScreen)) { + if (this.handle_a_button(client.currentScreen, focused)) { this.action_gui_cooldown = 5; // Prevent to press too quickly the focused element, so we have to skip 5 ticks. return; } @@ -243,7 +279,7 @@ public class ControllerInput } } - if (button == GLFW.GLFW_GAMEPAD_BUTTON_A && client.currentScreen != null && !this.is_screen_interactive(client.currentScreen) && this.action_gui_cooldown == 0 && this.ignore_next_a == 0) { + if (button == GLFW.GLFW_GAMEPAD_BUTTON_A && client.currentScreen != null && !is_screen_interactive(client.currentScreen) && this.action_gui_cooldown == 0 && this.ignore_next_a == 0) { double mouse_x = client.mouse.getX() * (double) client.window.getScaledWidth() / (double) client.window.getWidth(); double mouse_y = client.mouse.getY() * (double) client.window.getScaledHeight() / (double) client.window.getHeight(); if (action == 0) { @@ -256,24 +292,35 @@ public class ControllerInput } if (client.currentScreen == null && action != 2) { - ButtonBinding.handle_button(button, state); + ButtonBinding.handle_button(client, button, action); } } private void handle_axe(@NotNull MinecraftClient client, int axis, float value, float abs_value, int state) { int as_button_state = value > 0.5F ? 1 : (value < -0.5F ? 2 : 0); + + if (client.currentScreen instanceof LambdaControlsControlsScreen && as_button_state != 0 + && !(as_button_state == 2 && (axis == GLFW.GLFW_GAMEPAD_AXIS_LEFT_TRIGGER || axis == GLFW.GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER))) { + LambdaControlsControlsScreen controls_screen = (LambdaControlsControlsScreen) client.currentScreen; + if (controls_screen.focused_binding != null) { + this.config.set_button_binding(controls_screen.focused_binding, axis_as_button(axis, as_button_state == 1)); + controls_screen.focused_binding = null; + return; + } + } + double dead_zone = this.config.get_dead_zone(); if (client.currentScreen == null) { { - int axis_minus = axis + 10; + int axis_minus = axis + 100; boolean current_plus_state = as_button_state == 1; boolean current_minus_state = as_button_state == 2; boolean previous_plus_state = AXIS_STATES.getOrDefault(axis, false); boolean previous_minus_state = AXIS_STATES.getOrDefault(axis_minus, false); if (current_plus_state != previous_plus_state) { - this.config.get_keybind("axis_" + axis + "+").ifPresent(key_binding -> ((KeyBindingAccessor) key_binding).handle_press_state(current_plus_state)); + ButtonBinding.handle_button(client, ButtonBinding.axis_as_button(axis, true), 0); if (current_plus_state) AXIS_COOLDOWNS.put(axis, 5); } else if (current_plus_state) { @@ -283,7 +330,7 @@ public class ControllerInput } if (current_minus_state != previous_minus_state) { - this.config.get_keybind("axis_" + axis + "-").ifPresent(key_binding -> ((KeyBindingAccessor) key_binding).handle_press_state(current_minus_state)); + ButtonBinding.handle_button(client, ButtonBinding.axis_as_button(axis, false), 0); if (current_minus_state) AXIS_COOLDOWNS.put(axis_minus, 5); } else if (current_minus_state) { @@ -298,27 +345,28 @@ public class ControllerInput // Handles the look direction. if (client.player != null) { + double pow_value = Math.pow(abs_value, 2.0); if (axis == GLFW_GAMEPAD_AXIS_RIGHT_Y) { if (state == 2) { - this.target_pitch = client.player.pitch - this.config.get_right_y_axis_sign() * (this.config.get_rotation_speed() * (abs_value + dead_zone) / (1.0 - dead_zone)) * 0.33D; + this.target_pitch = client.player.pitch - this.config.get_right_y_axis_sign() * (this.config.get_rotation_speed() * pow_value) * 0.33D; this.target_pitch = MathHelper.clamp(this.target_pitch, -90.0D, 90.0D); } else if (state == 1) { - this.target_pitch = client.player.pitch + this.config.get_right_y_axis_sign() * (this.config.get_rotation_speed() * (abs_value - dead_zone) / (1.0 - dead_zone)) * 0.33D; + this.target_pitch = client.player.pitch + this.config.get_right_y_axis_sign() * (this.config.get_rotation_speed() * pow_value) * 0.33D; this.target_pitch = MathHelper.clamp(this.target_pitch, -90.0D, 90.0D); } } if (axis == GLFW_GAMEPAD_AXIS_RIGHT_X) { if (state == 2) { - this.target_yaw = client.player.yaw - this.config.get_right_x_axis_sign() * (this.config.get_rotation_speed() * (abs_value + dead_zone) / (1.0 - dead_zone)) * 0.33D; + this.target_yaw = client.player.yaw - this.config.get_right_x_axis_sign() * (this.config.get_rotation_speed() * pow_value) * 0.33D; } else if (state == 1) { - this.target_yaw = client.player.yaw + this.config.get_right_x_axis_sign() * (this.config.get_rotation_speed() * (abs_value + dead_zone) / (1.0 - dead_zone)) * 0.33D; + this.target_yaw = client.player.yaw + this.config.get_right_x_axis_sign() * (this.config.get_rotation_speed() * pow_value) * 0.33D; } } } } else { boolean allow_mouse_control = true; - if (this.action_gui_cooldown == 0 && this.config.is_movement_axis(axis) && this.is_screen_interactive(client.currentScreen)) { + if (this.action_gui_cooldown == 0 && this.config.is_movement_axis(axis) && is_screen_interactive(client.currentScreen)) { if (this.config.is_forward_button(axis, false, as_button_state)) { allow_mouse_control = this.change_focus(client.currentScreen, false); } else if (this.config.is_back_button(axis, false, as_button_state)) { @@ -412,7 +460,7 @@ public class ControllerInput } } - private boolean handle_a_button(@NotNull Element focused) + private boolean handle_a_button(@NotNull Screen screen, @NotNull Element focused) { if (focused instanceof AbstractPressableButtonWidget) { AbstractPressableButtonWidget button_widget = (AbstractPressableButtonWidget) focused; @@ -423,10 +471,17 @@ public class ControllerInput WorldListWidget list = (WorldListWidget) focused; list.method_20159().ifPresent(WorldListWidget.LevelItem::play); return true; + } else if (focused instanceof MultiplayerServerListWidget) { + MultiplayerServerListWidget list = (MultiplayerServerListWidget) focused; + MultiplayerServerListWidget.Entry entry = list.getSelected(); + if (entry instanceof MultiplayerServerListWidget.LanServerListEntry || entry instanceof MultiplayerServerListWidget.ServerItem) { + ((MultiplayerScreen) screen).selectEntry(entry); + ((MultiplayerScreen) screen).connect(); + } } else if (focused instanceof ParentElement) { Element child_focused = ((ParentElement) focused).getFocused(); if (child_focused != null) - return this.handle_a_button(child_focused); + return this.handle_a_button(screen, child_focused); } return false; } @@ -452,6 +507,9 @@ public class ControllerInput slider.keyPressed(right ? 262 : 263, 0, 0); this.action_gui_cooldown = 2; // Prevent to press too quickly the focused element, so we have to skip 5 ticks. return false; + } else if (element instanceof AlwaysSelectedEntryListWidget) { + ((EntryListWidgetAccessor) element).move_selection(right ? 1 : -1); + return false; } else if (element instanceof ParentElement) { ParentElement entry_list = (ParentElement) element; Element focused = entry_list.getFocused(); @@ -486,7 +544,7 @@ public class ControllerInput } } - private boolean is_screen_interactive(@NotNull Screen screen) + static boolean is_screen_interactive(@NotNull Screen screen) { return !(screen instanceof AdvancementsScreen || screen instanceof AbstractContainerScreen); } diff --git a/src/main/java/me/lambdaurora/lambdacontrols/ControllerType.java b/src/main/java/me/lambdaurora/lambdacontrols/ControllerType.java index 83899fc..833bba7 100644 --- a/src/main/java/me/lambdaurora/lambdacontrols/ControllerType.java +++ b/src/main/java/me/lambdaurora/lambdacontrols/ControllerType.java @@ -22,7 +22,7 @@ import java.util.Optional; public enum ControllerType implements Nameable { DEFAULT(0), - PLAYSTATION(1), + DUALSHOCK(1), SWITCH(2), XBOX(3), STEAM(4), diff --git a/src/main/java/me/lambdaurora/lambdacontrols/LambdaControls.java b/src/main/java/me/lambdaurora/lambdacontrols/LambdaControls.java index fbd9040..08fdc56 100644 --- a/src/main/java/me/lambdaurora/lambdacontrols/LambdaControls.java +++ b/src/main/java/me/lambdaurora/lambdacontrols/LambdaControls.java @@ -50,7 +50,6 @@ public class LambdaControls implements ClientModInitializer { Controller.update_mappings(); ButtonBinding.init(client.options); - this.config.init_keybindings(client.options); GLFW.glfwSetJoystickCallback((jid, event) -> { if (event == GLFW.GLFW_CONNECTED) { Controller controller = Controller.by_id(jid); diff --git a/src/main/java/me/lambdaurora/lambdacontrols/LambdaControlsConfig.java b/src/main/java/me/lambdaurora/lambdacontrols/LambdaControlsConfig.java index 0221568..83a53e2 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.options.GameOptions; import net.minecraft.client.options.KeyBinding; import org.jetbrains.annotations.NotNull; import org.lwjgl.glfw.GLFW; @@ -19,8 +18,6 @@ import java.util.HashMap; import java.util.Map; import java.util.Optional; -import static org.lwjgl.glfw.GLFW.*; - /** * Represents LambdaControls configuration. */ @@ -38,11 +35,6 @@ public class LambdaControlsConfig private double dead_zone; private double rotation_speed; private double mouse_speed; - // Controller controls - private String back_button; - private String forward_button; - private String left_button; - private String right_button; public LambdaControlsConfig(@NotNull LambdaControls mod) { @@ -64,29 +56,7 @@ public class LambdaControlsConfig this.rotation_speed = this.config.getOrElse("controller.rotation_speed", 40.0); this.mouse_speed = this.config.getOrElse("controller.mouse_speed", 25.0); // Controller controls. - this.back_button = this.config.getOrElse("controller.controls.back", "none").toLowerCase(); - this.forward_button = this.config.getOrElse("controller.controls.forward", "none").toLowerCase(); - this.left_button = this.config.getOrElse("controller.controls.left", "none").toLowerCase(); - this.right_button = this.config.getOrElse("controller.controls.right", "none").toLowerCase(); - } - - public void init_keybindings(GameOptions options) - { - this.keybinding_mappings.put("axis_" + GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER + "+", options.keyAttack); - this.keybinding_mappings.put("axis_" + GLFW_GAMEPAD_AXIS_LEFT_TRIGGER + "+", options.keyUse); - this.keybinding_mappings.put("axis_" + GLFW_GAMEPAD_AXIS_LEFT_X + "+", options.keyRight); - this.keybinding_mappings.put("axis_" + GLFW_GAMEPAD_AXIS_LEFT_X + "-", options.keyLeft); - this.keybinding_mappings.put("axis_" + GLFW_GAMEPAD_AXIS_LEFT_Y + "+", options.keyBack); - this.keybinding_mappings.put("axis_" + GLFW_GAMEPAD_AXIS_LEFT_Y + "-", options.keyForward); - this.keybinding_mappings.put("button_" + GLFW_GAMEPAD_BUTTON_A, options.keyJump); - this.keybinding_mappings.put("button_" + GLFW_GAMEPAD_BUTTON_B, options.keyDrop); - this.keybinding_mappings.put("button_" + GLFW_GAMEPAD_BUTTON_X, options.keySwapHands); - this.keybinding_mappings.put("button_" + GLFW_GAMEPAD_BUTTON_Y, options.keyInventory); - this.keybinding_mappings.put("button_" + GLFW_GAMEPAD_BUTTON_BACK, options.keyPlayerList); - this.keybinding_mappings.put("button_" + GLFW_GAMEPAD_BUTTON_GUIDE, options.keyScreenshot); - this.keybinding_mappings.put("button_" + GLFW_GAMEPAD_BUTTON_RIGHT_THUMB, options.keySneak); - this.keybinding_mappings.put("button_" + GLFW_GAMEPAD_BUTTON_LEFT_THUMB, options.keySprint); - this.keybinding_mappings.put("button_" + GLFW_GAMEPAD_BUTTON_DPAD_UP, options.keyTogglePerspective); + ButtonBinding.load_from_config(this); } public void save() @@ -343,52 +313,54 @@ public class LambdaControlsConfig return Optional.ofNullable(this.keybinding_mappings.get(id)); } - public String get_back_button() + /** + * Loads the button binding from configuration. + * + * @param button The button binding. + */ + public void load_button_binding(@NotNull ButtonBinding button) { - return this.back_button; + button.set_button(this.config.getOrElse("controller.controls." + button.get_name(), button.get_button())); } - public String get_forward_button() + /** + * Sets the button binding in configuration. + * + * @param binding The button binding. + * @param button The button. + */ + public void set_button_binding(@NotNull ButtonBinding binding, int button) { - return this.forward_button; - } - - public String get_left_button() - { - return this.left_button; - } - - public String get_right_button() - { - return this.right_button; + binding.set_button(button); + this.config.set("controller.controls." + binding.get_name(), button); } public boolean is_back_button(int btn, boolean is_btn, int state) { if (!is_btn && state == 0) return false; - return this.get_back_button().equals((is_btn ? "button_" : "axe_") + btn + (is_btn ? "" : (state == 1 ? "+" : "-"))); + return ButtonBinding.BACK.is_button(ButtonBinding.axis_as_button(btn, state == 1)); } public boolean is_forward_button(int btn, boolean is_btn, int state) { if (!is_btn && state == 0) return false; - return this.get_forward_button().equals((is_btn ? "button_" : "axe_") + btn + (is_btn ? "" : (state == 1 ? "+" : "-"))); + return ButtonBinding.FORWARD.is_button(ButtonBinding.axis_as_button(btn, state == 1)); } public boolean is_left_button(int btn, boolean is_btn, int state) { if (!is_btn && state == 0) return false; - return this.get_left_button().equals((is_btn ? "button_" : "axe_") + btn + (is_btn ? "" : (state == 1 ? "+" : "-"))); + return ButtonBinding.LEFT.is_button(ButtonBinding.axis_as_button(btn, state == 1)); } public boolean is_right_button(int btn, boolean is_btn, int state) { if (!is_btn && state == 0) return false; - return this.get_right_button().equals((is_btn ? "button_" : "axe_") + btn + (is_btn ? "" : (state == 1 ? "+" : "-"))); + return ButtonBinding.RIGHT.is_button(ButtonBinding.axis_as_button(btn, state == 1)); } /** @@ -399,7 +371,9 @@ public class LambdaControlsConfig */ public boolean is_movement_axis(int i) { - return this.get_forward_button().startsWith("axe_" + i) || this.get_back_button().startsWith("axe_" + i) || this.get_left_button().startsWith("axe_" + i) - || this.get_right_button().startsWith("axe_" + i); + return ButtonBinding.FORWARD.is_button(ButtonBinding.axis_as_button(i, true)) || ButtonBinding.FORWARD.is_button(ButtonBinding.axis_as_button(i, false)) + || ButtonBinding.BACK.is_button(ButtonBinding.axis_as_button(i, true)) || ButtonBinding.BACK.is_button(ButtonBinding.axis_as_button(i, false)) + || ButtonBinding.LEFT.is_button(ButtonBinding.axis_as_button(i, true)) || ButtonBinding.LEFT.is_button(ButtonBinding.axis_as_button(i, false)) + || ButtonBinding.RIGHT.is_button(ButtonBinding.axis_as_button(i, true)) || ButtonBinding.RIGHT.is_button(ButtonBinding.axis_as_button(i, false)); } } diff --git a/src/main/java/me/lambdaurora/lambdacontrols/gui/ControlsListWidget.java b/src/main/java/me/lambdaurora/lambdacontrols/gui/ControlsListWidget.java new file mode 100644 index 0000000..d8c1592 --- /dev/null +++ b/src/main/java/me/lambdaurora/lambdacontrols/gui/ControlsListWidget.java @@ -0,0 +1,183 @@ +/* + * 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.ButtonBinding; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.Element; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.gui.widget.ElementListWidget; +import net.minecraft.client.resource.language.I18n; +import net.minecraft.util.Formatting; +import org.aperlambda.lambdacommon.utils.Pair; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +/** + * Represents a control list widget. + */ +public class ControlsListWidget extends ElementListWidget +{ + private final LambdaControlsControlsScreen gui; + private int field_2733; + + public ControlsListWidget(@NotNull LambdaControlsControlsScreen gui, @NotNull MinecraftClient client) + { + super(client, gui.width + 45, gui.height, 43, gui.height - 32, 20); + this.gui = gui; + + ButtonBinding.stream_categories() + .sorted(Comparator.comparingInt(e -> e.getKey().get_value())) + .map(category -> Pair.of(category.getKey().get_key(), category.getValue())) + .forEach(category -> { + this.addEntry(new CategoryEntry(category.get_key())); + + category.get_value().forEach(binding -> { + int i = client.textRenderer.getStringWidth(I18n.translate(binding.get_translation_key())); + if (i > this.field_2733) { + this.field_2733 = i; + } + + this.addEntry(new ControlsListWidget.ButtonBindingEntry(binding)); + }); + }); + } + + @Override + protected int getScrollbarPosition() + { + return super.getScrollbarPosition() + 15; + } + + @Override + public int getRowWidth() + { + return super.getRowWidth() + 32; + } + + public class ButtonBindingEntry extends Entry + { + private final ButtonBinding binding; + private final String binding_name; + private final ButtonWidget edit_button; + private final ButtonWidget reset_button; + + ButtonBindingEntry(@NotNull ButtonBinding binding) + { + this.binding = binding; + this.binding_name = I18n.translate(this.binding.get_translation_key()); + this.edit_button = new ButtonWidget(0, 0, 75, 20, this.binding_name, btn -> gui.focused_binding = binding) + { + protected String getNarrationMessage() + { + return binding.is_not_bound() ? I18n.translate("narrator.controls.unbound", binding_name) : I18n.translate("narrator.controls.bound", binding_name, super.getNarrationMessage()); + } + }; + this.reset_button = new ButtonWidget(0, 0, 50, 20, I18n.translate("controls.reset"), + btn -> gui.mod.config.set_button_binding(binding, binding.get_default_button())) + { + protected String getNarrationMessage() + { + return I18n.translate("narrator.controls.reset", binding_name); + } + }; + } + + @Override + public List children() + { + return Collections.unmodifiableList(Arrays.asList(this.edit_button, this.reset_button)); + } + + @Override + public void render(int index, int y, int x, int width, int height, int mouse_x, int mouse_y, boolean hovering, float delta) + { + boolean focused = gui.focused_binding == this.binding; + TextRenderer text_renderer = ControlsListWidget.this.minecraft.textRenderer; + String binding_name = this.binding_name; + float var10002 = (float) (x + 90 - ControlsListWidget.this.field_2733); + int var10003 = y + height / 2; + text_renderer.draw(binding_name, var10002, (float) (var10003 - 9 / 2), 16777215); + this.reset_button.x = x + 190; + this.reset_button.y = y; + this.reset_button.active = !this.binding.is_default(); + this.reset_button.render(mouse_x, mouse_y, delta); + this.edit_button.x = x + 105; + this.edit_button.y = y; + this.edit_button.setMessage(ButtonBinding.get_localized_button_name(binding.get_button())); + + if (focused) { + this.edit_button.setMessage(Formatting.WHITE + "> " + Formatting.YELLOW + this.edit_button.getMessage() + Formatting.WHITE + " <"); + } else if (!this.binding.is_not_bound() && ButtonBinding.has_duplicates(this.binding.get_button())) { + this.edit_button.setMessage(Formatting.RED + this.edit_button.getMessage()); + } else if (this.binding.is_not_bound()) { + this.edit_button.setMessage(Formatting.GOLD + edit_button.getMessage()); + } + + this.edit_button.render(mouse_x, mouse_y, delta); + } + + public boolean mouseClicked(double mouseX, double mouseY, int button) + { + if (this.edit_button.mouseClicked(mouseX, mouseY, button)) + return true; + else + return this.reset_button.mouseClicked(mouseX, mouseY, button); + } + + public boolean mouseReleased(double mouseX, double mouseY, int button) + { + return this.edit_button.mouseReleased(mouseX, mouseY, button) || this.reset_button.mouseReleased(mouseX, mouseY, button); + } + } + + public class CategoryEntry extends Entry + { + private final String name; + private final int name_width; + + public CategoryEntry(String string) + { + this.name = I18n.translate(string); + this.name_width = ControlsListWidget.this.minecraft.textRenderer.getStringWidth(this.name); + } + + @Override + public void render(int index, int y, int x, int width, int height, int mouse_x, int mouse_y, boolean hovering, float delta) + { + ControlsListWidget.this.minecraft.textRenderer.draw(this.name, (float) (ControlsListWidget.this.minecraft.currentScreen.width / 2 - this.name_width / 2), + (float) ((y + height) - 9 - 1), 16777215); + } + + @Override + public boolean changeFocus(boolean bl) + { + return false; + } + + @Override + public List children() + { + return Collections.emptyList(); + } + } + + @Environment(EnvType.CLIENT) + public abstract static class Entry extends ElementListWidget.Entry + { + } +} diff --git a/src/main/java/me/lambdaurora/lambdacontrols/gui/LambdaControlsControlsScreen.java b/src/main/java/me/lambdaurora/lambdacontrols/gui/LambdaControlsControlsScreen.java new file mode 100644 index 0000000..841a239 --- /dev/null +++ b/src/main/java/me/lambdaurora/lambdacontrols/gui/LambdaControlsControlsScreen.java @@ -0,0 +1,93 @@ +/* + * 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.ButtonBinding; +import me.lambdaurora.lambdacontrols.LambdaControls; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.options.BooleanOption; +import net.minecraft.client.options.Option; +import net.minecraft.client.resource.language.I18n; +import net.minecraft.text.TranslatableText; +import org.jetbrains.annotations.NotNull; + +import java.util.Objects; +import java.util.function.Predicate; + +/** + * Represents the controls screen. + */ +public class LambdaControlsControlsScreen extends Screen +{ + private final LambdaControlsSettingsScreen parent; + final LambdaControls mod; + private final Option inverts_right_x_axis; + private final Option inverts_right_y_axis; + private ControlsListWidget bindings_list_widget; + private ButtonWidget reset_button; + public ButtonBinding focused_binding; + + protected LambdaControlsControlsScreen(@NotNull LambdaControlsSettingsScreen parent) + { + super(new TranslatableText("lambdacontrols.menu.title.controller_controls")); + this.parent = parent; + this.mod = parent.mod; + this.inverts_right_x_axis = new BooleanOption("lambdacontrols.menu.invert_right_x_axis", game_options -> this.mod.config.does_invert_right_x_axis(), + (game_options, new_value) -> { + synchronized (this.mod.config) { + this.mod.config.set_invert_right_x_axis(new_value); + } + }); + this.inverts_right_y_axis = new BooleanOption("lambdacontrols.menu.invert_right_y_axis", game_options -> this.mod.config.does_invert_right_y_axis(), + (game_options, new_value) -> { + synchronized (this.mod.config) { + this.mod.config.set_invert_right_y_axis(new_value); + } + }); + } + + @Override + public void removed() + { + this.mod.config.save(); + super.removed(); + } + + @Override + protected void init() + { + this.addButton(this.inverts_right_x_axis.createButton(this.minecraft.options, this.width / 2 - 155, 18, 150)); + this.addButton(this.inverts_right_y_axis.createButton(this.minecraft.options, this.width / 2 - 155 + 160, 18, 150)); + this.bindings_list_widget = new ControlsListWidget(this, this.minecraft); + this.children.add(this.bindings_list_widget); + this.reset_button = this.addButton(new ButtonWidget(this.width / 2 - 155, this.height - 29, 150, 20, I18n.translate("controls.resetAll"), + btn -> ButtonBinding.stream().forEach(binding -> this.mod.config.set_button_binding(binding, binding.get_default_button())))); + this.addButton(new ButtonWidget(this.width / 2 - 155 + 160, this.height - 29, 150, 20, I18n.translate("gui.done"), + btn -> this.minecraft.openScreen(this.parent))); + } + + // Replacement for Predicate#not as it is Java 11. + private Predicate not(Predicate target) + { + Objects.requireNonNull(target); + return target.negate(); + } + + @Override + public void render(int mouse_x, int mouse_y, float delta) + { + this.renderBackground(); + this.bindings_list_widget.render(mouse_x, mouse_y, delta); + this.drawCenteredString(this.font, this.title.asFormattedString(), this.width / 2, 8, 16777215); + this.reset_button.active = ButtonBinding.stream().anyMatch(this.not(ButtonBinding::is_default)); + super.render(mouse_x, mouse_y, delta); + } +} diff --git a/src/main/java/me/lambdaurora/lambdacontrols/gui/LambdaControlsSettingsScreen.java b/src/main/java/me/lambdaurora/lambdacontrols/gui/LambdaControlsSettingsScreen.java index d54bb8a..3c9c6ba 100644 --- a/src/main/java/me/lambdaurora/lambdacontrols/gui/LambdaControlsSettingsScreen.java +++ b/src/main/java/me/lambdaurora/lambdacontrols/gui/LambdaControlsSettingsScreen.java @@ -19,6 +19,7 @@ import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.options.*; import net.minecraft.client.resource.language.I18n; import net.minecraft.text.TranslatableText; +import net.minecraft.util.Formatting; import org.jetbrains.annotations.NotNull; import org.lwjgl.glfw.GLFW; @@ -27,7 +28,7 @@ import org.lwjgl.glfw.GLFW; */ public class LambdaControlsSettingsScreen extends Screen { - private final LambdaControls mod; + final LambdaControls mod; private final Screen parent; private final GameOptions options; private final Option controller_option; @@ -37,8 +38,6 @@ public class LambdaControlsSettingsScreen extends Screen private final Option dead_zone_option; private final Option rotation_speed_option; private final Option mouse_speed_option; - private final Option inverts_right_x_axis; - private final Option inverts_right_y_axis; private ButtonListWidget list; public LambdaControlsSettingsScreen(Screen parent, @NotNull GameOptions options) @@ -53,7 +52,13 @@ public class LambdaControlsSettingsScreen extends Screen if (current_id > GLFW.GLFW_JOYSTICK_LAST) current_id = GLFW.GLFW_JOYSTICK_1; this.mod.config.set_controller(Controller.by_id(current_id)); - }, (game_options, option) -> option.getDisplayPrefix() + this.mod.config.get_controller().get_name()); + }, (game_options, option) -> { + String controller_name = this.mod.config.get_controller().get_name(); + if (controller_name.equals(String.valueOf(this.mod.config.get_controller().get_id()))) + return option.getDisplayPrefix() + Formatting.RED + controller_name; + else + return option.getDisplayPrefix() + controller_name; + }); this.controller_type_option = new CyclingOption("lambdacontrols.menu.controller_type", (game_options, amount) -> this.mod.config.set_controller_type(this.mod.config.get_controller_type().next()), (game_options, option) -> option.getDisplayPrefix() + this.mod.config.get_controller_type().get_translated_name()); @@ -83,18 +88,6 @@ public class LambdaControlsSettingsScreen extends Screen this.mod.config.set_mouse_speed(new_value); } }, (game_options, option) -> option.getDisplayPrefix() + option.get(options)); - this.inverts_right_x_axis = new BooleanOption("lambdacontrols.menu.invert_right_x_axis", game_options -> this.mod.config.does_invert_right_x_axis(), - (game_options, new_value) -> { - synchronized (this.mod.config) { - this.mod.config.set_invert_right_x_axis(new_value); - } - }); - this.inverts_right_y_axis = new BooleanOption("lambdacontrols.menu.invert_right_y_axis", game_options -> this.mod.config.does_invert_right_y_axis(), - (game_options, new_value) -> { - synchronized (this.mod.config) { - this.mod.config.set_invert_right_y_axis(new_value); - } - }); } @Override @@ -129,14 +122,18 @@ public class LambdaControlsSettingsScreen extends Screen this.mod.config.save(); })); this.addButton(new ButtonWidget(this.width / 2 - 155 + 160, 18, 150, button_height, I18n.translate("options.controls"), - btn -> this.minecraft.openScreen(new ControlsOptionsScreen(this, this.options)))); + btn -> { + if (this.mod.config.get_controls_mode() == ControlsMode.CONTROLLER) + this.minecraft.openScreen(new LambdaControlsControlsScreen(this)); + else + this.minecraft.openScreen(new ControlsOptionsScreen(this, this.options)); + })); this.list = new ButtonListWidget(this.minecraft, this.width, this.height, 43, this.height - 29 - this.get_text_height(), 25); this.list.addSingleOptionEntry(this.controller_option); this.list.addOptionEntry(this.controller_type_option, this.dead_zone_option); this.list.addOptionEntry(this.hud_enable_option, this.hud_side_option); this.list.addOptionEntry(this.rotation_speed_option, this.mouse_speed_option); - this.list.addOptionEntry(this.inverts_right_x_axis, this.inverts_right_y_axis); this.children.add(this.list); this.addButton(new ButtonWidget(this.width / 2 - 155, this.height - 29, 300, button_height, I18n.translate("gui.done"), @@ -144,14 +141,14 @@ public class LambdaControlsSettingsScreen extends Screen } @Override - public void render(int mouseX, int mouseY, float delta) + public void render(int mouse_x, int mouse_y, float delta) { this.renderBackground(); - this.list.render(mouseX, mouseY, delta); - super.render(mouseX, mouseY, delta); + this.list.render(mouse_x, mouse_y, delta); + super.render(mouse_x, mouse_y, delta); this.drawCenteredString(this.font, I18n.translate("lambdacontrols.menu.title"), this.width / 2, 8, 16777215); - this.drawCenteredString(this.font, I18n.translate("lambdacontrols.controller.mappings.1"), this.width / 2, this.height - 29 - (5 + this.font.fontHeight) * 3, 10526880); - this.drawCenteredString(this.font, I18n.translate("lambdacontrols.controller.mappings.2"), this.width / 2, this.height - 29 - (5 + this.font.fontHeight) * 2, 10526880); - this.drawCenteredString(this.font, I18n.translate("lambdacontrols.controller.mappings.3"), this.width / 2, this.height - 29 - (5 + this.font.fontHeight), 10526880); + this.drawCenteredString(this.font, I18n.translate("lambdacontrols.controller.mappings.1", Formatting.GREEN.toString(), Formatting.RESET.toString()), this.width / 2, this.height - 29 - (5 + this.font.fontHeight) * 3, 10526880); + this.drawCenteredString(this.font, I18n.translate("lambdacontrols.controller.mappings.2", Formatting.GOLD.toString(), Formatting.RESET.toString()), this.width / 2, this.height - 29 - (5 + this.font.fontHeight) * 2, 10526880); + this.drawCenteredString(this.font, I18n.translate("lambdacontrols.controller.mappings.3", Formatting.GREEN.toString(), Formatting.RESET.toString()), this.width / 2, this.height - 29 - (5 + this.font.fontHeight), 10526880); } } diff --git a/src/main/java/me/lambdaurora/lambdacontrols/gui/TouchscreenOverlay.java b/src/main/java/me/lambdaurora/lambdacontrols/gui/TouchscreenOverlay.java index c88f704..0dcccd7 100644 --- a/src/main/java/me/lambdaurora/lambdacontrols/gui/TouchscreenOverlay.java +++ b/src/main/java/me/lambdaurora/lambdacontrols/gui/TouchscreenOverlay.java @@ -139,6 +139,7 @@ public class TouchscreenOverlay extends Screen this.update_jump_buttons(); } + @Override protected void init() { super.init(); diff --git a/src/main/java/me/lambdaurora/lambdacontrols/mixin/EntryListWidgetAccessor.java b/src/main/java/me/lambdaurora/lambdacontrols/mixin/EntryListWidgetAccessor.java new file mode 100644 index 0000000..07b92c3 --- /dev/null +++ b/src/main/java/me/lambdaurora/lambdacontrols/mixin/EntryListWidgetAccessor.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.mixin; + +import net.minecraft.client.gui.widget.EntryListWidget; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(EntryListWidget.class) +public interface EntryListWidgetAccessor +{ + @Invoker("moveSelection") + void move_selection(int amount); +} diff --git a/src/main/resources/assets/lambdacontrols/lang/en_us.json b/src/main/resources/assets/lambdacontrols/lang/en_us.json index 25bb470..84fca5d 100644 --- a/src/main/resources/assets/lambdacontrols/lang/en_us.json +++ b/src/main/resources/assets/lambdacontrols/lang/en_us.json @@ -1,26 +1,61 @@ { "lambdacontrols.action.attack": "Attack", "lambdacontrols.action.back": "Back", - "lambdacontrols.action.drop_item": "Drop item", + "lambdacontrols.action.chat": "Open Chat", + "lambdacontrols.action.drop_item": "Drop Item", "lambdacontrols.action.exit": "Exit", "lambdacontrols.action.forward": "Forward", "lambdacontrols.action.hit": "Hit", "lambdacontrols.action.inventory": "Inventory", "lambdacontrols.action.jump": "Jump", + "lambdacontrols.action.left": "Left", + "lambdacontrols.action.pause_game": "Pause Game", + "lambdacontrols.action.pick_block": "Pick Block", "lambdacontrols.action.pickup": "Pickup", "lambdacontrols.action.pickup_all": "Pickup all", + "lambdacontrols.action.player_list": "Player List", "lambdacontrols.action.quick_move": "Quick move", + "lambdacontrols.action.right": "Right", + "lambdacontrols.action.screenshot": "Take Screenshot", "lambdacontrols.action.sneak": "Sneak", "lambdacontrols.action.sprint": "Sprint", - "lambdacontrols.action.swap_hands": "Swap hands", + "lambdacontrols.action.swap_hands": "Swap Hands", + "lambdacontrols.action.toggle_perspective": "Toggle Perspective", + "lambdacontrols.action.toggle_smooth_camera": "Toggle Cinematic Camera", "lambdacontrols.action.use": "Use", + "lambdacontrols.button.a": "A", + "lambdacontrols.button.b": "B", + "lambdacontrols.button.x": "X", + "lambdacontrols.button.y": "Y", + "lambdacontrols.button.left_bumper": "Left bumper", + "lambdacontrols.button.right_bumper": "Right bumper", + "lambdacontrols.button.back": "Back", + "lambdacontrols.button.start": "Start", + "lambdacontrols.button.guide": "Guide", + "lambdacontrols.button.left_thumb": "Left thumb", + "lambdacontrols.button.right_thumb": "Right thumb", + "lambdacontrols.button.dpad_up": "DPAD up", + "lambdacontrols.button.dpad_right": "DPAD right", + "lambdacontrols.button.dpad_down": "DPAD down", + "lambdacontrols.button.dpad_left": "DPAD left", + "lambdacontrols.axis.left_x+": "Left X+", + "lambdacontrols.axis.left_y+": "Left Y+", + "lambdacontrols.axis.right_x+": "Right X+", + "lambdacontrols.axis.right_y+": "Right Y+", + "lambdacontrols.axis.left_trigger": "Left trigger", + "lambdacontrols.axis.right_trigger": "Right trigger", + "lambdacontrols.axis.left_x-": "Left X-", + "lambdacontrols.axis.left_y-": "Left Y-", + "lambdacontrols.axis.right_x-": "Right X-", + "lambdacontrols.axis.right_y-": "Right Y-", + "lambdacontrols.button.unknown": "Unknown (%d)", "lambdacontrols.controller.connected": "Controller %d connected.", "lambdacontrols.controller.disconnected": "Controller %d disconnected.", - "lambdacontrols.controller.mappings.1": "To configure the controller mappings, please use SDL2 Gamepad Tool", - "lambdacontrols.controller.mappings.2": "(http://generalarcade.com/gamepadtool/),", - "lambdacontrols.controller.mappings.3": "and put the mapping in `config/gamecontrollerdb.txt`.", + "lambdacontrols.controller.mappings.1": "To configure the controller mappings, please use %sSDL2 Gamepad Tool%s", + "lambdacontrols.controller.mappings.2": "(%shttp://generalarcade.com/gamepadtool/%s),", + "lambdacontrols.controller.mappings.3": "and put the mapping in `%sconfig/gamecontrollerdb.txt%s`.", "lambdacontrols.controller_type.default": "default", - "lambdacontrols.controller_type.playstation": "PlayStation", + "lambdacontrols.controller_type.dualshock": "DualShock", "lambdacontrols.controller_type.switch": "Switch", "lambdacontrols.controller_type.xbox": "Xbox", "lambdacontrols.controller_type.steam": "Steam", @@ -40,5 +75,6 @@ "lambdacontrols.menu.invert_right_y_axis": "Invert right Y", "lambdacontrols.menu.mouse_speed": "Mouse speed", "lambdacontrols.menu.rotation_speed": "Rotation speed", - "lambdacontrols.menu.title": "LambdaControls - Settings" + "lambdacontrols.menu.title": "LambdaControls - Settings", + "lambdacontrols.menu.title.controller_controls": "Controller controls" } \ No newline at end of file diff --git a/src/main/resources/assets/lambdacontrols/lang/fr_fr.json b/src/main/resources/assets/lambdacontrols/lang/fr_fr.json new file mode 100644 index 0000000..28aa8ed --- /dev/null +++ b/src/main/resources/assets/lambdacontrols/lang/fr_fr.json @@ -0,0 +1,80 @@ +{ + "lambdacontrols.action.attack": "Attaquer", + "lambdacontrols.action.back": "Reculer", + "lambdacontrols.action.chat": "Ouvrir le tchat", + "lambdacontrols.action.drop_item": "Jeter l'objet", + "lambdacontrols.action.exit": "Sortir", + "lambdacontrols.action.forward": "Avancer", + "lambdacontrols.action.hit": "Taper", + "lambdacontrols.action.inventory": "Inventaire", + "lambdacontrols.action.jump": "Sauter", + "lambdacontrols.action.left": "Aller à gauche", + "lambdacontrols.action.pause_game": "Mettre en pause le jeu", + "lambdacontrols.action.pick_block": "Choisir le bloc", + "lambdacontrols.action.pickup": "Prendre", + "lambdacontrols.action.pickup_all": "Prendre tout", + "lambdacontrols.action.player_list": "Afficher la liste des joueurs", + "lambdacontrols.action.quick_move": "Mouvement rapide", + "lambdacontrols.action.right": "Aller à droite", + "lambdacontrols.action.screenshot": "Prendre une capture d'écran", + "lambdacontrols.action.sneak": "S'accroupir", + "lambdacontrols.action.sprint": "Courir", + "lambdacontrols.action.swap_hands": "Échanger de mains", + "lambdacontrols.action.toggle_perspective": "Changer de point de vue", + "lambdacontrols.action.toggle_smooth_camera": "Basculer en mode cinématique", + "lambdacontrols.action.use": "Utiliser", + "lambdacontrols.button.a": "A", + "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.back": "Retour", + "lambdacontrols.button.start": "Touche Menu", + "lambdacontrols.button.guide": "Guide", + "lambdacontrols.button.left_thumb": "Stick analogique gauche", + "lambdacontrols.button.right_thumb": "Stick analogique droit", + "lambdacontrols.button.dpad_up": "D-Pad haut", + "lambdacontrols.button.dpad_right": "D-Pad droit", + "lambdacontrols.button.dpad_down": "D-Pad bas", + "lambdacontrols.button.dpad_left": "D-Pad gauche", + "lambdacontrols.axis.left_x+": "X+ Gauche", + "lambdacontrols.axis.left_y+": "Y+ Gauche", + "lambdacontrols.axis.right_x+": "X+ Droit", + "lambdacontrols.axis.right_y+": "Y+ Droit", + "lambdacontrols.axis.left_trigger": "Gâchette gauche", + "lambdacontrols.axis.right_trigger": "Gâchette droite", + "lambdacontrols.axis.left_x-": "X- Gauche", + "lambdacontrols.axis.left_y-": "Y- Gauche", + "lambdacontrols.axis.right_x-": "X- Droit", + "lambdacontrols.axis.right_y-": "Y- Droit", + "lambdacontrols.button.unknown": "Inconnu (%d)", + "lambdacontrols.controller.connected": "Manette %d connecté.", + "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.2": "(%shttp://generalarcade.com/gamepadtool/%s),", + "lambdacontrols.controller.mappings.3": "et mettez les correspondances dans le fichier `%sconfig/gamecontrollerdb.txt%s`.", + "lambdacontrols.controller_type.default": "default", + "lambdacontrols.controller_type.dualshock": "DualShock", + "lambdacontrols.controller_type.switch": "Switch", + "lambdacontrols.controller_type.xbox": "Xbox", + "lambdacontrols.controller_type.steam": "Steam", + "lambdacontrols.controller_type.ouya": "OUYA", + "lambdacontrols.controls_mode.default": "Clavier/Souris", + "lambdacontrols.controls_mode.controller": "Manette", + "lambdacontrols.controls_mode.touchscreen": "Tactile", + "lambdacontrols.hud_side.left": "gauche", + "lambdacontrols.hud_side.right": "droit", + "lambdacontrols.menu.controller": "Manette", + "lambdacontrols.menu.controller_type": "Type de manette", + "lambdacontrols.menu.controls_mode": "Mode de contrôle", + "lambdacontrols.menu.dead_zone": "Zone morte", + "lambdacontrols.menu.hud_enable": "Activer le HUD", + "lambdacontrols.menu.hud_side": "Côté du HUD", + "lambdacontrols.menu.invert_right_x_axis": "Inverser le joystick droit (X)", + "lambdacontrols.menu.invert_right_y_axis": "Inverser le joystick droit (Y)", + "lambdacontrols.menu.mouse_speed": "Vitesse de la souris", + "lambdacontrols.menu.rotation_speed": "Vitesse de rotation", + "lambdacontrols.menu.title": "LambdaControls - Paramètres", + "lambdacontrols.menu.title.controller_controls": "Contrôles de la manette" +} \ No newline at end of file diff --git a/src/main/resources/config.toml b/src/main/resources/config.toml index 43483c2..d790241 100644 --- a/src/main/resources/config.toml +++ b/src/main/resources/config.toml @@ -25,3 +25,39 @@ controls = "default" invert_right_x_axis = false # Inverts the right Y axis. invert_right_y_axis = false + # Controller controls. + [controller.controls] + # Attack control. + attack = 105 + # Back control. + back = 201 + # Open chat control. + chat = 12 + # Drop item control. + drop_item = 1 + # Forward control. + forward = 101 + # Inventory control. + inventory = 3 + # Jump control. + jump = 0 + # Pause game control. + pause_game = 7 + # Pick block control. + pick_block = 14 + # Show player list control. + player_list = 6 + # Take screenshot control. + screenshot = 13 + # Sneak control. + sneak = 10 + # Sprint control. + sprint = 9 + # Swap hands control. + swap_hands = 2 + # Toggle perspective control. + toggle_perspective = 11 + # Toggle smooth camera control. + toggle_smooth_camera = -1 + # Use control. + use = 104 diff --git a/src/main/resources/lambdacontrols.mixins.json b/src/main/resources/lambdacontrols.mixins.json index 65133a4..2c576b2 100644 --- a/src/main/resources/lambdacontrols.mixins.json +++ b/src/main/resources/lambdacontrols.mixins.json @@ -6,6 +6,7 @@ "AbstractButtonWidgetAccessor", "AbstractContainerScreenMixin", "CreativeInventoryScreenMixin", + "EntryListWidgetAccessor", "GameRendererMixin", "InGameHudMixin", "KeyBindingMixin",