Add controller settings GUI and more WIP on controller support.

This commit is contained in:
LambdAurora
2019-12-01 23:07:54 +01:00
parent 6f09036814
commit 4fe7f70ffa
17 changed files with 1111 additions and 142 deletions

View File

@@ -0,0 +1,487 @@
/*
* 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;
import me.lambdaurora.lambdacontrols.mixin.AbstractContainerScreenAccessor;
import me.lambdaurora.lambdacontrols.util.CreativeInventoryScreenAccessor;
import me.lambdaurora.lambdacontrols.util.LambdaKeyBinding;
import me.lambdaurora.lambdacontrols.util.MouseAccessor;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.Element;
import net.minecraft.client.gui.ParentElement;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.ingame.AbstractContainerScreen;
import net.minecraft.client.gui.screen.ingame.CreativeInventoryScreen;
import net.minecraft.client.gui.screen.world.WorldListWidget;
import net.minecraft.client.gui.widget.*;
import net.minecraft.client.options.KeyBinding;
import net.minecraft.container.Slot;
import net.minecraft.item.ItemGroup;
import net.minecraft.util.math.MathHelper;
import org.aperlambda.lambdacommon.utils.Pair;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.glfw.GLFW;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
public class ControllerInput
{
private static final Map<Integer, Boolean> BUTTON_STATES = new HashMap<>();
private static final Map<Integer, Integer> BUTTON_COOLDOWNS = new HashMap<>();
private static final Map<Integer, Float> AXE_STATES = new HashMap<>();
private final LambdaControls mod;
private final LambdaControlsConfig config;
private int controller = GLFW.GLFW_JOYSTICK_3;
private int action_gui_cooldown = 0;
private boolean last_a_state = false;
private boolean continuous_sneak = false;
private int last_sneak = 0;
private double prev_target_yaw = 0.0;
private double prev_target_pitch = 0.0;
private double target_yaw = 0.0;
private double target_pitch = 0.0;
private float prev_x_axis = 0.F;
private float prev_y_axis = 0.F;
private int prev_target_mouse_x = 0;
private int prev_target_mouse_y = 0;
private int target_mouse_x = 0;
private int target_mouse_y = 0;
private float mouse_speed_x = 0.F;
private float mouse_speed_y = 0.F;
public ControllerInput(@NotNull LambdaControls mod)
{
this.mod = mod;
this.config = mod.config;
}
/**
* This method is called every Minecraft tick.
*
* @param client The client instance.
*/
public void on_tick(@NotNull MinecraftClient client)
{
BUTTON_COOLDOWNS.entrySet().stream().filter(entry -> entry.getValue() > 0).forEach(entry -> BUTTON_COOLDOWNS.put(entry.getKey(), entry.getValue() - 1));
// Decreases the last_sneak counter which allows to double press to sneak continuously.
if (this.last_sneak > 0)
--this.last_sneak;
// Decreases the cooldown for GUI actions.
if (this.action_gui_cooldown > 0)
--this.action_gui_cooldown;
this.prev_target_yaw = this.target_yaw;
this.prev_target_pitch = this.target_pitch;
this.fetch_button_input(client);
this.fetch_axe_input(client);
}
public void on_pre_render_screen(@NotNull MinecraftClient client, @NotNull Screen screen)
{
if (this.prev_target_mouse_x != this.target_mouse_x || this.prev_target_mouse_y != this.target_mouse_y) {
double mouse_x = prev_target_mouse_x + (this.target_mouse_x - this.prev_target_mouse_x) * client.getTickDelta() + 0.5;
double mouse_y = prev_target_mouse_y + (this.target_mouse_y - this.prev_target_mouse_y) * client.getTickDelta() + 0.5;
GLFW.glfwSetCursorPos(client.window.getHandle(), mouse_x, mouse_y);
}
}
public void on_render(@NotNull MinecraftClient client)
{
if (client.currentScreen == null && (this.prev_target_yaw != this.target_yaw || this.prev_target_pitch != this.target_pitch)) {
float rotation_yaw = (float) (client.player.prevYaw + (this.target_yaw - client.player.prevYaw) * client.getTickDelta());
float rotation_pitch = (float) (client.player.prevPitch + (this.target_pitch - client.player.prevPitch) * client.getTickDelta());
client.player.yaw = rotation_yaw;
client.player.pitch = MathHelper.clamp(rotation_pitch, -90.F, 90.F);
if (client.player.isRiding()) {
client.player.getVehicle().copyPositionAndRotation(client.player);
}
}
}
public void on_screen_open(@NotNull MinecraftClient client, int window_width, int window_height)
{
if (client.currentScreen == null) {
this.target_mouse_x = this.prev_target_mouse_x = (int) (window_width / 2.F);
this.target_mouse_y = this.prev_target_mouse_y = (int) (window_height / 2.F);
}
}
private void fetch_button_input(@NotNull MinecraftClient client)
{
ByteBuffer buffer = GLFW.glfwGetJoystickButtons(this.controller);
if (buffer != null) {
for (int i = 0; i < buffer.limit(); i++) {
boolean btn_state = buffer.get() == (byte) 1;
boolean previous_state = BUTTON_STATES.getOrDefault(i, false);
if (btn_state != previous_state) {
this.handle_button(client, i, btn_state ? 0 : 1, btn_state);
if (btn_state)
BUTTON_COOLDOWNS.put(i, 5);
} else if (btn_state) {
if (BUTTON_COOLDOWNS.getOrDefault(i, 0) == 0) {
BUTTON_COOLDOWNS.put(i, 5);
this.handle_button(client, i, 2, true);
}
}
BUTTON_STATES.put(i, btn_state);
if (this.config.is_jump_button(i))
this.last_a_state = btn_state;
}
}
}
private void fetch_axe_input(@NotNull MinecraftClient client)
{
FloatBuffer buffer = GLFW.glfwGetJoystickAxes(this.controller);
if (buffer != null) {
for (int i = 0; i < buffer.limit(); i++) {
float value = buffer.get();
float abs_value = Math.abs(value);
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);
}
}
}
private void handle_button(@NotNull MinecraftClient client, int button, int action, boolean state)
{
if (action == 0) {
// Handles RB and LB buttons.
if (this.config.is_hotbar_left_button(button) || this.config.is_hotbar_right_button(button)) {
this.handle_rb_lb(client, this.config.is_hotbar_right_button(button));
return;
}
// Handles when the player presses the Start button.
if (this.config.is_start_button(button)) {
// If in game, then pause the game.
if (client.currentScreen == null)
client.openPauseMenu(false);
else // Else just close the current screen.
client.currentScreen.onClose();
return;
}
if (this.config.is_jump_button(button) && client.currentScreen != null) {
if (this.action_gui_cooldown == 0) {
Element focused = client.currentScreen.getFocused();
if (focused != null)
this.handle_a_button(focused);
this.action_gui_cooldown = 5; // Prevent to press too quickly the focused element, so we have to skip 5 ticks.
return;
}
}
}
// Handles sneak button and continuous sneak.
if (this.config.is_sneak_button(button) && client.player != null) {
if (action == 0) {
if (this.continuous_sneak) {
this.set_sneaking(client, this.continuous_sneak = false);
} else if (this.last_sneak > 3) {
this.set_sneaking(client, this.continuous_sneak = true);
} else {
this.set_sneaking(client, true);
this.last_sneak = 15;
}
} else if (action == 1) {
if (this.continuous_sneak)
return;
this.set_sneaking(client, false);
}
return;
}
if (this.config.is_jump_button(button) && client.currentScreen != null) {
if (this.last_a_state != state) {
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 (state) {
client.currentScreen.mouseClicked(mouse_x, mouse_y, GLFW.GLFW_MOUSE_BUTTON_1);
} else {
client.currentScreen.mouseReleased(mouse_x, mouse_y, GLFW.GLFW_MOUSE_BUTTON_1);
}
return;
}
}
if (client.currentScreen == null && action != 2) {
Optional<KeyBinding> key_binding = this.config.get_keybind("button_" + button);
key_binding.ifPresent(keyBinding -> ((LambdaKeyBinding) keyBinding).handle_press_state(action != 1));
}
}
private void handle_axe(@NotNull MinecraftClient client, int axe, float value, float abs_value, int state)
{
int as_button_state = value > 0.5F ? 1 : (value < -0.5F ? 2 : 0);
double dead_zone = this.config.get_dead_zone();
if (client.currentScreen == null) {
this.config.get_keybind("axe_" + axe + "+").ifPresent(key_binding -> ((LambdaKeyBinding) key_binding).handle_press_state(as_button_state == 1));
this.config.get_keybind("axe_" + axe + "-").ifPresent(key_binding -> ((LambdaKeyBinding) key_binding).handle_press_state(as_button_state == 2));
// Handles the look direction.
if (this.config.is_look_axis(axe) && client.player != null) {
if (this.config.is_view_down_control(axe, state)) {
if (this.config.get_view_down_control().endsWith("+"))
this.target_pitch = client.player.pitch + (this.config.get_rotation_speed() * (abs_value - dead_zone) / (1.0 - dead_zone)) * 0.33D;
else
this.target_pitch = client.player.pitch - (this.config.get_rotation_speed() * (abs_value + dead_zone) / (1.0 - dead_zone)) * 0.33D;
this.target_pitch = MathHelper.clamp(this.target_pitch, -90.0D, 90.0D);
} else if (this.config.is_view_up_control(axe, state)) {
if (this.config.get_view_up_control().endsWith("+"))
this.target_pitch = client.player.pitch + (this.config.get_rotation_speed() * (abs_value - dead_zone) / (1.0 - dead_zone)) * 0.33D;
else
this.target_pitch = client.player.pitch - (this.config.get_rotation_speed() * (abs_value + dead_zone) / (1.0 - dead_zone)) * 0.33D;
this.target_pitch = MathHelper.clamp(this.target_pitch, -90.0D, 90.0D);
}
if (this.config.is_view_left_control(axe, state)) {
if (this.config.get_view_left_control().endsWith("+"))
this.target_yaw = client.player.yaw + (this.config.get_rotation_speed() * (abs_value - dead_zone) / (1.0 - dead_zone)) * 0.33D;
else
this.target_yaw = client.player.yaw - (this.config.get_rotation_speed() * (abs_value + dead_zone) / (1.0 - dead_zone)) * 0.33D;
} else if (this.config.is_view_right_control(axe, state)) {
if (this.config.get_view_right_control().endsWith("+"))
this.target_yaw = client.player.yaw + (this.config.get_rotation_speed() * (abs_value - dead_zone) / (1.0 - dead_zone)) * 0.33D;
else
this.target_yaw = client.player.yaw - (this.config.get_rotation_speed() * (abs_value + dead_zone) / (1.0 - dead_zone)) * 0.33D;
}
}
} else {
boolean allow_mouse_control = true;
if (this.action_gui_cooldown == 0 && this.config.is_movement_axis(axe)) {
if (this.config.is_forward_button(axe, false, as_button_state)) {
allow_mouse_control = this.change_focus(client.currentScreen, false);
} else if (this.config.is_back_button(axe, false, as_button_state)) {
allow_mouse_control = this.change_focus(client.currentScreen, true);
} else if (this.config.is_left_button(axe, false, as_button_state)) {
allow_mouse_control = this.handle_left_right(client.currentScreen, false);
} else if (this.config.is_right_button(axe, false, as_button_state)) {
allow_mouse_control = this.handle_left_right(client.currentScreen, true);
}
}
float movement_x = 0.0F;
float movement_y = 0.0F;
if (this.config.is_back_button(axe, false, (value > 0 ? 1 : 2))) {
movement_y = abs_value;
} else if (this.config.is_forward_button(axe, false, (value > 0 ? 1 : 2))) {
movement_y = -abs_value;
} else if (this.config.is_left_button(axe, false, (value > 0 ? 1 : 2))) {
movement_x = -abs_value;
} else if (this.config.is_right_button(axe, false, (value > 0 ? 1 : 2))) {
movement_x = abs_value;
}
if (client.currentScreen != null && allow_mouse_control) {
boolean moving = Math.abs(movement_y) >= dead_zone || Math.abs(movement_x) >= dead_zone;
if (moving) {
/*
Updates the target mouse position when the initial movement stick movement is detected.
It prevents the cursor to jump to the old target mouse position if the user moves the cursor with the mouse.
*/
if (Math.abs(prev_x_axis) < dead_zone && Math.abs(prev_y_axis) < dead_zone) {
double mouse_x = client.mouse.getX();
double mouse_y = client.mouse.getY();
prev_target_mouse_x = target_mouse_x = (int) mouse_x;
prev_target_mouse_y = target_mouse_y = (int) mouse_y;
}
if (Math.abs(movement_x) >= dead_zone)
this.mouse_speed_x = movement_x;
else
this.mouse_speed_x = 0.F;
if (Math.abs(movement_y) >= dead_zone)
this.mouse_speed_y = movement_y;
else
this.mouse_speed_y = 0.F;
} else {
this.mouse_speed_x = 0.F;
this.mouse_speed_y = 0.F;
}
if (Math.abs(this.mouse_speed_x) > .05F || Math.abs(this.mouse_speed_y) > .05F) {
this.target_mouse_x += this.mouse_speed_x * this.config.get_rotation_speed();
this.target_mouse_x = MathHelper.clamp(this.target_mouse_x, 0, client.window.getWidth());
this.target_mouse_y += this.mouse_speed_y * this.config.get_rotation_speed();
this.target_mouse_y = MathHelper.clamp(this.target_mouse_y, 0, client.window.getHeight());
}
//this.move_mouse_to_closest_slot(client, client.currentScreen);
}
this.prev_x_axis = movement_x;
this.prev_y_axis = movement_y;
}
}
/**
* Handles the press on RB on LB.
*
* @param client The client's instance.
* @param right True if RB is pressed, else false.
*/
private void handle_rb_lb(@NotNull MinecraftClient client, boolean right)
{
// When ingame
if (client.currentScreen == null) {
if (right)
client.player.inventory.selectedSlot = client.player.inventory.selectedSlot == 8 ? 0 : client.player.inventory.selectedSlot + 1;
else
client.player.inventory.selectedSlot = client.player.inventory.selectedSlot == 0 ? 8 : client.player.inventory.selectedSlot - 1;
} else if (client.currentScreen instanceof CreativeInventoryScreen) {
CreativeInventoryScreenAccessor creative_inventory = (CreativeInventoryScreenAccessor) client.currentScreen;
int current_selected_tab = creative_inventory.get_selected_tab();
int next_tab = current_selected_tab + (right ? 1 : -1);
if (next_tab < 0)
next_tab = ItemGroup.GROUPS.length - 1;
else if (next_tab >= ItemGroup.GROUPS.length)
next_tab = 0;
creative_inventory.set_selected_tab(ItemGroup.GROUPS[next_tab]);
}
}
private void handle_a_button(@NotNull Element focused)
{
if (focused instanceof AbstractPressableButtonWidget) {
AbstractPressableButtonWidget button_widget = (AbstractPressableButtonWidget) focused;
button_widget.playDownSound(MinecraftClient.getInstance().getSoundManager());
button_widget.onPress();
} else if (focused instanceof WorldListWidget) {
WorldListWidget list = (WorldListWidget) focused;
list.method_20159().ifPresent(WorldListWidget.LevelItem::play);
} else if (focused instanceof ParentElement) {
Element child_focused = ((ParentElement) focused).getFocused();
if (child_focused != null)
this.handle_a_button(child_focused);
}
}
/**
* Handles the left and right buttons.
*
* @param screen The current screen.
* @param right True if the right button is pressed, else false.
*/
private boolean handle_left_right(@NotNull Screen screen, boolean right)
{
Element focused = screen.getFocused();
if (focused != null)
return this.handle_right_left_element(focused, right);
return true;
}
private boolean handle_right_left_element(@NotNull Element element, boolean right)
{
if (element instanceof SliderWidget) {
SliderWidget slider = (SliderWidget) element;
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 ParentElement) {
ParentElement entry_list = (ParentElement) element;
Element focused = entry_list.getFocused();
if (focused == null)
return true;
return this.handle_right_left_element(focused, right);
}
return true;
}
/**
* Sets if the player is sneaking.
*
* @param client The client's instance.
* @param sneaking True if the player is sneaking, else false.
*/
private void set_sneaking(@NotNull MinecraftClient client, boolean sneaking)
{
((LambdaKeyBinding) client.options.keySneak).handle_press_state(sneaking);
}
private boolean change_focus(@NotNull Screen screen, boolean down)
{
if (!screen.changeFocus(down)) {
if (screen.changeFocus(down)) {
this.action_gui_cooldown = 5;
return false;
}
return true;
} else {
this.action_gui_cooldown = 5;
return false;
}
}
// Inspired from https://github.com/MrCrayfish/Controllable/blob/1.14.X/src/main/java/com/mrcrayfish/controllable/client/ControllerInput.java#L686.
private void move_mouse_to_closest_slot(@NotNull MinecraftClient client, @Nullable Screen screen)
{
// Makes the mouse attracted to slots. This helps with selecting items when using a controller.
if (screen instanceof AbstractContainerScreen) {
AbstractContainerScreen inventory_screen = (AbstractContainerScreen) screen;
AbstractContainerScreenAccessor accessor = (AbstractContainerScreenAccessor) inventory_screen;
int gui_left = accessor.get_left();
int gui_top = accessor.get_top();
int mouse_x = (int) (target_mouse_x * (double) client.window.getScaledWidth() / (double) client.window.getWidth());
int mouse_y = (int) (target_mouse_y * (double) client.window.getScaledHeight() / (double) client.window.getHeight());
// Finds the closest slot in the GUI within 14 pixels.
Optional<Pair<Slot, Double>> closest_slot = inventory_screen.getContainer().slotList.parallelStream()
.map(slot -> {
int pos_x = gui_left + slot.xPosition + 8;
int pos_y = gui_top + slot.yPosition + 8;
// Distance between the slot and the cursor.
double distance = Math.sqrt(Math.pow(pos_x - mouse_x, 2) + Math.pow(pos_y - mouse_y, 2));
return Pair.of(slot, distance);
}).filter(entry -> entry.get_value() <= 14.0)
.min(Comparator.comparingDouble(Pair::get_value));
if (closest_slot.isPresent()) {
Slot slot = closest_slot.get().get_key();
if (slot.hasStack() || !client.player.inventory.getMainHandStack().isEmpty()) {
int slot_center_x_scaled = gui_left + slot.xPosition + 8;
int slot_center_y_scaled = gui_top + slot.yPosition + 8;
int slot_center_x = (int) (slot_center_x_scaled / ((double) client.window.getScaledWidth() / (double) client.window.getWidth()));
int slot_center_y = (int) (slot_center_y_scaled / ((double) client.window.getScaledHeight() / (double) client.window.getHeight()));
double delta_x = slot_center_x - target_mouse_x;
double delta_y = slot_center_y - target_mouse_y;
if (mouse_x != slot_center_x_scaled || mouse_y != slot_center_y_scaled) {
this.target_mouse_x += delta_x * 0.75;
this.target_mouse_y += delta_y * 0.75;
} else {
mouse_speed_x = 0.F;
mouse_speed_y = 0.F;
}
this.mouse_speed_x *= .75F;
this.mouse_speed_y *= .75F;
}
} else {
this.mouse_speed_x *= .1F;
this.mouse_speed_y *= .1F;
}
} else {
this.mouse_speed_x = 0.F;
this.mouse_speed_y = 0.F;
}
}
}

View File

@@ -9,19 +9,37 @@
package me.lambdaurora.lambdacontrols;
import me.lambdaurora.lambdacontrols.mixin.AbstractContainerScreenAccessor;
import me.lambdaurora.lambdacontrols.util.CreativeInventoryScreenAccessor;
import me.lambdaurora.lambdacontrols.util.LambdaKeyBinding;
import net.fabricmc.api.ClientModInitializer;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.Element;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.ingame.AbstractContainerScreen;
import net.minecraft.client.gui.screen.ingame.CreativeInventoryScreen;
import net.minecraft.client.gui.screen.ingame.InventoryScreen;
import net.minecraft.client.gui.screen.world.WorldListWidget;
import net.minecraft.client.gui.widget.AbstractPressableButtonWidget;
import net.minecraft.client.gui.widget.EntryListWidget;
import net.minecraft.client.gui.widget.SliderWidget;
import net.minecraft.client.options.GameOptions;
import net.minecraft.container.Slot;
import net.minecraft.item.ItemGroup;
import net.minecraft.util.math.MathHelper;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.aperlambda.lambdacommon.utils.Pair;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.glfw.GLFW;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import static org.lwjgl.glfw.GLFW.GLFW_JOYSTICK_1;
@@ -32,10 +50,22 @@ import static org.lwjgl.glfw.GLFW.GLFW_JOYSTICK_1;
public class LambdaControls implements ClientModInitializer
{
private static LambdaControls INSTANCE;
public final Logger logger = LogManager.getLogger("LambdaControls");
public final LambdaControlsConfig config = new LambdaControlsConfig(this);
private final Map<Integer, Integer> BUTTON_STATES = new HashMap<>();
private int cid = GLFW_JOYSTICK_1;
public final Logger logger = LogManager.getLogger("LambdaControls");
public final LambdaControlsConfig config = new LambdaControlsConfig(this);
public final ControllerInput controller_input = new ControllerInput(this);
private final Map<Integer, Integer> BUTTON_STATES = new HashMap<>();
private float prev_x_axis = 0.F;
private float prev_y_axis = 0.F;
private int prev_target_mouse_x = 0;
private int prev_target_mouse_y = 0;
private int target_mouse_x = 0;
private int target_mouse_y = 0;
private float mouse_speed_x = 0.F;
private float mouse_speed_y = 0.F;
private boolean last_a_state = false;
private int cid = GLFW_JOYSTICK_1;
private boolean allow_controller_mouse = true;
private int action_gui_cooldown = 0;
@Override
public void onInitializeClient()
@@ -64,82 +94,25 @@ public class LambdaControls implements ClientModInitializer
*
* @param client The client instance.
*/
public void on_tick(MinecraftClient client)
public void on_tick(@NotNull MinecraftClient client)
{
GameOptions options = client.options;
ByteBuffer btn_buffer = GLFW.glfwGetJoystickButtons(GLFW.GLFW_JOYSTICK_3);
if (btn_buffer != null) {
for (int i = 0; i < btn_buffer.limit(); i++) {
boolean btn_state = btn_buffer.get() == (byte) 1;
if (this.config.get_controls_mode() == ControlsMode.CONTROLLER)
this.controller_input.on_tick(client);
/* Decreases the cooldown for the screen focus change.
if (this.action_gui_cooldown > 0)
--this.action_gui_cooldown;
if (this.action_gui_cooldown == 0)
this.allow_controller_mouse = true;
int current_state = BUTTON_STATES.getOrDefault(i, 0);
if (current_state == 0 && btn_state) {
BUTTON_STATES.put(i, 1);
this.prev_target_mouse_x = this.target_mouse_x;
this.prev_target_mouse_y = this.target_mouse_y;
if (LambdaControls.get().config.get_controls_mode() == ControlsMode.CONTROLLER)
this.on_controller_tick(client);*/
}
int f_i = i;
this.config.get_keybind("button_" + i).ifPresent(key_binding -> {
((LambdaKeyBinding) key_binding).lambdacontrols_press();
if (key_binding == options.keyInventory && client.player != null && client.player.container != client.player.playerContainer) {
BUTTON_STATES.put(f_i, 2);
}
});
if (this.config.is_hotbar_left_button(i)) {
client.player.inventory.selectedSlot = client.player.inventory.selectedSlot == 0 ? 8 : client.player.inventory.selectedSlot - 1;
} else if (this.config.is_hotbar_right_button(i)) {
client.player.inventory.selectedSlot = client.player.inventory.selectedSlot == 8 ? 0 : client.player.inventory.selectedSlot + 1;
}
} else if (current_state != 0 && !btn_state) {
this.config.get_keybind("button_" + i).ifPresent(key_binding -> {
if (key_binding == options.keyInventory && current_state == 2 && client.player != null && client.player.container != client.player.playerContainer) {
client.player.closeContainer();
}
((LambdaKeyBinding) key_binding).lambdacontrols_unpress();
});
BUTTON_STATES.put(i, 0);
}
}
}
FloatBuffer axes_buffer = GLFW.glfwGetJoystickAxes(GLFW.GLFW_JOYSTICK_3);
if (axes_buffer != null) {
for (int i = 0; i < axes_buffer.limit(); i++) {
float value = axes_buffer.get();
{
int state = value > 0.5F ? 1 : (value < -0.5F ? 2 : 0);
this.config.get_keybind("axe_" + i + "+").ifPresent(key_binding -> ((LambdaKeyBinding) key_binding).handle_press_state(state == 1));
this.config.get_keybind("axe_" + i + "-").ifPresent(key_binding -> ((LambdaKeyBinding) key_binding).handle_press_state(state == 2));
}
if (this.config.is_look_axis(i) && (value > 0.25F || value < -0.25F)) {
int state = value > 0.25F ? 1 : (value < -0.25F ? 2 : 0);
float multiplier = 50.f;
double x = 0.0D;
double y = 0.0D;
if (this.config.is_view_down_control(i, state)) {
if (this.config.get_view_down_control().endsWith("+"))
y = Math.abs(value * multiplier);
else
y = -Math.abs(value * multiplier);
} else if (this.config.is_view_up_control(i, state)) {
if (this.config.get_view_up_control().endsWith("+"))
y = Math.abs(value * multiplier);
else
y = -Math.abs(value * multiplier);
}
if (this.config.is_view_left_control(i, state)) {
if (this.config.get_view_left_control().endsWith("+"))
x = Math.abs(value * multiplier);
else
x = -Math.abs(value * multiplier);
} else if (this.config.is_view_right_control(i, state)) {
if (this.config.get_view_right_control().endsWith("+"))
x = Math.abs(value * multiplier);
else
x = -Math.abs(value * multiplier);
}
client.player.changeLookDirection(x, y);
}
}
}
public void on_render(MinecraftClient client)
{
this.controller_input.on_render(client);
}
/**

View File

@@ -28,6 +28,16 @@ public class LambdaControlsConfig
private final LambdaControls mod;
private ControlsMode controls_mode;
private HudSide hud_side;
// Controller settings
private double dead_zone;
private double rotation_speed;
// Controller controls
private String back_button;
private String forward_button;
private String jump_button;
private String left_button;
private String right_button;
private String sneak_button;
public LambdaControlsConfig(@NotNull LambdaControls mod)
{
@@ -41,53 +51,59 @@ public class LambdaControlsConfig
this.mod.log("Configuration loaded.");
this.controls_mode = ControlsMode.by_id(this.config.getOrElse("controls", "default")).orElse(ControlsMode.DEFAULT);
this.hud_side = HudSide.by_id(this.config.getOrElse("hud.side", "left")).orElse(HudSide.LEFT);
// Controller settings
this.dead_zone = this.config.getOrElse("controller.dead_zone", 0.25D);
this.rotation_speed = this.config.getOrElse("controller.rotation_speed", 25.D);
// 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.jump_button = this.config.getOrElse("controller.controls.jump", "none").toLowerCase();
this.left_button = this.config.getOrElse("controller.controls.left", "none").toLowerCase();
this.right_button = this.config.getOrElse("controller.controls.right", "none").toLowerCase();
this.sneak_button = this.config.getOrElse("controller.controls.sneak", "none").toLowerCase();
}
public void init_keybindings(GameOptions options)
{
String str = this.config.getOrElse("controller.attack", "none").toLowerCase();
String str = this.config.getOrElse("controller.controls.attack", "none").toLowerCase();
if (!str.equals("none"))
this.keybinding_mappings.put(str, options.keyAttack);
str = this.config.getOrElse("controller.back", "none").toLowerCase();
if (!str.equals("none"))
this.keybinding_mappings.put(str, options.keyBack);
str = this.config.getOrElse("controller.drop", "none").toLowerCase();
if (!this.back_button.equals("none"))
this.keybinding_mappings.put(this.back_button, options.keyBack);
str = this.config.getOrElse("controller.controls.drop", "none").toLowerCase();
if (!str.equals("none"))
this.keybinding_mappings.put(str, options.keyDrop);
str = this.config.getOrElse("controller.forward", "none").toLowerCase();
if (!str.equals("none"))
this.keybinding_mappings.put(str, options.keyForward);
str = this.config.getOrElse("controller.inventory", "none").toLowerCase();
if (!this.forward_button.equals("none"))
this.keybinding_mappings.put(this.forward_button, options.keyForward);
str = this.config.getOrElse("controller.controls.inventory", "none").toLowerCase();
if (!str.equals("none"))
this.keybinding_mappings.put(str, options.keyInventory);
str = this.config.getOrElse("controller.jump", "none").toLowerCase();
if (!str.equals("none"))
this.keybinding_mappings.put(str, options.keyJump);
str = this.config.getOrElse("controller.left", "none").toLowerCase();
if (!str.equals("none"))
this.keybinding_mappings.put(str, options.keyLeft);
str = this.config.getOrElse("controller.right", "none").toLowerCase();
if (!str.equals("none"))
this.keybinding_mappings.put(str, options.keyRight);
str = this.config.getOrElse("controller.sneak", "none").toLowerCase();
if (!str.equals("none"))
this.keybinding_mappings.put(str, options.keySneak);
str = this.config.getOrElse("controller.sprint", "none").toLowerCase();
if (!this.jump_button.equals("none"))
this.keybinding_mappings.put(this.jump_button, options.keyJump);
if (!this.left_button.equals("none"))
this.keybinding_mappings.put(this.left_button, options.keyLeft);
if (!this.right_button.equals("none"))
this.keybinding_mappings.put(this.right_button, options.keyRight);
if (!this.sneak_button.equals("none"))
this.keybinding_mappings.put(this.sneak_button, options.keySneak);
str = this.config.getOrElse("controller.controls.sprint", "none").toLowerCase();
if (!str.equals("none"))
this.keybinding_mappings.put(str, options.keySprint);
str = this.config.getOrElse("controller.use", "none").toLowerCase();
str = this.config.getOrElse("controller.controls.use", "none").toLowerCase();
if (!str.equals("none"))
this.keybinding_mappings.put(str, options.keyUse);
}
public void save()
{
this.config.set("controller.dead_zone", this.dead_zone);
this.config.set("controller.rotation_speed", this.rotation_speed);
this.config.save();
this.mod.log("Configuration saved.");
}
/**
* Returns the controls mode from the configuration.
* Gets the controls mode from the configuration.
*
* @return The controls mode.
*/
@@ -108,7 +124,7 @@ public class LambdaControlsConfig
}
/**
* Returns the HUD side from the configuration.
* Gets the HUD side from the configuration.
*
* @return The HUD side.
*/
@@ -128,6 +144,46 @@ public class LambdaControlsConfig
this.config.set("hud.side", hud_side.get_name());
}
/**
* Gets the controller's dead zone from the configuration.
*
* @return The controller's dead zone value.
*/
public double get_dead_zone()
{
return this.dead_zone;
}
/**
* Sets the controller's dead zone in the configuration.
*
* @param dead_zone The new controller's dead zone value.
*/
public void set_dead_zone(double dead_zone)
{
this.dead_zone = dead_zone;
}
/**
* Gets the controller's rotation speed.
*
* @return The rotation speed.
*/
public double get_rotation_speed()
{
return this.rotation_speed;
}
/**
* Sets the controller's rotation speed.
*
* @param rotation_speed The rotation speed.
*/
public void set_rotation_speed(double rotation_speed)
{
this.rotation_speed = rotation_speed;
}
/**
* Returns the keybindings.
*
@@ -143,14 +199,49 @@ public class LambdaControlsConfig
return Optional.ofNullable(this.keybinding_mappings.get(id));
}
public String get_back_button()
{
return this.back_button;
}
public String get_forward_button()
{
return this.forward_button;
}
public String get_hotbar_left_button()
{
return this.config.getOrElse("controller.hotbar_left", "none").toLowerCase();
return this.config.getOrElse("controller.controls.hotbar_left", "none").toLowerCase();
}
public String get_hotbar_right_button()
{
return this.config.getOrElse("controller.hotbar_right", "none").toLowerCase();
return this.config.getOrElse("controller.controls.hotbar_right", "none").toLowerCase();
}
public String get_jump_button()
{
return this.jump_button;
}
public String get_left_button()
{
return this.left_button;
}
public String get_right_button()
{
return this.right_button;
}
public String get_sneak_button()
{
return this.sneak_button;
}
public String get_start_button()
{
return this.config.getOrElse("controller.controls.start", "none").toLowerCase();
}
public boolean is_hotbar_left_button(int button)
@@ -163,24 +254,67 @@ public class LambdaControlsConfig
return this.get_hotbar_right_button().equals("button_" + 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 ? "+" : "-")));
}
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 ? "+" : "-")));
}
public boolean is_jump_button(int btn)
{
return this.get_jump_button().equals("button_" + btn);
}
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 ? "+" : "-")));
}
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 ? "+" : "-")));
}
public boolean is_sneak_button(int btn)
{
return this.get_sneak_button().equals("button_" + btn);
}
public boolean is_start_button(int btn)
{
return this.get_start_button().equals("button_" + btn);
}
public String get_view_down_control()
{
return this.config.getOrElse("controller.view_down", "none").toLowerCase();
return this.config.getOrElse("controller.controls.view_down", "none").toLowerCase();
}
public String get_view_left_control()
{
return this.config.getOrElse("controller.view_left", "none").toLowerCase();
return this.config.getOrElse("controller.controls.view_left", "none").toLowerCase();
}
public String get_view_right_control()
{
return this.config.getOrElse("controller.view_right", "none").toLowerCase();
return this.config.getOrElse("controller.controls.view_right", "none").toLowerCase();
}
public String get_view_up_control()
{
return this.config.getOrElse("controller.view_up", "none").toLowerCase();
return this.config.getOrElse("controller.controls.view_up", "none").toLowerCase();
}
public boolean is_view_down_control(int axe, int state)
@@ -211,9 +345,27 @@ public class LambdaControlsConfig
return this.get_view_up_control().contains(axe + (state == 1 ? "+" : "-"));
}
/**
* Returns whether the specified axis is an axis used for look direction.
*
* @param i The axis index.
* @return True if the axis is used for look direction, else false.
*/
public boolean is_look_axis(int i)
{
return this.get_view_down_control().startsWith("axe_" + i) || this.get_view_left_control().startsWith("axe_" + i) || this.get_view_right_control().startsWith("axe_" + i)
|| this.get_view_up_control().startsWith("axe_" + i);
}
/**
* Returns whether the specified axis is an axis used for movements.
*
* @param i The axis index.
* @return True if the axis is used for movements, else false.
*/
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);
}
}

View File

@@ -0,0 +1,100 @@
/*
* 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.ControlsMode;
import me.lambdaurora.lambdacontrols.HudSide;
import me.lambdaurora.lambdacontrols.LambdaControls;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.controls.ControlsOptionsScreen;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.options.DoubleOption;
import net.minecraft.client.options.GameOptions;
import net.minecraft.client.options.Option;
import net.minecraft.client.resource.language.I18n;
import net.minecraft.text.TranslatableText;
import org.jetbrains.annotations.NotNull;
/**
* Represents the LambdaControls settings screen.
*/
public class LambdaControlsSettingsScreen extends Screen
{
private final LambdaControls mod;
private final Screen parent;
private final GameOptions options;
private final Option dead_zone_option;
private final Option rotation_speed_option;
public LambdaControlsSettingsScreen(Screen parent, @NotNull GameOptions options)
{
super(new TranslatableText("lambdacontrols.title.settings"));
this.mod = LambdaControls.get();
this.parent = parent;
this.options = options;
this.dead_zone_option = new DoubleOption("lambdacontrols.menu.dead_zone", 0.05D, 1.0D, 0.05F, game_options -> this.mod.config.get_dead_zone(),
(game_options, new_value) -> {
synchronized (this.mod.config) {
this.mod.config.set_dead_zone(new_value);
}
}, (game_options, option) -> option.getDisplayPrefix() + option.get(options));
this.rotation_speed_option = new DoubleOption("lambdacontrols.menu.rotation_speed", 0.0D, 50.0D, 0.5F, game_options -> this.mod.config.get_rotation_speed(),
(game_options, new_value) -> {
synchronized (this.mod.config) {
this.mod.config.set_rotation_speed(new_value);
}
}, (game_options, option) -> option.getDisplayPrefix() + option.get(options));
}
@Override
public void onClose()
{
this.mod.config.save();
super.onClose();
}
@Override
protected void init()
{
super.init();
int y = 18;
int button_height = 20, spacing = 5;
this.addButton(new ButtonWidget(this.width / 2 - 155, y, 150, button_height, I18n.translate("lambdacontrols.menu.controls_mode") + ": " + this.mod.config.get_controls_mode().get_translated_name(),
btn -> {
ControlsMode next = this.mod.config.get_controls_mode().next();
btn.setMessage(I18n.translate("lambdacontrols.menu.controls_mode") + ": " + next.get_translated_name());
this.mod.config.set_controls_mode(next);
this.mod.config.save();
}));
this.addButton(new ButtonWidget(this.width / 2 - 155 + 160, y, 150, button_height, I18n.translate("options.controls"),
btn -> this.minecraft.openScreen(new ControlsOptionsScreen(this, this.options))));
this.addButton(new ButtonWidget(this.width / 2 - 155, (y += spacing + button_height), 150, button_height, I18n.translate("lambdacontrols.menu.hud_side") + ": " + this.mod.config.get_hud_side().get_translated_name(),
btn -> {
HudSide next = this.mod.config.get_hud_side().next();
btn.setMessage(I18n.translate("lambdacontrols.menu.hud_side") + ": " + next.get_translated_name());
this.mod.config.set_hud_side(next);
this.mod.config.save();
}));
this.addButton(new ButtonWidget(this.width / 2 - 155 + 160, y, 150, button_height, I18n.translate("lambdacontrols.menu.controller_controls"),
btn -> this.minecraft.openScreen(new ControlsOptionsScreen(this, this.options))));
this.addButton(this.dead_zone_option.createButton(this.options, this.width / 2 - 155, (y += spacing + button_height), 150));
this.addButton(this.rotation_speed_option.createButton(this.options, this.width / 2 - 155 + 160, y, 150));
this.addButton(new ButtonWidget(this.width / 2 - 155 + 160, this.height - 29, 150, button_height, I18n.translate("gui.done"), (buttonWidget) -> {
this.minecraft.openScreen(this.parent);
}));
}
@Override
public void render(int mouseX, int mouseY, float delta)
{
this.renderBackground();
super.render(mouseX, mouseY, delta);
}
}

View File

@@ -102,9 +102,10 @@ public class TouchscreenOverlay extends Screen
this.fly_button.visible = true;
this.fly_up_button.visible = true;
this.fly_down_button.visible = true;
if (old_state_fly != this.fly_button.visible)
if (old_state_fly != this.fly_button.visible) {
this.fly_button_enable_ticks = 5;
else if (this.fly_button_enable_ticks > 0)
this.handle_jump(false);
} else if (this.fly_button_enable_ticks > 0)
this.fly_button_enable_ticks--;
} else {
this.jump_button.visible = true;

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.AbstractButtonWidget;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(AbstractButtonWidget.class)
public interface AbstractButtonWidgetAccessor
{
@Accessor("height")
int get_height();
}

View File

@@ -0,0 +1,24 @@
/*
* 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.screen.ingame.AbstractContainerScreen;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(AbstractContainerScreen.class)
public interface AbstractContainerScreenAccessor
{
@Accessor("left")
int get_left();
@Accessor("top")
int get_top();
}

View File

@@ -0,0 +1,34 @@
/*
* 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 me.lambdaurora.lambdacontrols.util.CreativeInventoryScreenAccessor;
import net.minecraft.client.gui.screen.ingame.CreativeInventoryScreen;
import net.minecraft.item.ItemGroup;
import org.jetbrains.annotations.NotNull;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(CreativeInventoryScreen.class)
public abstract class CreativeInventoryScreenMixin implements CreativeInventoryScreenAccessor
{
@Shadow
protected abstract void setSelectedTab(ItemGroup itemGroup);
@Accessor("selectedTab")
public abstract int get_selected_tab();
@Override
public void set_selected_tab(@NotNull ItemGroup group)
{
this.setSelectedTab(group);
}
}

View File

@@ -0,0 +1,36 @@
/*
* 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 me.lambdaurora.lambdacontrols.ControlsMode;
import me.lambdaurora.lambdacontrols.LambdaControls;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.GameRenderer;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(GameRenderer.class)
public class GameRendererMixin
{
@Shadow
@Final
private MinecraftClient client;
@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/Screen;render(IIF)V"))
private void on_render(float tick_delta, long start_time, boolean full_render, CallbackInfo ci)
{
if (this.client.currentScreen != null && LambdaControls.get().config.get_controls_mode() == ControlsMode.CONTROLLER)
LambdaControls.get().controller_input.on_pre_render_screen(this.client, this.client.currentScreen);
}
}

View File

@@ -31,7 +31,8 @@ public abstract class MinecraftClientMixin
@Shadow
public boolean skipGameRender;
@Shadow public Screen currentScreen;
@Shadow
public Screen currentScreen;
@Inject(method = "init", at = @At("RETURN"))
private void on_init(CallbackInfo ci)
@@ -39,11 +40,16 @@ public abstract class MinecraftClientMixin
LambdaControls.get().on_mc_init((MinecraftClient) (Object) this);
}
@Inject(method = "handleInputEvents", at = @At("HEAD"))
@Inject(method = "render", at = @At("HEAD"))
private void on_render(boolean full_render, CallbackInfo ci)
{
LambdaControls.get().on_render((MinecraftClient) (Object) (this));
}
@Inject(method = "tick", at = @At("HEAD"))
private void on_handle_input_events(CallbackInfo ci)
{
if (LambdaControls.get().config.get_controls_mode() == ControlsMode.CONTROLLER)
LambdaControls.get().on_tick((MinecraftClient) (Object) this);
LambdaControls.get().on_tick((MinecraftClient) (Object) this);
}
@Inject(method = "openScreen", at = @At("RETURN"))
@@ -55,6 +61,8 @@ public abstract class MinecraftClientMixin
screen.init(((MinecraftClient) (Object) this), this.window.getScaledWidth(), this.window.getScaledHeight());
this.skipGameRender = false;
this.currentScreen = screen;
} else if (screen != null) {
mod.controller_input.on_screen_open(((MinecraftClient) (Object) this), this.window.getWidth(), this.window.getHeight());
}
}
}

View File

@@ -11,6 +11,7 @@ package me.lambdaurora.lambdacontrols.mixin;
import me.lambdaurora.lambdacontrols.ControlsMode;
import me.lambdaurora.lambdacontrols.LambdaControls;
import me.lambdaurora.lambdacontrols.util.MouseAccessor;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.Mouse;
import org.spongepowered.asm.mixin.Final;
@@ -21,17 +22,13 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(Mouse.class)
public class MouseMixin
public abstract class MouseMixin implements MouseAccessor
{
@Shadow
@Final
private MinecraftClient client;
protected abstract void onCursorPos(long window, double x, double y);
@Shadow
private double x;
@Shadow
private double y;
protected abstract void onMouseButton(long window, int button, int action, int mods);
@Inject(method = "lockCursor", at = @At("HEAD"), cancellable = true)
private void on_mouse_locked(CallbackInfo ci)
@@ -39,4 +36,16 @@ public class MouseMixin
if (LambdaControls.get().config.get_controls_mode() == ControlsMode.TOUCHSCREEN)
ci.cancel();
}
@Override
public void on_mouse_button(long window, int button, int action, int mods)
{
this.onMouseButton(window, button, action, mods);
}
@Override
public void on_cursor_pos(long window, double x, double y)
{
this.onCursorPos(window, x, y);
}
}

View File

@@ -0,0 +1,50 @@
/*
* 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 me.lambdaurora.lambdacontrols.gui.LambdaControlsSettingsScreen;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.SettingsScreen;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.options.GameOptions;
import net.minecraft.client.resource.language.I18n;
import net.minecraft.text.Text;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(SettingsScreen.class)
public class SettingsScreenMixin extends Screen
{
@Final
@Shadow
private GameOptions settings;
protected SettingsScreenMixin(Text title)
{
super(title);
}
@Inject(method = "init", at = @At("RETURN"))
private void on_init(CallbackInfo ci)
{
this.buttons.stream().filter(button -> button.getMessage().equals(I18n.translate("options.controls")))
.findFirst()
.ifPresent(btn -> {
this.buttons.remove(btn);
this.children.remove(btn);
this.addButton(new ButtonWidget(btn.x, btn.y, btn.getWidth(), ((AbstractButtonWidgetAccessor) btn).get_height(), btn.getMessage(),
b -> this.minecraft.openScreen(new LambdaControlsSettingsScreen(this, this.settings))));
});
}
}

View File

@@ -0,0 +1,33 @@
/*
* 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.util;
import net.minecraft.item.ItemGroup;
import org.jetbrains.annotations.NotNull;
/**
* Represents an accessor to CreativeInventoryScreen.
*/
public interface CreativeInventoryScreenAccessor
{
/**
* Gets the selected tab.
*
* @return The selected tab index.
*/
int get_selected_tab();
/**
* Sets the selected tab.
*
* @param group The tab's item group.
*/
void set_selected_tab(@NotNull ItemGroup group);
}

View File

@@ -0,0 +1,20 @@
/*
* 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.util;
/**
* Represents mouse's extra access.
*/
public interface MouseAccessor
{
void on_mouse_button(long window, int button, int action, int mods);
void on_cursor_pos(long window, double x, double y);
}

View File

@@ -0,0 +1,12 @@
{
"lambdacontrols.menu.controller_controls": "Controller controls...",
"lambdacontrols.menu.controls_mode": "Controls mode",
"lambdacontrols.menu.dead_zone": "Dead zone",
"lambdacontrols.menu.hud_side": "HUD side",
"lambdacontrols.menu.rotation_speed": "Rotation speed",
"lambdacontrols.controls_mode.default": "Keyboard/Mouse",
"lambdacontrols.controls_mode.controller": "Controller",
"lambdacontrols.controls_mode.touchscreen": "Touchscreen",
"lambdacontrols.hud_side.left": "left",
"lambdacontrols.hud_side.right": "right"
}

View File

@@ -4,29 +4,33 @@
controls = "default"
[hud]
# Dertermines where the movements buttons are.
side = "left"
# Dertermines where the movements buttons are.
side = "left"
# Controller settings
[controller]
attack = "button_7"
back = "axe_1+"
drop = "button_2"
forward = "axe_1-"
hotbar_left = "button_4"
hotbar_right = "button_5"
inventory = "button_3"
jump = "button_0"
left = "axe_0-"
right = "axe_0+"
sneak = "button_12"
sprint = "button_11"
start = "button_4"
use = "button_6"
view_down = "axe_3+"
view_left = "axe_2-"
view_right = "axe_2+"
view_up = "axe_3-"
dead_zone = 0.25
rotation_speed = 25.0
# Controller controls
[controller.controls]
attack = "button_7"
back = "axe_1+"
drop = "button_2"
forward = "axe_1-"
hotbar_left = "button_4"
hotbar_right = "button_5"
inventory = "button_3"
jump = "button_0"
left = "axe_0-"
right = "axe_0+"
sneak = "button_12"
sprint = "button_11"
start = "button_9"
use = "button_6"
view_down = "axe_3+"
view_left = "axe_2-"
view_right = "axe_2+"
view_up = "axe_3-"
# Colors
[colors]

View File

@@ -3,10 +3,15 @@
"package": "me.lambdaurora.lambdacontrols.mixin",
"compatibilityLevel": "JAVA_8",
"client": [
"AbstractButtonWidgetAccessor",
"AbstractContainerScreenAccessor",
"CreativeInventoryScreenMixin",
"GameRendererMixin",
"InGameHudMixin",
"KeyBindingMixin",
"MinecraftClientMixin",
"MouseMixin"
"MouseMixin",
"SettingsScreenMixin"
],
"injectors": {
"defaultRequire": 1