Add better button management, the controls screen and more.

This commit is contained in:
LambdAurora
2019-12-08 23:40:16 +01:00
parent 82f67e7af9
commit 6b78d32e6f
20 changed files with 1061 additions and 128 deletions

35
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -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.

View File

@@ -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.

76
CODE_OF_CONDUCT.md Normal file
View File

@@ -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

103
CONTRIBUTING.md Normal file
View File

@@ -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).

View File

@@ -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.

View File

@@ -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<ButtonBinding> 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<ButtonBinding> BINDINGS = new ArrayList<>();
private static final Map<Pair<String, Integer>, List<ButtonBinding>> 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<PressAction> 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<PressAction> 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<ButtonBinding> stream()
{
return BINDINGS.stream();
}
public static @NotNull Stream<Map.Entry<Pair<String, Integer>, List<ButtonBinding>>> 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);
}
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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),

View File

@@ -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);

View File

@@ -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));
}
}

View File

@@ -0,0 +1,183 @@
/*
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
*
* 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<ControlsListWidget.Entry>
{
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<? extends Element> 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<? extends Element> children()
{
return Collections.emptyList();
}
}
@Environment(EnvType.CLIENT)
public abstract static class Entry extends ElementListWidget.Entry<Entry>
{
}
}

View File

@@ -0,0 +1,93 @@
/*
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
*
* 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 <T> Predicate<T> not(Predicate<T> 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);
}
}

View File

@@ -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);
}
}

View File

@@ -139,6 +139,7 @@ public class TouchscreenOverlay extends Screen
this.update_jump_buttons();
}
@Override
protected void init()
{
super.init();

View File

@@ -0,0 +1,21 @@
/*
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
*
* 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);
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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

View File

@@ -6,6 +6,7 @@
"AbstractButtonWidgetAccessor",
"AbstractContainerScreenMixin",
"CreativeInventoryScreenMixin",
"EntryListWidgetAccessor",
"GameRendererMixin",
"InGameHudMixin",
"KeyBindingMixin",