🚧 WIP of chording and next release.

This commit is contained in:
LambdAurora
2020-01-01 01:54:14 +01:00
parent 9ae1bc2a3b
commit 46d43c6f46
50 changed files with 1710 additions and 1231 deletions

View File

@@ -1,6 +1,6 @@
MIT License
Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -36,6 +36,8 @@ dependencies {
modApi "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
modCompile "io.github.prospector:modmenu:1.8.0+build.16"
modCompile "me.lambdaurora:spruceui:${project.spruceui_version}"
include "me.lambdaurora:spruceui:${project.spruceui_version}"
//modCompile "io.github.cottonmc:cotton-client-commands:0.4.2+1.14.3-SNAPSHOT"
implementation "org.jetbrains:annotations:17.0.0"

View File

@@ -8,11 +8,12 @@ org.gradle.jvmargs=-Xmx1G
loader_version=0.7.2+build.174
# Mod Properties
mod_version = 1.0.2
mod_version = 1.1.0-test1
maven_group = me.lambdaurora
archives_base_name = lambdacontrols
# Dependencies
# currently not on the main fabric site, check on the maven: https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api
fabric_version=0.4.25+build.282-1.15
fabric_version=0.4.26+build.283-1.15
spruceui_version=1.0.1

View File

@@ -1,517 +0,0 @@
/*
* 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.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.Identifier;
import org.aperlambda.lambdacommon.utils.Identifiable;
import org.aperlambda.lambdacommon.utils.Nameable;
import org.jetbrains.annotations.NotNull;
import org.lwjgl.glfw.GLFW;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Stream;
/**
* Represents a button binding.
*
* @author LambdAurora
*/
public class ButtonBinding implements Nameable
{
private static final List<ButtonBinding> BINDINGS = new ArrayList<>();
private static final List<Category> CATEGORIES = new ArrayList<>();
public static final PressAction DEFAULT_ACTION = (client, button, action) -> {
if (action == 2)
return false;
button.as_key_binding().ifPresent(key_binding -> ((KeyBindingAccessor) key_binding).handle_press_state(button.is_button_down()));
return true;
};
public static final Category MOVEMENT_CATEGORY;
public static final Category GAMEPLAY_CATEGORY;
public static final Category INVENTORY_CATEGORY;
public static final Category MULTIPLAYER_CATEGORY;
public static final Category MISC_CATEGORY;
public static final ButtonBinding ATTACK = new ButtonBinding("attack", axis_as_button(GLFW.GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER, true));
public static final ButtonBinding BACK = new ButtonBinding("back", axis_as_button(GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y, false));
public static final ButtonBinding CHAT = new ButtonBinding("chat", GLFW.GLFW_GAMEPAD_BUTTON_DPAD_RIGHT);
public static final ButtonBinding DROP_ITEM = new ButtonBinding("drop_item", GLFW.GLFW_GAMEPAD_BUTTON_B);
public static final ButtonBinding FORWARD = new ButtonBinding("forward", axis_as_button(GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y, true));
public static final ButtonBinding INVENTORY = new ButtonBinding("inventory", GLFW.GLFW_GAMEPAD_BUTTON_Y);
public static final ButtonBinding JUMP = new ButtonBinding("jump", GLFW.GLFW_GAMEPAD_BUTTON_A);
public static final ButtonBinding LEFT = new ButtonBinding("left", axis_as_button(GLFW.GLFW_GAMEPAD_AXIS_LEFT_X, false));
public static final ButtonBinding PAUSE_GAME = new ButtonBinding("pause_game", GLFW.GLFW_GAMEPAD_BUTTON_START);
public static final ButtonBinding PICK_BLOCK = new ButtonBinding("pick_block", GLFW.GLFW_GAMEPAD_BUTTON_DPAD_LEFT);
public static final ButtonBinding PLAYER_LIST = new ButtonBinding("player_list", GLFW.GLFW_GAMEPAD_BUTTON_BACK);
public static final ButtonBinding RIGHT = new ButtonBinding("right", axis_as_button(GLFW.GLFW_GAMEPAD_AXIS_LEFT_X, true));
public static final ButtonBinding SCREENSHOT = new ButtonBinding("screenshot", GLFW.GLFW_GAMEPAD_BUTTON_DPAD_DOWN,
Collections.singletonList((client, button, action) -> {
if (action == 0)
ScreenshotUtils.saveScreenshot(client.runDirectory, client.getWindow().getFramebufferWidth(), client.getWindow().getFramebufferHeight(), client.getFramebuffer(),
text -> client.execute(() -> client.inGameHud.getChatHud().addMessage(text)));
return true;
}));
public static final ButtonBinding SMOOTH_CAMERA = new ButtonBinding("toggle_smooth_camera", -1);
public static final ButtonBinding SNEAK = new ButtonBinding("sneak", GLFW.GLFW_GAMEPAD_BUTTON_RIGHT_THUMB,
Arrays.asList(DEFAULT_ACTION, (client, button, action) -> {
if (client.player != null && !client.player.abilities.flying) {
button.as_key_binding().filter(binding -> action == 0).ifPresent(binding -> ((KeyBindingAccessor) binding).handle_press_state(!binding.isPressed()));
return true;
}
return false;
}));
public static final ButtonBinding SPRINT = new ButtonBinding("sprint", GLFW.GLFW_GAMEPAD_BUTTON_LEFT_THUMB);
public static final ButtonBinding SWAP_HANDS = new ButtonBinding("swap_hands", GLFW.GLFW_GAMEPAD_BUTTON_X);
public static final ButtonBinding TOGGLE_PERSPECTIVE = new ButtonBinding("toggle_perspective", GLFW.GLFW_GAMEPAD_BUTTON_DPAD_UP);
public static final ButtonBinding USE = new ButtonBinding("use", axis_as_button(GLFW.GLFW_GAMEPAD_AXIS_LEFT_TRIGGER, true));
private int button;
private int default_button;
private String key;
private KeyBinding minecraft_key_binding = null;
private List<PressAction> actions = new ArrayList<>(Collections.singletonList(DEFAULT_ACTION));
private boolean pressed = false;
protected ButtonBinding(@NotNull String key, int default_button, @NotNull List<PressAction> actions)
{
this.default_button = this.button = default_button;
this.key = key;
this.actions.addAll(actions);
BINDINGS.add(this);
}
protected ButtonBinding(@NotNull String key, int default_button)
{
this(key, default_button, Collections.emptyList());
}
/**
* Returns the button bound.
*
* @return The bound button.
*/
public int get_button()
{
return this.button;
}
/**
* Sets the bound button.
*
* @param button The bound button.
*/
public void set_button(int button)
{
this.button = button;
}
/**
* Returns whether the bound button is the specified button or not.
*
* @param button The button to check.
* @return True if the bound button is the specified button, else false.
*/
public boolean is_button(int button)
{
return this.button == button;
}
/**
* Returns whether this button is down or not.
*
* @return True if the button is down, else false.
*/
public boolean is_button_down()
{
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()
{
return this.key;
}
/**
* Returns the translation key of this button binding.
*
* @return The translation key.
*/
public @NotNull String get_translation_key()
{
return "lambdacontrols.action." + this.get_name();
}
/**
* Returns the key binding equivalent of this button binding.
*
* @return The key binding equivalent.
*/
public @NotNull Optional<KeyBinding> as_key_binding()
{
return Optional.ofNullable(this.minecraft_key_binding);
}
/**
* Returns the specified axis as a button.
*
* @param axis The axis.
* @param positive True if the axis part is positive, else false.
* @return The axis as a button.
*/
public static int axis_as_button(int axis, boolean positive)
{
return positive ? 100 + axis : 200 + axis;
}
/**
* Returns the second Joycon's specified button code.
*
* @param button The raw button code.
* @return The second Joycon's button code.
*/
public static int joycon2_button(int button)
{
return 300 + button;
}
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)
{
BINDINGS.parallelStream().filter(binding -> Objects.equals(binding.button, button))
.forEach(binding -> binding.pressed = state);
}
public static void handle_button(@NotNull MinecraftClient client, int button, int action)
{
BINDINGS.parallelStream().filter(binding -> binding.button == button)
.forEach(binding -> {
for (int i = binding.actions.size() - 1; i >= 0; i--) {
if (binding.actions.get(i).press(client, binding, 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<Category> stream_categories()
{
return CATEGORIES.stream();
}
static {
MOVEMENT_CATEGORY = register_default_category("key.categories.movement", category -> category.register_all_bindings(
FORWARD,
BACK,
LEFT,
RIGHT,
JUMP,
SNEAK,
SPRINT));
GAMEPLAY_CATEGORY = register_default_category("key.categories.gameplay", category -> category.register_all_bindings(
ATTACK,
PICK_BLOCK,
USE
));
INVENTORY_CATEGORY = register_default_category("key.categories.inventory", category -> category.register_all_bindings(
DROP_ITEM,
INVENTORY,
SWAP_HANDS
));
MULTIPLAYER_CATEGORY = register_default_category("key.categories.multiplayer",
category -> category.register_all_bindings(CHAT, PLAYER_LIST));
MISC_CATEGORY = register_default_category("key.categories.misc", category -> category.register_all_bindings(
SCREENSHOT,
//SMOOTH_CAMERA,
TOGGLE_PERSPECTIVE
));
}
public static ButtonBinding register(@NotNull Identifier binding_id, int default_button, @NotNull List<PressAction> actions)
{
return new ButtonBinding(binding_id.get_namespace() + "." + binding_id.get_name(), default_button, actions);
}
public static ButtonBinding register(@NotNull Identifier binding_id, int default_button)
{
return register(binding_id, default_button, Collections.emptyList());
}
public static ButtonBinding register(@NotNull net.minecraft.util.Identifier binding_id, int default_button, @NotNull List<PressAction> actions)
{
return register(new Identifier(binding_id.getNamespace(), binding_id.getPath()), default_button, actions);
}
public static ButtonBinding register(@NotNull net.minecraft.util.Identifier binding_id, int default_button)
{
return register(binding_id, default_button, Collections.emptyList());
}
/**
* Registers a category of button bindings.
*
* @param category The category to register.
* @return The registered category.
*/
public static Category register_category(@NotNull Category category)
{
CATEGORIES.add(category);
return category;
}
public static Category register_category(@NotNull Identifier identifier, int priority)
{
return register_category(new Category(identifier, priority));
}
public static Category register_category(@NotNull Identifier identifier)
{
return register_category(new Category(identifier));
}
private static Category register_default_category(@NotNull String key, @NotNull Consumer<Category> key_adder)
{
Category category = register_category(new Identifier("minecraft", key), CATEGORIES.size());
key_adder.accept(category);
return category;
}
public static class Category implements Identifiable
{
private final List<ButtonBinding> bindings = new ArrayList<>();
private final Identifier id;
private int priority;
public Category(@NotNull Identifier id, int priority)
{
this.id = id;
this.priority = priority;
}
public Category(@NotNull Identifier id)
{
this(id, 100);
}
public void register_binding(@NotNull ButtonBinding binding)
{
if (this.bindings.contains(binding))
throw new IllegalStateException("Cannot register twice a button binding in the same category.");
this.bindings.add(binding);
}
public void register_all_bindings(@NotNull ButtonBinding... bindings)
{
this.register_all_bindings(Arrays.asList(bindings));
}
public void register_all_bindings(@NotNull List<ButtonBinding> bindings)
{
bindings.forEach(this::register_binding);
}
/**
* Gets the bindings assigned to this category.
*
* @return The bindings assigned to this category.
*/
public @NotNull List<ButtonBinding> get_bindings()
{
return Collections.unmodifiableList(this.bindings);
}
/**
* Gets the translated name of this category.
* <p>
* The translation key should be `modid.identifier_name`.
*
* @return The translated name.
*/
public @NotNull String get_translated_name()
{
if (this.id.get_namespace().equals("minecraft"))
return I18n.translate(this.id.get_name());
else
return I18n.translate(this.id.get_namespace() + "." + this.id.get_name());
}
/**
* Gets the priority display of this category.
* It will defines in which order the categories will display on the controls screen.
*
* @return The priority of this category.
*/
public int get_priority()
{
return this.priority;
}
@Override
public @NotNull Identifier get_identifier()
{
return this.id;
}
}
@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, @NotNull ButtonBinding button, int action);
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright © 2020 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;
/**
* Represents a button state.
*
* @author LambdAurora
* @version 1.1.0
* @since 1.1.0
*/
public enum ButtonState
{
NONE(0),
PRESS(1),
RELEASE(2),
REPEAT(3);
public final int id;
ButtonState(int id)
{
this.id = id;
}
/**
* Returns whether this state is a pressed state.
*
* @return True if this state is a pressed state, else false.
*/
public boolean is_pressed()
{
return this == PRESS || this == REPEAT;
}
/**
* Returns whether this state is an unpressed state.
*
* @return True if this state is an unpressed state, else false.
*/
public boolean is_unpressed()
{
return this == RELEASE || this == NONE;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
@@ -18,6 +18,10 @@ import java.util.Optional;
/**
* Represents a controller type.
*
* @author LambdAurora
* @version 1.0.0
* @since 1.0.0
*/
public enum ControllerType implements Nameable
{

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
@@ -18,6 +18,10 @@ import java.util.Optional;
/**
* Represents the controls mode.
*
* @author LambdAurora
* @version 1.0.0
* @since 1.0.0
*/
public enum ControlsMode implements Nameable
{

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
@@ -18,6 +18,10 @@ import java.util.Optional;
/**
* Represents the hud side which is the side where the movements buttons are.
*
* @author LambdAurora
* @version 1.0.0
* @since 1.0.0
*/
public enum HudSide implements Nameable
{

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
@@ -10,9 +10,14 @@
package me.lambdaurora.lambdacontrols;
import com.mojang.blaze3d.platform.GlStateManager;
import me.lambdaurora.lambdacontrols.compat.LambdaControlsCompat;
import me.lambdaurora.lambdacontrols.controller.ButtonBinding;
import me.lambdaurora.lambdacontrols.controller.Controller;
import me.lambdaurora.lambdacontrols.gui.LambdaControlsHud;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.keybinding.FabricKeyBinding;
import net.fabricmc.fabric.api.client.keybinding.KeyBindingRegistry;
import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.DrawableHelper;
@@ -24,28 +29,35 @@ import net.minecraft.text.TranslatableText;
import net.minecraft.util.Identifier;
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.lwjgl.glfw.GLFW;
/**
* Represents the LambdaControls mod.
*
* @author LambdAurora
* @version 1.1.0
* @since 1.0.0
*/
public class LambdaControls implements ClientModInitializer
{
private static LambdaControls INSTANCE;
public static final FabricKeyBinding BINDING_LOOK_UP = FabricKeyBinding.Builder.create(new Identifier("lambdacontrols", "look_up"),
public static final String MODID = "lambdacontrols";
public static final FabricKeyBinding BINDING_LOOK_UP = FabricKeyBinding.Builder.create(new Identifier(MODID, "look_up"),
InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_8, "key.categories.movement").build();
public static final FabricKeyBinding BINDING_LOOK_RIGHT = FabricKeyBinding.Builder.create(new Identifier("lambdacontrols", "look_right"),
public static final FabricKeyBinding BINDING_LOOK_RIGHT = FabricKeyBinding.Builder.create(new Identifier(MODID, "look_right"),
InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_6, "key.categories.movement").build();
public static final FabricKeyBinding BINDING_LOOK_DOWN = FabricKeyBinding.Builder.create(new Identifier("lambdacontrols", "look_down"),
public static final FabricKeyBinding BINDING_LOOK_DOWN = FabricKeyBinding.Builder.create(new Identifier(MODID, "look_down"),
InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_2, "key.categories.movement").build();
public static final FabricKeyBinding BINDING_LOOK_LEFT = FabricKeyBinding.Builder.create(new Identifier("lambdacontrols", "look_left"),
public static final FabricKeyBinding BINDING_LOOK_LEFT = FabricKeyBinding.Builder.create(new Identifier(MODID, "look_left"),
InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_4, "key.categories.movement").build();
public static final Identifier CONTROLLER_BUTTONS = new Identifier("lambdacontrols", "textures/gui/controller_buttons.png");
public static final Identifier CONTROLLER_AXIS = new Identifier("lambdacontrols", "textures/gui/controller_axis.png");
public static final Identifier CONTROLLER_BUTTONS = new Identifier(MODID, "textures/gui/controller_buttons.png");
public static final Identifier CONTROLLER_AXIS = new Identifier(MODID, "textures/gui/controller_axis.png");
public final Logger logger = LogManager.getLogger("LambdaControls");
public final LambdaControlsConfig config = new LambdaControlsConfig(this);
public final LambdaInput input = new LambdaInput(this);
private LambdaControlsHud hud;
private ControlsMode previous_controls_mode;
@Override
@@ -53,12 +65,13 @@ public class LambdaControls implements ClientModInitializer
{
INSTANCE = this;
this.log("Initializing LambdaControls...");
this.config.load();
KeyBindingRegistry.INSTANCE.register(BINDING_LOOK_UP);
KeyBindingRegistry.INSTANCE.register(BINDING_LOOK_RIGHT);
KeyBindingRegistry.INSTANCE.register(BINDING_LOOK_DOWN);
KeyBindingRegistry.INSTANCE.register(BINDING_LOOK_LEFT);
HudRenderCallback.EVENT.register(delta -> this.hud.render());
}
/**
@@ -66,8 +79,9 @@ public class LambdaControls implements ClientModInitializer
*/
public void on_mc_init(@NotNull MinecraftClient client)
{
Controller.update_mappings();
ButtonBinding.init(client.options);
this.config.load();
Controller.update_mappings();
GLFW.glfwSetJoystickCallback((jid, event) -> {
if (event == GLFW.GLFW_CONNECTED) {
Controller controller = Controller.by_id(jid);
@@ -80,6 +94,10 @@ public class LambdaControls implements ClientModInitializer
this.switch_controls_mode();
});
this.hud = new LambdaControlsHud(client, this);
LambdaControlsCompat.init();
}
/**
@@ -128,6 +146,16 @@ public class LambdaControls implements ClientModInitializer
this.logger.info("[LambdaControls] " + info);
}
/**
* Prints a warning to the terminal.
*
* @param warning The warning to print.
*/
public void warn(String warning)
{
this.logger.info("[LambdaControls] " + warning);
}
/**
* Gets the LambdaControls instance.
*
@@ -138,15 +166,39 @@ public class LambdaControls implements ClientModInitializer
return INSTANCE;
}
public static int draw_button(int x, int y, @NotNull ButtonBinding button, @NotNull MinecraftClient client)
public static Pair<Integer, Integer> draw_button(int x, int y, @NotNull ButtonBinding button, @NotNull MinecraftClient client)
{
return draw_button(x, y, button.get_button(), client);
}
public static int draw_button(int x, int y, int button, @NotNull MinecraftClient client)
public static Pair<Integer, Integer> draw_button(int x, int y, int[] buttons, @NotNull MinecraftClient client)
{
int height = 0;
int length = 0;
int current_x = x;
for (int i = 0; i < buttons.length; i++) {
int btn = buttons[i];
Pair<Integer, Integer> size = draw_button(current_x, y, btn, client);
if (size.get_key() > height)
height = size.get_value();
length += size.get_key();
if (i + 1 < buttons.length) {
length += 2;
current_x = x + length;
}
}
return Pair.of(length, height);
}
public static Pair<Integer, Integer> draw_button(int x, int y, int button, @NotNull MinecraftClient client)
{
boolean second = false;
if (button == -1)
return 0;
return Pair.of(0, 0);
else if (button >= 500) {
button -= 1000;
second = true;
}
int controller_type = get().config.get_controller_type().get_id();
boolean axis = false;
@@ -218,11 +270,11 @@ public class LambdaControls implements ClientModInitializer
client.getTextureManager().bindTexture(axis ? LambdaControls.CONTROLLER_AXIS : LambdaControls.CONTROLLER_BUTTONS);
GlStateManager.disableDepthTest();
GlStateManager.color4f(1.0F, 1.0F, 1.0F, 1.0F);
GlStateManager.color4f(1.0F, second ? 0.0F : 1.0F, 1.0F, 1.0F);
DrawableHelper.blit(x, y, (float) button_offset, (float) (controller_type * (axis ? 18 : 15)), axis ? 18 : 15, axis ? 18 : 15, 256, 256);
GlStateManager.enableDepthTest();
return axis ? 18 : 15;
return axis ? Pair.of(18, 18) : Pair.of(15, 15);
}
public static int draw_button_tip(int x, int y, @NotNull ButtonBinding button, boolean display, @NotNull MinecraftClient client)
@@ -230,10 +282,10 @@ public class LambdaControls implements ClientModInitializer
return draw_button_tip(x, y, button.get_button(), button.get_translation_key(), display, client);
}
public static int draw_button_tip(int x, int y, int button, @NotNull String action, boolean display, @NotNull MinecraftClient client)
public static int draw_button_tip(int x, int y, int[] button, @NotNull String action, boolean display, @NotNull MinecraftClient client)
{
if (display) {
int button_width = draw_button(x, y, button, client);
int button_width = draw_button(x, y, button, client).get_key();
String translated_action = I18n.translate(action);
int text_y = (15 - client.textRenderer.fontHeight) / 2;

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
@@ -10,55 +10,78 @@
package me.lambdaurora.lambdacontrols;
import com.electronwill.nightconfig.core.file.FileConfig;
import net.minecraft.client.options.KeyBinding;
import me.lambdaurora.lambdacontrols.controller.ButtonBinding;
import me.lambdaurora.lambdacontrols.controller.Controller;
import me.lambdaurora.lambdacontrols.controller.InputManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.glfw.GLFW;
import java.util.HashMap;
import java.util.Map;
import java.util.Arrays;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.lwjgl.glfw.GLFW.GLFW_GAMEPAD_AXIS_LEFT_X;
import static org.lwjgl.glfw.GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y;
/**
* Represents LambdaControls configuration.
*/
public class LambdaControlsConfig
{
private final FileConfig config = FileConfig.builder("config/lambdacontrols.toml").concurrent().defaultResource("/config.toml").build();
private final Map<String, KeyBinding> keybinding_mappings = new HashMap<>();
private final LambdaControls mod;
private ControlsMode controls_mode;
private ControllerType controller_type;
private static final ControlsMode DEFAULT_CONTROLS_MODE = ControlsMode.DEFAULT;
private static final boolean DEFAULT_AUTO_SWITCH_MODE = false;
private static final boolean DEFAULT_HUD_ENABLE = true;
private static final HudSide DEFAULT_HUD_SIDE = HudSide.LEFT;
private static final ControllerType DEFAULT_CONTROLLER_TYPE = ControllerType.DEFAULT;
private static final double DEFAULT_DEAD_ZONE = 0.25;
private static final double DEFAULT_ROTATION_SPEED = 40.0;
private static final double DEFAULT_MOUSE_SPEED = 25.0;
private static final Pattern BUTTON_BINDING_PATTERN = Pattern.compile("(-?\\d+)\\+?");
private final FileConfig config = FileConfig.builder("config/lambdacontrols.toml").concurrent().defaultResource("/config.toml").build();
private final LambdaControls mod;
private ControlsMode controls_mode;
private ControllerType controller_type;
// HUD settings.
private boolean hud_enable;
private HudSide hud_side;
private boolean hud_enable;
private HudSide hud_side;
// Controller settings
private double dead_zone;
private double rotation_speed;
private double mouse_speed;
private double dead_zone;
private double rotation_speed;
private double mouse_speed;
public LambdaControlsConfig(@NotNull LambdaControls mod)
{
this.mod = mod;
}
/**
* Loads the configuration
*/
public void load()
{
this.keybinding_mappings.clear();
this.config.load();
this.check_and_fix();
this.mod.log("Configuration loaded.");
this.controls_mode = ControlsMode.by_id(this.config.getOrElse("controls", "default")).orElse(ControlsMode.DEFAULT);
this.controls_mode = ControlsMode.by_id(this.config.getOrElse("controls", DEFAULT_CONTROLS_MODE.get_name())).orElse(DEFAULT_CONTROLS_MODE);
// HUD settings.
this.hud_enable = this.config.getOrElse("hud.enable", true);
this.hud_side = HudSide.by_id(this.config.getOrElse("hud.side", "left")).orElse(HudSide.LEFT);
this.hud_enable = this.config.getOrElse("hud.enable", DEFAULT_HUD_ENABLE);
this.hud_side = HudSide.by_id(this.config.getOrElse("hud.side", DEFAULT_HUD_SIDE.get_name())).orElse(DEFAULT_HUD_SIDE);
// Controller settings.
this.controller_type = ControllerType.by_id(this.config.getOrElse("controller.type", "default")).orElse(ControllerType.DEFAULT);
this.dead_zone = this.config.getOrElse("controller.dead_zone", 0.25);
this.rotation_speed = this.config.getOrElse("controller.rotation_speed", 40.0);
this.mouse_speed = this.config.getOrElse("controller.mouse_speed", 25.0);
this.controller_type = ControllerType.by_id(this.config.getOrElse("controller.type", DEFAULT_CONTROLLER_TYPE.get_name())).orElse(DEFAULT_CONTROLLER_TYPE);
this.dead_zone = this.config.getOrElse("controller.dead_zone", DEFAULT_DEAD_ZONE);
this.rotation_speed = this.config.getOrElse("controller.rotation_speed", DEFAULT_ROTATION_SPEED);
this.mouse_speed = this.config.getOrElse("controller.mouse_speed", DEFAULT_MOUSE_SPEED);
// Controller controls.
ButtonBinding.load_from_config(this);
InputManager.load_button_bindings(this);
}
/**
* Saves the configuration.
*/
public void save()
{
this.config.set("controller.dead_zone", this.dead_zone);
@@ -68,6 +91,35 @@ public class LambdaControlsConfig
this.mod.log("Configuration saved.");
}
public void check_and_fix()
{
InputManager.stream_bindings().forEach(binding -> {
String path = "controller.controls." + binding.get_name();
Object raw = this.config.getRaw(path);
if (raw instanceof Number) {
this.mod.warn("Invalid data at \"" + path + "\", fixing...");
this.config.set(path, "0;" + raw);
}
});
}
/**
* Resets the configuration to default values.
*/
public void reset()
{
this.set_controls_mode(DEFAULT_CONTROLS_MODE);
this.set_auto_switch_mode(DEFAULT_AUTO_SWITCH_MODE);
this.set_hud_enabled(DEFAULT_HUD_ENABLE);
this.set_hud_side(DEFAULT_HUD_SIDE);
this.set_controller_type(DEFAULT_CONTROLLER_TYPE);
this.set_dead_zone(DEFAULT_DEAD_ZONE);
this.set_rotation_speed(DEFAULT_ROTATION_SPEED);
this.set_mouse_speed(DEFAULT_MOUSE_SPEED);
InputManager.stream_bindings().forEach(binding -> this.set_button_binding(binding, binding.get_default_button()));
}
/**
* Gets the controls mode from the configuration.
*
@@ -96,7 +148,7 @@ public class LambdaControlsConfig
*/
public boolean has_auto_switch_mode()
{
return this.config.getOrElse("auto_switch_mode", false);
return this.config.getOrElse("auto_switch_mode", DEFAULT_AUTO_SWITCH_MODE);
}
/**
@@ -177,6 +229,34 @@ public class LambdaControlsConfig
this.config.set("controller.id", controller.get_id());
}
/**
* Gets the second controller (for Joy-Con supports).
*
* @return The second controller.
*/
public @NotNull Optional<Controller> get_second_controller()
{
Object raw = this.config.getRaw("controller.id2");
if (raw instanceof Number) {
if ((int) raw == -1)
return Optional.empty();
return Optional.of(Controller.by_id((Integer) raw));
} else if (raw instanceof String) {
return Optional.of(Controller.by_guid((String) raw).orElse(Controller.by_id(GLFW.GLFW_JOYSTICK_1)));
}
return Optional.empty();
}
/**
* Sets the second controller.
*
* @param controller The second controller.
*/
public void set_second_controller(@Nullable Controller controller)
{
this.config.set("controller.id2", controller == null ? -1 : controller.get_id());
}
/**
* Gets the controller's type.
*
@@ -318,21 +398,6 @@ public class LambdaControlsConfig
return this.does_invert_right_y_axis() ? -1.0 : 1.0;
}
/**
* Returns the keybindings.
*
* @return The keybindings.
*/
public @NotNull Map<String, KeyBinding> get_keybindings()
{
return this.keybinding_mappings;
}
public Optional<KeyBinding> get_keybind(@NotNull String id)
{
return Optional.ofNullable(this.keybinding_mappings.get(id));
}
/**
* Loads the button binding from configuration.
*
@@ -340,7 +405,43 @@ public class LambdaControlsConfig
*/
public void load_button_binding(@NotNull ButtonBinding button)
{
button.set_button(this.config.getOrElse("controller.controls." + button.get_name(), button.get_button()));
button.set_button(button.get_default_button());
String button_code = this.config.getOrElse("controller.controls." + button.get_name(), button.get_button_code());
Matcher matcher = BUTTON_BINDING_PATTERN.matcher(button_code);
try {
int[] buttons = new int[1];
int count = 0;
while (matcher.find()) {
count++;
if (count > buttons.length)
buttons = Arrays.copyOf(buttons, count);
String current;
if (!this.check_validity(button, button_code, current = matcher.group(1)))
return;
buttons[count - 1] = Integer.parseInt(current);
}
if (count == 0) {
this.mod.warn("Malformed config value \"" + button_code + "\" for binding \"" + button.get_name() + "\".");
this.set_button_binding(button, new int[]{-1});
}
button.set_button(buttons);
} catch (Exception e) {
this.mod.warn("Malformed config value \"" + button_code + "\" for binding \"" + button.get_name() + "\".");
this.config.set("controller.controls." + button.get_name(), button.get_button_code());
}
}
private boolean check_validity(@NotNull ButtonBinding binding, @NotNull String input, String group)
{
if (group == null) {
this.mod.warn("Malformed config value \"" + input + "\" for binding \"" + binding.get_name() + "\".");
this.config.set("controller.controls." + binding.get_name(), binding.get_button_code());
return false;
}
return true;
}
/**
@@ -349,51 +450,48 @@ public class LambdaControlsConfig
* @param binding The button binding.
* @param button The button.
*/
public void set_button_binding(@NotNull ButtonBinding binding, int button)
public void set_button_binding(@NotNull ButtonBinding binding, int[] button)
{
binding.set_button(button);
this.config.set("controller.controls." + binding.get_name(), button);
this.config.set("controller.controls." + binding.get_name(), binding.get_button_code());
}
public boolean is_back_button(int btn, boolean is_btn, int state)
{
if (!is_btn && state == 0)
return false;
return ButtonBinding.BACK.is_button(ButtonBinding.axis_as_button(btn, state == 1));
return ButtonBinding.axis_as_button(GLFW_GAMEPAD_AXIS_LEFT_Y, false) == 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 ButtonBinding.FORWARD.is_button(ButtonBinding.axis_as_button(btn, state == 1));
return ButtonBinding.axis_as_button(GLFW_GAMEPAD_AXIS_LEFT_Y, true) == 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 ButtonBinding.LEFT.is_button(ButtonBinding.axis_as_button(btn, state == 1));
return ButtonBinding.axis_as_button(GLFW_GAMEPAD_AXIS_LEFT_X, false) == 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 ButtonBinding.RIGHT.is_button(ButtonBinding.axis_as_button(btn, state == 1));
return ButtonBinding.axis_as_button(GLFW_GAMEPAD_AXIS_LEFT_X, true) == ButtonBinding.axis_as_button(btn, state == 1);
}
/**
* Returns whether the specified axis is an axis used for movements.
*
* @param i The axis index.
* @param axis The axis index.
* @return True if the axis is used for movements, else false.
*/
public boolean is_movement_axis(int i)
public boolean is_movement_axis(int axis)
{
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));
return axis == GLFW_GAMEPAD_AXIS_LEFT_Y || axis == GLFW_GAMEPAD_AXIS_LEFT_X;
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright © 2020 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 io.github.prospector.modmenu.api.ModMenuApi;
import me.lambdaurora.lambdacontrols.gui.LambdaControlsSettingsScreen;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
import java.util.function.Function;
/**
* Represents the API implementation of ModMenu for LambdaControls.
*
* @author LambdAurora
* @version 1.1.0
* @since 1.1.0
*/
public class LambdaControlsModMenu implements ModMenuApi
{
@Override
public String getModId()
{
return LambdaControls.MODID;
}
@Override
public Function<Screen, ? extends Screen> getConfigScreenFactory()
{
return screen -> new LambdaControlsSettingsScreen(screen, MinecraftClient.getInstance().options, false);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
@@ -9,21 +9,21 @@
package me.lambdaurora.lambdacontrols;
import me.lambdaurora.lambdacontrols.gui.LabelWidget;
import me.lambdaurora.lambdacontrols.controller.ButtonBinding;
import me.lambdaurora.lambdacontrols.controller.Controller;
import me.lambdaurora.lambdacontrols.controller.InputManager;
import me.lambdaurora.lambdacontrols.gui.LambdaControlsControlsScreen;
import me.lambdaurora.lambdacontrols.gui.TouchscreenOverlay;
import me.lambdaurora.lambdacontrols.mixin.EntryListWidgetAccessor;
import me.lambdaurora.lambdacontrols.util.AbstractContainerScreenAccessor;
import me.lambdaurora.lambdacontrols.util.CreativeInventoryScreenAccessor;
import me.lambdaurora.lambdacontrols.util.KeyBindingAccessor;
import me.lambdaurora.lambdacontrols.util.MouseAccessor;
import me.lambdaurora.spruceui.SpruceLabelWidget;
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.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;
@@ -32,7 +32,6 @@ import net.minecraft.client.gui.widget.AlwaysSelectedEntryListWidget;
import net.minecraft.client.gui.widget.SliderWidget;
import net.minecraft.container.Slot;
import net.minecraft.container.SlotActionType;
import net.minecraft.item.ItemGroup;
import net.minecraft.util.math.MathHelper;
import org.aperlambda.lambdacommon.utils.Pair;
import org.jetbrains.annotations.NotNull;
@@ -47,25 +46,26 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import static me.lambdaurora.lambdacontrols.ButtonBinding.*;
import static me.lambdaurora.lambdacontrols.controller.ButtonBinding.axis_as_button;
import static org.lwjgl.glfw.GLFW.GLFW_GAMEPAD_AXIS_RIGHT_X;
import static org.lwjgl.glfw.GLFW.GLFW_GAMEPAD_AXIS_RIGHT_Y;
/**
* Represents the LambdaControls' input handler.
*
* @author LambdAurora
* @version 1.1.0
* @since 1.0.0
*/
public class LambdaInput
{
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, Boolean> AXIS_STATES = new HashMap<>();
private static final Map<Integer, Integer> AXIS_COOLDOWNS = new HashMap<>();
private final LambdaControlsConfig config;
// Cooldowns
private int action_gui_cooldown = 0;
private int ignore_next_a = 0;
// Sneak state.
private boolean sneak = false;
private double prev_target_yaw = 0.0;
private double prev_target_pitch = 0.0;
private double target_yaw = 0.0;
@@ -115,19 +115,29 @@ public class LambdaInput
public void on_controller_tick(@NotNull MinecraftClient client)
{
BUTTON_COOLDOWNS.entrySet().stream().filter(entry -> entry.getValue() > 0).forEach(entry -> BUTTON_COOLDOWNS.put(entry.getKey(), entry.getValue() - 1));
AXIS_COOLDOWNS.entrySet().stream().filter(entry -> entry.getValue() > 0).forEach(entry -> AXIS_COOLDOWNS.put(entry.getKey(), entry.getValue() - 1));
// Decreases the cooldown for GUI actions.
if (this.action_gui_cooldown > 0)
--this.action_gui_cooldown;
this.prev_target_mouse_x = this.target_mouse_x;
this.prev_target_mouse_y = this.target_mouse_y;
InputManager.update_states();
Controller controller = this.config.get_controller();
if (controller.is_connected()) {
GLFWGamepadState state = controller.get_state();
this.fetch_button_input(client, state);
this.fetch_axe_input(client, state);
this.fetch_button_input(client, state, false);
this.fetch_axe_input(client, state, false);
}
this.config.get_second_controller().filter(Controller::is_connected)
.ifPresent(joycon -> {
GLFWGamepadState state = joycon.get_state();
this.fetch_button_input(client, state, true);
this.fetch_axe_input(client, state, true);
});
InputManager.update_bindings();
InputManager.stream_active_bindings().forEach(binding -> binding.handle(client, InputManager.get_binding_state(binding)));
if (this.ignore_next_a > 0)
this.ignore_next_a--;
@@ -189,66 +199,73 @@ public class LambdaInput
}
}
private void fetch_button_input(@NotNull MinecraftClient client, @NotNull GLFWGamepadState gamepad_state)
private void fetch_button_input(@NotNull MinecraftClient client, @NotNull GLFWGamepadState gamepad_state, boolean left_joycon)
{
ByteBuffer buffer = gamepad_state.buttons();
for (int btn = 0; btn < buffer.limit(); btn++) {
for (int i = 0; i < buffer.limit(); i++) {
int btn = left_joycon ? ButtonBinding.controller2_button(i) : i;
boolean btn_state = buffer.get() == (byte) 1;
boolean previous_state = BUTTON_STATES.getOrDefault(btn, false);
ButtonState current_state = ButtonState.NONE;
ButtonState previous_state = InputManager.STATES.getOrDefault(btn, ButtonState.NONE);
ButtonBinding.set_button_state(btn, btn_state);
if (btn_state != previous_state) {
if (btn_state != previous_state.is_pressed()) {
current_state = btn_state ? ButtonState.PRESS : ButtonState.RELEASE;
this.handle_button(client, btn, btn_state ? 0 : 1, btn_state);
if (btn_state)
BUTTON_COOLDOWNS.put(btn, 5);
} else if (btn_state) {
current_state = ButtonState.REPEAT;
if (BUTTON_COOLDOWNS.getOrDefault(btn, 0) == 0) {
BUTTON_COOLDOWNS.put(btn, 5);
this.handle_button(client, btn, 2, true);
}
}
BUTTON_STATES.put(btn, btn_state);
InputManager.STATES.put(btn, current_state);
}
}
private void fetch_axe_input(@NotNull MinecraftClient client, @NotNull GLFWGamepadState gamepad_state)
private void fetch_axe_input(@NotNull MinecraftClient client, @NotNull GLFWGamepadState gamepad_state, boolean left_joycon)
{
FloatBuffer buffer = gamepad_state.axes();
for (int i = 0; i < buffer.limit(); i++) {
int axis = left_joycon ? ButtonBinding.controller2_button(i) : i;
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);
//InputManager.(axis_as_button(axis, true), value > 0.5F);
//ButtonBinding.set_button_state(axis_as_button(axis, 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);
this.handle_axe(client, axis, value, abs_value, state);
}
}
public boolean are_buttons_pressed(int[] buttons)
{
int i = 0;
for (int btn : buttons) {
if (BUTTON_STATES.containsKey(btn) && BUTTON_STATES.get(btn))
i++;
}
return i == buttons.length;
}
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);
this.config.set_button_binding(controls_screen.focused_binding, new int[]{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)) {
@@ -267,19 +284,7 @@ public class LambdaInput
}
}
if (action == 0) {
// Handles when the player presses the Start button.
if (PAUSE_GAME.is_button(button)) {
// If in game, then pause the game.
if (client.currentScreen == null)
client.openPauseMenu(false);
else if (client.currentScreen instanceof AbstractContainerScreen) // If the current screen is a container then close it.
client.player.closeContainer();
else// Else just close the current screen.
client.currentScreen.onClose();
return;
}
if (action == 1) {
if (button == GLFW.GLFW_GAMEPAD_BUTTON_A && client.currentScreen != null) {
if (this.action_gui_cooldown == 0) {
Element focused = client.currentScreen.getFocused();
@@ -327,11 +332,6 @@ public class LambdaInput
client.currentScreen.mouseReleased(mouse_x, mouse_y, GLFW.GLFW_MOUSE_BUTTON_1);
}
this.action_gui_cooldown = 5;
return;
}
if (client.currentScreen == null) {
ButtonBinding.handle_button(client, button, action);
}
}
@@ -340,10 +340,11 @@ public class LambdaInput
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))) {
&& !(as_button_state == 2 && (axis == GLFW.GLFW_GAMEPAD_AXIS_LEFT_TRIGGER || axis == GLFW.GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER ||
axis == ButtonBinding.controller2_button(GLFW.GLFW_GAMEPAD_AXIS_LEFT_TRIGGER) || axis == ButtonBinding.controller2_button(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));
this.config.set_button_binding(controls_screen.focused_binding, new int[]{axis_as_button(axis, as_button_state == 1)});
controls_screen.focused_binding = null;
return;
}
@@ -352,38 +353,36 @@ public class LambdaInput
double dead_zone = this.config.get_dead_zone();
if (client.currentScreen == null) {
{
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);
ButtonState previous_plus_state = InputManager.STATES.getOrDefault(axis_as_button(axis, true), ButtonState.NONE);
ButtonState previous_minus_state = InputManager.STATES.getOrDefault(axis_as_button(axis, false), ButtonState.NONE);
if (current_plus_state != previous_plus_state) {
ButtonBinding.handle_button(client, ButtonBinding.axis_as_button(axis, true), 0);
if (current_plus_state != previous_plus_state.is_pressed()) {
InputManager.STATES.put(axis_as_button(axis, true), current_plus_state ? ButtonState.PRESS : ButtonState.RELEASE);
if (current_plus_state)
AXIS_COOLDOWNS.put(axis, 5);
BUTTON_COOLDOWNS.put(axis_as_button(axis, true), 5);
} else if (current_plus_state) {
if (AXIS_COOLDOWNS.getOrDefault(axis, 0) == 0) {
AXIS_COOLDOWNS.put(axis, 5);
InputManager.STATES.put(axis_as_button(axis, true), ButtonState.REPEAT);
if (BUTTON_COOLDOWNS.getOrDefault(axis_as_button(axis, true), 0) == 0) {
BUTTON_COOLDOWNS.put(axis_as_button(axis, true), 5);
}
}
if (current_minus_state != previous_minus_state) {
ButtonBinding.handle_button(client, ButtonBinding.axis_as_button(axis, false), 0);
if (current_minus_state != previous_minus_state.is_pressed()) {
InputManager.STATES.put(axis_as_button(axis, false), current_minus_state ? ButtonState.PRESS : ButtonState.RELEASE);
if (current_minus_state)
AXIS_COOLDOWNS.put(axis_minus, 5);
BUTTON_COOLDOWNS.put(axis_as_button(axis, false), 5);
} else if (current_minus_state) {
if (AXIS_COOLDOWNS.getOrDefault(axis_minus, 0) == 0) {
AXIS_COOLDOWNS.put(axis_minus, 5);
InputManager.STATES.put(axis_as_button(axis, false), ButtonState.REPEAT);
if (BUTTON_COOLDOWNS.getOrDefault(axis_as_button(axis, false), 0) == 0) {
BUTTON_COOLDOWNS.put(axis_as_button(axis, false), 5);
}
}
AXIS_STATES.put(axis, current_plus_state);
AXIS_STATES.put(axis_minus, current_minus_state);
}
// Handles the look direction.
this.handle_look(client, axis, abs_value, state);
this.handle_look(client, axis, (float) (abs_value / (1.0 - this.config.get_dead_zone())), state);
} else {
boolean allow_mouse_control = true;
@@ -422,8 +421,8 @@ public class LambdaInput
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;
this.prev_target_mouse_x = this.target_mouse_x = (int) mouse_x;
this.prev_target_mouse_y = this.target_mouse_y = (int) mouse_y;
}
if (Math.abs(movement_x) >= dead_zone)
@@ -440,7 +439,7 @@ public class LambdaInput
this.mouse_speed_y = 0.F;
}
if (Math.abs(this.mouse_speed_x) > .05F || Math.abs(this.mouse_speed_y) > .05F) {
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_mouse_speed();
this.target_mouse_x = MathHelper.clamp(this.target_mouse_x, 0, client.getWindow().getWidth());
this.target_mouse_y += this.mouse_speed_y * this.config.get_mouse_speed();
@@ -455,32 +454,6 @@ public class LambdaInput
}
}
/**
* 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 && client.player != 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 boolean handle_a_button(@NotNull Screen screen, @NotNull Element focused)
{
if (focused instanceof AbstractPressableButtonWidget) {
@@ -488,8 +461,8 @@ public class LambdaInput
button_widget.playDownSound(MinecraftClient.getInstance().getSoundManager());
button_widget.onPress();
return true;
} else if (focused instanceof LabelWidget) {
((LabelWidget) focused).on_press();
} else if (focused instanceof SpruceLabelWidget) {
((SpruceLabelWidget) focused).on_press();
return true;
} else if (focused instanceof WorldListWidget) {
WorldListWidget list = (WorldListWidget) focused;
@@ -557,7 +530,7 @@ public class LambdaInput
{
// Handles the look direction.
if (client.player != null) {
double pow_value = Math.pow(value, 2.0);
double pow_value = Math.pow(value, 4.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() * pow_value) * 0.33D;

View File

@@ -0,0 +1,41 @@
/*
* Copyright © 2020 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.compat;
import me.lambdaurora.lambdacontrols.controller.ButtonBinding;
import me.lambdaurora.lambdacontrols.controller.InputManager;
import net.fabricmc.fabric.api.client.keybinding.FabricKeyBinding;
import net.fabricmc.loader.api.FabricLoader;
import org.aperlambda.lambdacommon.utils.LambdaReflection;
import org.lwjgl.glfw.GLFW;
/**
* Represents a compatibility handler.
*
* @author LambdAurora
* @version 1.1.0
*/
public class LambdaControlsCompat
{
private static final String OKZOOMER_CLASS_PATH = "io.github.joaoh1.okzoomer.OkZoomer";
public static void init()
{
if (FabricLoader.getInstance().isModLoaded("okzoomer") && LambdaReflection.does_class_exist(OKZOOMER_CLASS_PATH)) {
LambdaReflection.get_class(OKZOOMER_CLASS_PATH).map(clazz -> LambdaReflection.get_first_field_of_type(clazz, FabricKeyBinding.class))
.ifPresent(field -> field.map(f -> (FabricKeyBinding) LambdaReflection.get_field_value(null, f))
.ifPresent(zoom_key_binding -> {
ButtonBinding binding = InputManager.register_binding(new ButtonBinding("zoom", new int[]{GLFW.GLFW_GAMEPAD_BUTTON_DPAD_UP, GLFW.GLFW_GAMEPAD_BUTTON_X}, true));
binding.set_key_binding(zoom_key_binding);
ButtonBinding.MISC_CATEGORY.register_binding(binding);
}));
}
}
}

View File

@@ -0,0 +1,391 @@
/*
* Copyright © 2020 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.controller;
import me.lambdaurora.lambdacontrols.ButtonState;
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.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.glfw.GLFW;
import java.util.*;
import java.util.stream.Collectors;
import static me.lambdaurora.lambdacontrols.controller.InputManager.register_binding;
import static me.lambdaurora.lambdacontrols.controller.InputManager.register_default_category;
/**
* Represents a button binding.
*
* @author LambdAurora
* @version 1.1.0
* @since 1.0.0
*/
public class ButtonBinding implements Nameable
{
public static final ButtonCategory MOVEMENT_CATEGORY;
public static final ButtonCategory GAMEPLAY_CATEGORY;
public static final ButtonCategory INVENTORY_CATEGORY;
public static final ButtonCategory MULTIPLAYER_CATEGORY;
public static final ButtonCategory MISC_CATEGORY;
public static final ButtonBinding ATTACK = register_binding(new ButtonBinding("attack", new int[]{axis_as_button(GLFW.GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER, true)}, false));
public static final ButtonBinding BACK = register_binding(new ButtonBinding("back", new int[]{axis_as_button(GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y, false)}, false));
public static final ButtonBinding CHAT = register_binding(new ButtonBinding("chat", new int[]{GLFW.GLFW_GAMEPAD_BUTTON_DPAD_RIGHT}, true));
public static final ButtonBinding DROP_ITEM = register_binding(new ButtonBinding("drop_item", new int[]{GLFW.GLFW_GAMEPAD_BUTTON_B}, true));
public static final ButtonBinding FORWARD = register_binding(new ButtonBinding("forward", new int[]{axis_as_button(GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y, true)}, false));
public static final ButtonBinding HOTBAR_LEFT = register_binding(new ButtonBinding("hotbar_left", new int[]{GLFW.GLFW_GAMEPAD_BUTTON_LEFT_BUMPER},
Collections.singletonList(InputHandlers.handle_hotbar(false)), true));
public static final ButtonBinding HOTBAR_RIGHT = register_binding(new ButtonBinding("hotbar_right", new int[]{GLFW.GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER},
Collections.singletonList(InputHandlers.handle_hotbar(true)), true));
public static final ButtonBinding INVENTORY = register_binding(new ButtonBinding("inventory", new int[]{GLFW.GLFW_GAMEPAD_BUTTON_Y}, true));
public static final ButtonBinding JUMP = register_binding(new ButtonBinding("jump", new int[]{GLFW.GLFW_GAMEPAD_BUTTON_A}, false));
public static final ButtonBinding LEFT = register_binding(new ButtonBinding("left", new int[]{axis_as_button(GLFW.GLFW_GAMEPAD_AXIS_LEFT_X, false)}, false));
public static final ButtonBinding PAUSE_GAME = register_binding(new ButtonBinding("pause_game", new int[]{GLFW.GLFW_GAMEPAD_BUTTON_START},
Collections.singletonList(InputHandlers::handle_pause_game), true));
public static final ButtonBinding PICK_BLOCK = register_binding(new ButtonBinding("pick_block", new int[]{GLFW.GLFW_GAMEPAD_BUTTON_DPAD_LEFT}, true));
public static final ButtonBinding PLAYER_LIST = register_binding(new ButtonBinding("player_list", new int[]{GLFW.GLFW_GAMEPAD_BUTTON_BACK}, false));
public static final ButtonBinding RIGHT = register_binding(new ButtonBinding("right", new int[]{axis_as_button(GLFW.GLFW_GAMEPAD_AXIS_LEFT_X, true)}, false));
public static final ButtonBinding SCREENSHOT = register_binding(new ButtonBinding("screenshot", new int[]{GLFW.GLFW_GAMEPAD_BUTTON_DPAD_UP, GLFW.GLFW_GAMEPAD_BUTTON_A},
Collections.singletonList((client, button, action) -> {
if (action == ButtonState.PRESS)
ScreenshotUtils.saveScreenshot(client.runDirectory, client.getWindow().getFramebufferWidth(), client.getWindow().getFramebufferHeight(), client.getFramebuffer(),
text -> client.execute(() -> client.inGameHud.getChatHud().addMessage(text)));
return true;
}), true));
public static final ButtonBinding SMOOTH_CAMERA = register_binding(new ButtonBinding("toggle_smooth_camera", new int[]{-1}, true));
public static final ButtonBinding SNEAK = register_binding(new ButtonBinding("sneak", new int[]{GLFW.GLFW_GAMEPAD_BUTTON_RIGHT_THUMB},
Arrays.asList(PressAction.DEFAULT_ACTION, (client, button, action) -> {
if (client.player != null && !client.player.abilities.flying) {
button.as_key_binding().filter(binding -> action == ButtonState.PRESS).ifPresent(binding -> ((KeyBindingAccessor) binding).handle_press_state(!binding.isPressed()));
return true;
}
return false;
}), true));
public static final ButtonBinding SPRINT = register_binding(new ButtonBinding("sprint", new int[]{GLFW.GLFW_GAMEPAD_BUTTON_LEFT_THUMB}, false));
public static final ButtonBinding SWAP_HANDS = register_binding(new ButtonBinding("swap_hands", new int[]{GLFW.GLFW_GAMEPAD_BUTTON_X}, true));
public static final ButtonBinding TOGGLE_PERSPECTIVE = register_binding(new ButtonBinding("toggle_perspective", new int[]{GLFW.GLFW_GAMEPAD_BUTTON_DPAD_UP, GLFW.GLFW_GAMEPAD_BUTTON_Y}, true));
public static final ButtonBinding USE = register_binding(new ButtonBinding("use", new int[]{axis_as_button(GLFW.GLFW_GAMEPAD_AXIS_LEFT_TRIGGER, true)}, 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(PressAction.DEFAULT_ACTION));
private boolean has_cooldown;
private int cooldown = 0;
boolean pressed = false;
public ButtonBinding(@NotNull String key, int[] default_button, @NotNull List<PressAction> actions, boolean has_cooldown)
{
this.button = this.default_button = default_button;
this.key = key;
this.actions.addAll(actions);
this.has_cooldown = has_cooldown;
}
public ButtonBinding(@NotNull String key, int[] default_button, boolean has_cooldown)
{
this(key, default_button, Collections.emptyList(), has_cooldown);
}
/**
* Returns the button bound.
*
* @return The bound button.
*/
public int[] get_button()
{
return this.button;
}
/**
* Sets the bound button.
*
* @param button The bound button.
*/
public void set_button(int[] button)
{
this.button = button;
}
/**
* Returns whether the bound button is the specified button or not.
*
* @param button The button to check.
* @return True if the bound button is the specified button, else false.
*/
public boolean is_button(int[] button)
{
return InputManager.are_buttons_equivalent(button, this.button);
}
/**
* Returns whether this button is down or not.
*
* @return True if the button is down, else false.
*/
public boolean is_button_down()
{
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[0] == -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.length == this.default_button.length && InputManager.are_buttons_equivalent(this.button, this.default_button);
}
/**
* Returns the button code.
*
* @return The button code.
*/
public @NotNull String get_button_code()
{
return Arrays.stream(this.button)
.mapToObj(btn -> Integer.valueOf(btn).toString())
.collect(Collectors.joining("+"));
}
/**
* Sets the key binding to emulate with this button binding.
*
* @param key_binding The optional key binding.
*/
public void set_key_binding(@Nullable KeyBinding key_binding)
{
this.minecraft_key_binding = key_binding;
}
/**
* Updates the button binding cooldown.
*/
public void update()
{
if (this.has_cooldown && this.cooldown > 0)
this.cooldown--;
}
/**
* Handles the button binding.
*
* @param client The client instance.
* @param state The state.
*/
public void handle(@NotNull MinecraftClient client, @NotNull ButtonState state)
{
if (state == ButtonState.REPEAT && this.has_cooldown && this.cooldown != 0)
return;
if (this.has_cooldown && state.is_pressed())
this.cooldown = 5;
for (int i = this.actions.size() - 1; i >= 0; i--) {
if (this.actions.get(i).press(client, this, state))
break;
}
}
@Override
public @NotNull String get_name()
{
return this.key;
}
/**
* Returns the translation key of this button binding.
*
* @return The translation key.
*/
public @NotNull String get_translation_key()
{
return "lambdacontrols.action." + this.get_name();
}
/**
* Returns the key binding equivalent of this button binding.
*
* @return The key binding equivalent.
*/
public @NotNull Optional<KeyBinding> as_key_binding()
{
return Optional.ofNullable(this.minecraft_key_binding);
}
/**
* Returns the specified axis as a button.
*
* @param axis The axis.
* @param positive True if the axis part is positive, else false.
* @return The axis as a button.
*/
public static int axis_as_button(int axis, boolean positive)
{
return positive ? 100 + axis : 200 + axis;
}
/**
* Returns the second Joycon's specified button code.
*
* @param button The raw button code.
* @return The second Joycon's button code.
*/
public static int controller2_button(int button)
{
return 500 + button;
}
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;
}
/**
* 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 % 500) {
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);
}
}
static {
MOVEMENT_CATEGORY = register_default_category("key.categories.movement", category -> category.register_all_bindings(
ButtonBinding.FORWARD,
ButtonBinding.BACK,
ButtonBinding.LEFT,
ButtonBinding.RIGHT,
ButtonBinding.JUMP,
ButtonBinding.SNEAK,
ButtonBinding.SPRINT));
GAMEPLAY_CATEGORY = register_default_category("key.categories.gameplay", category -> category.register_all_bindings(
ButtonBinding.ATTACK,
ButtonBinding.PICK_BLOCK,
ButtonBinding.USE
));
INVENTORY_CATEGORY = register_default_category("key.categories.inventory", category -> category.register_all_bindings(
ButtonBinding.DROP_ITEM,
ButtonBinding.HOTBAR_LEFT,
ButtonBinding.HOTBAR_RIGHT,
ButtonBinding.INVENTORY,
ButtonBinding.SWAP_HANDS
));
MULTIPLAYER_CATEGORY = register_default_category("key.categories.multiplayer",
category -> category.register_all_bindings(ButtonBinding.CHAT, ButtonBinding.PLAYER_LIST));
MISC_CATEGORY = register_default_category("key.categories.misc", category -> category.register_all_bindings(
ButtonBinding.SCREENSHOT,
//SMOOTH_CAMERA,
ButtonBinding.TOGGLE_PERSPECTIVE
));
}
}

View File

@@ -0,0 +1,104 @@
/*
* Copyright © 2020 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.controller;
import net.minecraft.client.resource.language.I18n;
import org.aperlambda.lambdacommon.Identifier;
import org.aperlambda.lambdacommon.utils.Identifiable;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* Represents a button binding category
*
* @author LambdAurora
* @version 1.1.0
* @since 1.1.0
*/
public class ButtonCategory implements Identifiable
{
private final List<ButtonBinding> bindings = new ArrayList<>();
private final Identifier id;
private int priority;
public ButtonCategory(@NotNull Identifier id, int priority)
{
this.id = id;
this.priority = priority;
}
public ButtonCategory(@NotNull Identifier id)
{
this(id, 100);
}
public void register_binding(@NotNull ButtonBinding binding)
{
if (this.bindings.contains(binding))
throw new IllegalStateException("Cannot register twice a button binding in the same category.");
this.bindings.add(binding);
}
public void register_all_bindings(@NotNull ButtonBinding... bindings)
{
this.register_all_bindings(Arrays.asList(bindings));
}
public void register_all_bindings(@NotNull List<ButtonBinding> bindings)
{
bindings.forEach(this::register_binding);
}
/**
* Gets the bindings assigned to this category.
*
* @return The bindings assigned to this category.
*/
public @NotNull List<ButtonBinding> get_bindings()
{
return Collections.unmodifiableList(this.bindings);
}
/**
* Gets the translated name of this category.
* <p>
* The translation key should be `modid.identifier_name`.
*
* @return The translated name.
*/
public @NotNull String get_translated_name()
{
if (this.id.get_namespace().equals("minecraft"))
return I18n.translate(this.id.get_name());
else
return I18n.translate(this.id.get_namespace() + "." + this.id.get_name());
}
/**
* Gets the priority display of this category.
* It will defines in which order the categories will display on the controls screen.
*
* @return The priority of this category.
*/
public int get_priority()
{
return this.priority;
}
@Override
public @NotNull Identifier get_identifier()
{
return this.id;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
@@ -7,8 +7,9 @@
* see the LICENSE file.
*/
package me.lambdaurora.lambdacontrols;
package me.lambdaurora.lambdacontrols.controller;
import me.lambdaurora.lambdacontrols.LambdaControls;
import org.aperlambda.lambdacommon.utils.Nameable;
import org.jetbrains.annotations.NotNull;
import org.lwjgl.glfw.GLFW;
@@ -31,6 +32,10 @@ import static org.lwjgl.BufferUtils.createByteBuffer;
/**
* Represents a controller.
*
* @author LambdAurora
* @version 1.0.0
* @since 1.0.0
*/
public class Controller implements Nameable
{

View File

@@ -0,0 +1,70 @@
/*
* Copyright © 2020 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.controller;
import me.lambdaurora.lambdacontrols.ButtonState;
import me.lambdaurora.lambdacontrols.util.CreativeInventoryScreenAccessor;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.ingame.AbstractContainerScreen;
import net.minecraft.client.gui.screen.ingame.CreativeInventoryScreen;
import net.minecraft.item.ItemGroup;
import org.jetbrains.annotations.NotNull;
/**
* Represents some input handlers.
*
* @author LambdAurora
* @version 1.1.0
* @since 1.1.0
*/
public class InputHandlers
{
private InputHandlers() {}
public static PressAction handle_hotbar(boolean right) {
return (client, button, action) -> {
if (action == ButtonState.RELEASE)
return false;
// When ingame
if (client.currentScreen == null && client.player != 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;
return true;
} 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]);
return true;
}
return false;
};
}
public static boolean handle_pause_game(@NotNull MinecraftClient client, @NotNull ButtonBinding binding, @NotNull ButtonState action) {
if (action == ButtonState.PRESS) {
// If in game, then pause the game.
if (client.currentScreen == null)
client.openPauseMenu(false);
else if (client.currentScreen instanceof AbstractContainerScreen && client.player != null) // If the current screen is a container then close it.
client.player.closeContainer();
else // Else just close the current screen.
client.currentScreen.onClose();
}
return true;
}
}

View File

@@ -0,0 +1,197 @@
/*
* Copyright © 2020 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.controller;
import me.lambdaurora.lambdacontrols.ButtonState;
import me.lambdaurora.lambdacontrols.LambdaControlsConfig;
import org.aperlambda.lambdacommon.Identifier;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Stream;
/**
* Represents an input manager for controllers.
*
* @author LambdAurora
* @version 1.1.0
* @since 1.1.0
*/
public class InputManager
{
private static final List<ButtonBinding> BINDINGS = new ArrayList<>();
private static final List<ButtonCategory> CATEGORIES = new ArrayList<>();
public static final Map<Integer, ButtonState> STATES = new HashMap<>();
public static @NotNull ButtonBinding register_binding(@NotNull ButtonBinding binding)
{
if (BINDINGS.contains(binding))
throw new IllegalStateException("Cannot register twice a button binding in the registry.");
BINDINGS.add(binding);
return binding;
}
public static ButtonBinding register_binding(@NotNull Identifier binding_id, int[] default_button, @NotNull List<PressAction> actions, boolean has_cooldown)
{
return register_binding(new ButtonBinding(binding_id.get_namespace() + "." + binding_id.get_name(), default_button, actions, has_cooldown));
}
public static ButtonBinding register_binding(@NotNull Identifier binding_id, int[] default_button, boolean has_cooldown)
{
return register_binding(binding_id, default_button, Collections.emptyList(), has_cooldown);
}
public static ButtonBinding register_binding(@NotNull net.minecraft.util.Identifier binding_id, int[] default_button, @NotNull List<PressAction> actions, boolean has_cooldown)
{
return register_binding(new Identifier(binding_id.getNamespace(), binding_id.getPath()), default_button, actions, has_cooldown);
}
public static ButtonBinding register_binding(@NotNull net.minecraft.util.Identifier binding_id, int[] default_button, boolean has_cooldown)
{
return register_binding(binding_id, default_button, Collections.emptyList(), has_cooldown);
}
/**
* Registers a category of button bindings.
*
* @param category The category to register.
* @return The registered category.
*/
public static ButtonCategory register_category(@NotNull ButtonCategory category)
{
CATEGORIES.add(category);
return category;
}
public static ButtonCategory register_category(@NotNull Identifier identifier, int priority)
{
return register_category(new ButtonCategory(identifier, priority));
}
public static ButtonCategory register_category(@NotNull Identifier identifier)
{
return register_category(new ButtonCategory(identifier));
}
protected static ButtonCategory register_default_category(@NotNull String key, @NotNull Consumer<ButtonCategory> key_adder)
{
ButtonCategory category = register_category(new Identifier("minecraft", key), CATEGORIES.size());
key_adder.accept(category);
return category;
}
/**
* Loads the button bindings from configuration.
*
* @param config The configuration instance.
*/
public static void load_button_bindings(@NotNull LambdaControlsConfig config)
{
BINDINGS.forEach(config::load_button_binding);
}
/**
* Returns the binding state.
*
* @param binding The binding.
* @return The current state of the binding.
*/
public static @NotNull ButtonState get_binding_state(@NotNull ButtonBinding binding)
{
ButtonState state = ButtonState.REPEAT;
for (int btn : binding.get_button()) {
ButtonState btn_state = InputManager.STATES.getOrDefault(btn, ButtonState.NONE);
if (btn_state == ButtonState.PRESS)
state = ButtonState.PRESS;
else if (btn_state == ButtonState.RELEASE) {
state = ButtonState.RELEASE;
break;
} else if (btn_state == ButtonState.NONE) {
state = ButtonState.NONE;
break;
}
}
return state;
}
/**
* 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_duplicated_bindings(int[] button)
{
return BINDINGS.parallelStream().filter(binding -> are_buttons_equivalent(binding.get_button(), button)).count() > 1;
}
/**
* Returns whether the specified buttons are equivalent or not.
*
* @param buttons1 First set of buttons.
* @param buttons2 Second set of buttons.
* @return True if the two sets of buttons are equivalent, else false.
*/
public static boolean are_buttons_equivalent(int[] buttons1, int[] buttons2)
{
if (buttons1.length != buttons2.length)
return false;
int count = 0;
for (int btn : buttons1) {
for (int btn2 : buttons2) {
if (btn == btn2) {
count++;
break;
}
}
}
return count == buttons1.length;
}
/**
* Updates the button states.
*/
public static void update_states()
{
STATES.forEach((btn, state) -> {
if (state == ButtonState.PRESS)
STATES.put(btn, ButtonState.REPEAT);
else if (state == ButtonState.RELEASE)
STATES.put(btn, ButtonState.NONE);
});
}
public static void update_bindings() {
BINDINGS.forEach(binding -> binding.pressed = get_binding_state(binding).is_pressed());
BINDINGS.forEach(ButtonBinding::update);
}
public static @NotNull Stream<ButtonBinding> stream_bindings()
{
return BINDINGS.stream();
}
public static @NotNull Stream<ButtonBinding> stream_active_bindings()
{
return BINDINGS.stream().filter(binding -> {
for (int btn : binding.get_button()) {
if (InputManager.STATES.getOrDefault(btn, ButtonState.NONE) == ButtonState.NONE)
return false;
}
return true;
});
}
public static @NotNull Stream<ButtonCategory> stream_categories()
{
return CATEGORIES.stream();
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright © 2020 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.controller;
import me.lambdaurora.lambdacontrols.ButtonState;
import me.lambdaurora.lambdacontrols.util.KeyBindingAccessor;
import net.minecraft.client.MinecraftClient;
import org.jetbrains.annotations.NotNull;
/**
* Represents a press action callback.
*
* @author LambdAurora
* @version 1.1.0
* @since 1.0.0
*/
@FunctionalInterface
public interface PressAction
{
PressAction DEFAULT_ACTION = (client, button, action) -> {
if (action == ButtonState.REPEAT || client.currentScreen != null)
return false;
button.as_key_binding().ifPresent(key_binding -> ((KeyBindingAccessor) key_binding).handle_press_state(button.is_button_down()));
return true;
};
/**
* Handles when there is a press action.
*
* @param client The client instance.
* @param action The action done.
*/
boolean press(@NotNull MinecraftClient client, @NotNull ButtonBinding button, @NotNull ButtonState action);
}

View File

@@ -1,55 +0,0 @@
/*
* 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 com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.util.math.MathHelper;
import org.jetbrains.annotations.NotNull;
/**
* Represents a button with an icon instead of text.
*/
public abstract class AbstractIconButtonWidget extends ButtonWidget
{
private int icon_size = 0;
public AbstractIconButtonWidget(int x, int y, int width, int height, @NotNull String message, @NotNull PressAction on_press)
{
super(x, y, width, height, message, on_press);
}
protected abstract int render_icon(int mouse_x, int mouse_y, float delta, int x, int y);
@Override
public void renderButton(int mouse_x, int mouse_y, float delta)
{
MinecraftClient client = MinecraftClient.getInstance();
client.getTextureManager().bindTexture(WIDGETS_LOCATION);
RenderSystem.color4f(1.0F, 1.0F, 1.0F, this.alpha);
int i = this.getYImage(this.isHovered());
RenderSystem.enableBlend();
RenderSystem.defaultBlendFunc();
RenderSystem.blendFunc(GlStateManager.SrcFactor.SRC_ALPHA, GlStateManager.DstFactor.ONE_MINUS_SRC_ALPHA);
this.blit(this.x, this.y, 0, 46 + i * 20, this.width / 2, this.height);
this.blit(this.x + this.width / 2, this.y, 200 - this.width / 2, 46 + i * 20, this.width / 2, this.height);
this.renderBg(client, mouse_x, mouse_y);
this.icon_size = this.render_icon(mouse_x, mouse_y, delta, this.x + 4, this.y + (this.height / 2 - this.icon_size / 2));
if (!this.getMessage().isEmpty()) {
int j = this.active ? 16777215 : 10526880;
this.drawCenteredString(client.textRenderer, this.getMessage(), this.x + 8 + this.icon_size + (this.width - 8 - this.icon_size - 6) / 2,
this.y + (this.height - 8) / 2, j | MathHelper.ceil(this.alpha * 255.0F) << 24);
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
@@ -9,8 +9,9 @@
package me.lambdaurora.lambdacontrols.gui;
import me.lambdaurora.lambdacontrols.ButtonBinding;
import me.lambdaurora.lambdacontrols.controller.ButtonBinding;
import me.lambdaurora.lambdacontrols.LambdaControls;
import me.lambdaurora.spruceui.AbstractIconButtonWidget;
import net.minecraft.client.MinecraftClient;
import org.jetbrains.annotations.NotNull;
@@ -23,18 +24,18 @@ public class ControllerButtonWidget extends AbstractIconButtonWidget
public ControllerButtonWidget(int x, int y, int width, @NotNull ButtonBinding button_binding, @NotNull PressAction on_press)
{
super(x, y, width, 20, ButtonBinding.get_localized_button_name(button_binding.get_button()), on_press);
super(x, y, width, 20, ButtonBinding.get_localized_button_name(button_binding.get_button()[0]), on_press);
this.binding = button_binding;
}
public void update()
{
this.setMessage(ButtonBinding.get_localized_button_name(binding.get_button()));
this.setMessage(ButtonBinding.get_localized_button_name(binding.get_button()[0]));
}
@Override
protected int render_icon(int mouse_x, int mouse_y, float delta, int x, int y)
{
return LambdaControls.draw_button(x, y, this.binding, MinecraftClient.getInstance());
return LambdaControls.draw_button(x, y, this.binding, MinecraftClient.getInstance()).get_value();
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
@@ -9,7 +9,9 @@
package me.lambdaurora.lambdacontrols.gui;
import me.lambdaurora.lambdacontrols.ButtonBinding;
import me.lambdaurora.lambdacontrols.controller.ButtonBinding;
import me.lambdaurora.lambdacontrols.controller.ButtonCategory;
import me.lambdaurora.lambdacontrols.controller.InputManager;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.MinecraftClient;
@@ -39,8 +41,8 @@ public class ControlsListWidget extends ElementListWidget<ControlsListWidget.Ent
super(client, gui.width + 45, gui.height, 43, gui.height - 32, 24);
this.gui = gui;
ButtonBinding.stream_categories()
.sorted(Comparator.comparingInt(ButtonBinding.Category::get_priority))
InputManager.stream_categories()
.sorted(Comparator.comparingInt(ButtonCategory::get_priority))
.forEach(category -> {
this.addEntry(new CategoryEntry(category));
@@ -78,7 +80,7 @@ public class ControlsListWidget extends ElementListWidget<ControlsListWidget.Ent
{
this.binding = binding;
this.binding_name = I18n.translate(this.binding.get_translation_key());
this.edit_button = new ControllerButtonWidget(0, 0, 90, this.binding, btn -> gui.focused_binding = binding)
this.edit_button = new ControllerButtonWidget(0, 0, 110, this.binding, btn -> gui.focused_binding = binding)
{
protected String getNarrationMessage()
{
@@ -114,16 +116,16 @@ public class ControlsListWidget extends ElementListWidget<ControlsListWidget.Ent
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 + 85;
this.edit_button.x = x + 75;
this.edit_button.y = y;
this.edit_button.update();
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())) {
} else if (!this.binding.is_not_bound() && InputManager.has_duplicated_bindings(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.setMessage(Formatting.GOLD + this.edit_button.getMessage());
}
this.edit_button.render(mouse_x, mouse_y, delta);
@@ -148,7 +150,7 @@ public class ControlsListWidget extends ElementListWidget<ControlsListWidget.Ent
private final String name;
private final int name_width;
public CategoryEntry(@NotNull ButtonBinding.Category category)
public CategoryEntry(@NotNull ButtonCategory category)
{
this.name = category.get_translated_name();
this.name_width = ControlsListWidget.this.minecraft.textRenderer.getStringWidth(this.name);

View File

@@ -1,239 +0,0 @@
/*
* 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 com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.Drawable;
import net.minecraft.client.gui.DrawableHelper;
import net.minecraft.client.gui.Element;
import net.minecraft.client.render.Tessellator;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.util.math.Matrix4f;
import net.minecraft.client.util.math.MatrixStack;
import org.jetbrains.annotations.NotNull;
import org.lwjgl.glfw.GLFW;
import java.util.List;
import java.util.function.Consumer;
/**
* Represents a label widget.
*/
// @TODO move this to a GUI library.
public class LabelWidget extends DrawableHelper implements Element, Drawable
{
public static final Consumer<LabelWidget> DEFAULT_ACTION = label -> {
};
private final MinecraftClient client = MinecraftClient.getInstance();
private final Consumer<LabelWidget> press_action;
private final int x;
private final int y;
private final int max_width;
//private final int max_height;
private String text;
private String tooltip_text;
public boolean visible;
private int width;
private int height;
private boolean centered;
protected boolean hovered;
protected boolean focused;
public LabelWidget(int x, int y, @NotNull String text, int max_width, @NotNull Consumer<LabelWidget> press_action, boolean centered)
{
this.visible = true;
this.x = x;
this.y = y;
this.max_width = max_width;
this.press_action = press_action;
this.centered = centered;
this.set_text(text);
}
public LabelWidget(int x, int y, @NotNull String text, int max_width, @NotNull Consumer<LabelWidget> press_action)
{
this(x, y, text, max_width, press_action, false);
}
public LabelWidget(int x, int y, @NotNull String text, int max_width, boolean centered)
{
this(x, y, text, max_width, DEFAULT_ACTION, centered);
}
public LabelWidget(int x, int y, @NotNull String text, int max_width)
{
this(x, y, text, max_width, DEFAULT_ACTION);
}
/**
* Sets the text of this label.
*
* @param text The text to set.
*/
public void set_text(@NotNull String text)
{
int width = this.client.textRenderer.getStringWidth(text);
while (width > this.max_width) {
text = text.substring(0, text.length() - 1);
width = this.client.textRenderer.getStringWidth(text);
}
this.text = text;
this.width = width;
this.height = this.client.textRenderer.fontHeight;
}
/**
* Sets the tooltip text of this label.
*
* @param text The tooltip text.
*/
public void set_tooltip_text(String text)
{
this.tooltip_text = text;
}
/**
* Gets the width of this label widget.
*
* @return The width of this label widget.
*/
public int get_width()
{
return this.width;
}
/**
* Gets the height of this label widget.
*
* @return The height of this label widget.
*/
public int get_height()
{
return this.height;
}
/**
* Fires the press event on this label widget.
*/
public void on_press()
{
this.press_action.accept(this);
}
@Override
public void render(int mouse_x, int mouse_y, float delta)
{
if (this.visible) {
int x = this.centered ? this.x - this.client.textRenderer.getStringWidth(this.text) / 2 : this.x;
this.hovered = mouse_x >= x && mouse_y >= this.y && mouse_x < x + this.width && mouse_y < this.y + this.height;
this.drawString(this.client.textRenderer, this.text, x, this.y, 10526880);
if (this.tooltip_text != null && !this.tooltip_text.isEmpty()) {
List<String> wrapped_tooltip_text = this.client.textRenderer.wrapStringToWidthAsList(this.tooltip_text, Math.max(this.width / 2, 200));
if (this.hovered)
this.render_tooltip(wrapped_tooltip_text, mouse_x, mouse_y);
else if (this.focused)
this.render_tooltip(wrapped_tooltip_text, this.x - 12, this.y);
}
}
}
@Override
public boolean mouseClicked(double mouse_x, double mouse_y, int button)
{
if (this.visible && button == GLFW.GLFW_MOUSE_BUTTON_1) {
if (this.hovered) {
this.on_press();
return true;
}
}
return false;
}
@Override
public boolean changeFocus(boolean down)
{
if (this.visible) {
this.focused = !this.focused;
return this.focused;
} else {
return false;
}
}
public void render_tooltip(List<String> text, int x, int y)
{
if (!text.isEmpty()) {
RenderSystem.disableRescaleNormal();
RenderSystem.disableDepthTest();
int i = 0;
for (String string : text) {
int j = this.client.textRenderer.getStringWidth(string);
if (j > i) {
i = j;
}
}
int k = x + 12;
int l = y - 12;
int n = 8;
if (text.size() > 1) {
n += 2 + (text.size() - 1) * 10;
}
if (k + i > this.client.getWindow().getScaledWidth()) {
k -= 28 + i;
}
if (l + n + 6 > this.client.getWindow().getScaledHeight()) {
l = this.client.getWindow().getScaledHeight() - n - 6;
}
this.setBlitOffset(300);
this.client.getItemRenderer().zOffset = 300.0F;
this.fillGradient(k - 3, l - 4, k + i + 3, l - 3, -267386864, -267386864);
this.fillGradient(k - 3, l + n + 3, k + i + 3, l + n + 4, -267386864, -267386864);
this.fillGradient(k - 3, l - 3, k + i + 3, l + n + 3, -267386864, -267386864);
this.fillGradient(k - 4, l - 3, k - 3, l + n + 3, -267386864, -267386864);
this.fillGradient(k + i + 3, l - 3, k + i + 4, l + n + 3, -267386864, -267386864);
this.fillGradient(k - 3, l - 3 + 1, k - 3 + 1, l + n + 3 - 1, 1347420415, 1344798847);
this.fillGradient(k + i + 2, l - 3 + 1, k + i + 3, l + n + 3 - 1, 1347420415, 1344798847);
this.fillGradient(k - 3, l - 3, k + i + 3, l - 3 + 1, 1347420415, 1347420415);
this.fillGradient(k - 3, l + n + 2, k + i + 3, l + n + 3, 1344798847, 1344798847);
MatrixStack matrix_stack = new MatrixStack();
VertexConsumerProvider.Immediate immediate = VertexConsumerProvider.immediate(Tessellator.getInstance().getBuffer());
matrix_stack.translate(0.0D, 0.0D, this.client.getItemRenderer().zOffset);
Matrix4f matrix4f = matrix_stack.peek().getModel();
for (int r = 0; r < text.size(); ++r) {
String string2 = text.get(r);
if (string2 != null) {
this.client.textRenderer.draw(string2, (float) k, (float) l, -1, true, matrix4f, immediate, false, 0, 15728880);
}
if (r == 0) {
l += 2;
}
l += 10;
}
immediate.draw();
this.setBlitOffset(0);
this.client.getItemRenderer().zOffset = 0.0F;
RenderSystem.enableDepthTest();
RenderSystem.enableRescaleNormal();
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
@@ -9,9 +9,12 @@
package me.lambdaurora.lambdacontrols.gui;
import me.lambdaurora.lambdacontrols.ButtonBinding;
import me.lambdaurora.lambdacontrols.controller.ButtonBinding;
import me.lambdaurora.lambdacontrols.LambdaControls;
import me.lambdaurora.lambdacontrols.controller.InputManager;
import me.lambdaurora.spruceui.SpruceButtonWidget;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.options.ControlsOptionsScreen;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.options.BooleanOption;
import net.minecraft.client.options.Option;
@@ -27,19 +30,21 @@ import java.util.function.Predicate;
*/
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;
private final Screen parent;
final LambdaControls mod;
private final Option inverts_right_x_axis;
private final Option inverts_right_y_axis;
private final boolean hide_settings;
private ControlsListWidget bindings_list_widget;
private ButtonWidget reset_button;
public ButtonBinding focused_binding;
protected LambdaControlsControlsScreen(@NotNull LambdaControlsSettingsScreen parent)
public LambdaControlsControlsScreen(@NotNull Screen parent, boolean hide_settings)
{
super(new TranslatableText("lambdacontrols.menu.title.controller_controls"));
this.parent = parent;
this.mod = parent.mod;
this.mod = LambdaControls.get();
this.hide_settings = hide_settings;
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) {
@@ -64,12 +69,17 @@ public class LambdaControlsControlsScreen extends Screen
@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.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.addButton(new SpruceButtonWidget(this.width / 2 - 155, 18, this.hide_settings ? 310 : 150, 20, I18n.translate("lambdacontrols.menu.keyboard_controls"),
btn -> this.minecraft.openScreen(new ControlsOptionsScreen(this, this.minecraft.options))));
if (!this.hide_settings)
this.addButton(new SpruceButtonWidget(this.width / 2 - 155 + 160, 18, 150, 20, I18n.translate("menu.options"),
btn -> this.minecraft.openScreen(new LambdaControlsSettingsScreen(this, this.minecraft.options, true))));
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()))));
btn -> InputManager.stream_bindings().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)));
}
@@ -87,7 +97,7 @@ public class LambdaControlsControlsScreen extends Screen
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));
this.reset_button.active = InputManager.stream_bindings().anyMatch(this.not(ButtonBinding::is_default));
super.render(mouse_x, mouse_y, delta);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
@@ -9,7 +9,8 @@
package me.lambdaurora.lambdacontrols.gui;
import me.lambdaurora.lambdacontrols.ButtonBinding;
import me.lambdaurora.lambdacontrols.HudSide;
import me.lambdaurora.lambdacontrols.controller.ButtonBinding;
import me.lambdaurora.lambdacontrols.ControlsMode;
import me.lambdaurora.lambdacontrols.LambdaControls;
import net.minecraft.client.MinecraftClient;
@@ -19,11 +20,17 @@ import org.jetbrains.annotations.NotNull;
/**
* Represents the LambdaControls HUD.
*
* @author LambdAurora
* @version 1.1.0
* @since 1.0.0
*/
public class LambdaControlsHud extends DrawableHelper
{
private final MinecraftClient client;
private final LambdaControls mod;
private int width_bottom = 0;
private int width_top = 0;
public LambdaControlsHud(@NotNull MinecraftClient client, @NotNull LambdaControls mod)
{
@@ -37,12 +44,12 @@ public class LambdaControlsHud extends DrawableHelper
public void render()
{
if (this.mod.config.get_controls_mode() == ControlsMode.CONTROLLER && this.mod.config.is_hud_enabled() && this.client.currentScreen == null && !this.client.options.hudHidden) {
int x = 10, y = bottom(10);
x += this.draw_button_tip(x, y, ButtonBinding.INVENTORY, true) + 10;
this.draw_button_tip(x, y, ButtonBinding.SWAP_HANDS, true);
x = 10;
x += this.draw_button_tip(x, (y -= 20), ButtonBinding.DROP_ITEM, !this.client.player.getMainHandStack().isEmpty()) + 10;
this.draw_button_tip(x, y, ButtonBinding.ATTACK.get_button(),
int x = this.mod.config.get_hud_side() == HudSide.LEFT ? 10 : client.getWindow().getScaledWidth() - 10 - this.width_bottom, y = bottom(10);
x += (this.width_bottom = this.draw_button_tip(x, y, ButtonBinding.INVENTORY, true) + 10);
this.width_bottom += this.draw_button_tip(x, y, ButtonBinding.SWAP_HANDS, true);
x = this.mod.config.get_hud_side() == HudSide.LEFT ? 10 : client.getWindow().getScaledWidth() - 10 - this.width_top;
x += (this.width_top = this.draw_button_tip(x, (y -= 20), ButtonBinding.DROP_ITEM, !this.client.player.getMainHandStack().isEmpty()) + 10);
this.width_top += this.draw_button_tip(x, y, ButtonBinding.ATTACK.get_button(),
this.client.crosshairTarget.getType() == HitResult.Type.BLOCK ? "lambdacontrols.action.hit" : ButtonBinding.ATTACK.get_translation_key(),
this.client.crosshairTarget.getType() != HitResult.Type.MISS);
}
@@ -58,7 +65,7 @@ public class LambdaControlsHud extends DrawableHelper
return LambdaControls.draw_button_tip(x, y, button, display, this.client);
}
private int draw_button_tip(int x, int y, int button, @NotNull String action, boolean display)
private int draw_button_tip(int x, int y, int[] button, @NotNull String action, boolean display)
{
return LambdaControls.draw_button_tip(x, y, button, action, display, this.client);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
@@ -9,14 +9,21 @@
package me.lambdaurora.lambdacontrols.gui;
import me.lambdaurora.lambdacontrols.Controller;
import me.lambdaurora.lambdacontrols.ControlsMode;
import me.lambdaurora.lambdacontrols.LambdaControls;
import me.lambdaurora.lambdacontrols.controller.Controller;
import me.lambdaurora.spruceui.SpruceButtonWidget;
import me.lambdaurora.spruceui.SpruceLabelWidget;
import me.lambdaurora.spruceui.Tooltip;
import me.lambdaurora.spruceui.option.*;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.options.ControlsOptionsScreen;
import net.minecraft.client.gui.widget.ButtonListWidget;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.options.*;
import net.minecraft.client.options.CyclingOption;
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 net.minecraft.util.Formatting;
@@ -29,30 +36,32 @@ import org.lwjgl.glfw.GLFW;
*/
public class LambdaControlsSettingsScreen extends Screen
{
public static final String GAMEPAD_TOOL_URL = "http://generalarcade.com/gamepadtool/";
final LambdaControls mod;
private final Screen parent;
private final GameOptions options;
private final Option auto_switch_mode_option;
private final Option controller_option;
private final Option controller_type_option;
private final Option dead_zone_option;
private final Option hud_enable_option;
private final Option hud_side_option;
private final Option mouse_speed_option;
private final Option rotation_speed_option;
private final String controller_mappings_url_text = I18n.translate("lambdacontrols.controller.mappings.2", Formatting.GOLD.toString(), GAMEPAD_TOOL_URL, Formatting.RESET.toString());
private ButtonListWidget list;
private LabelWidget gamepad_tool_url_label;
public static final String GAMEPAD_TOOL_URL = "http://generalarcade.com/gamepadtool/";
final LambdaControls mod;
private final Screen parent;
private final boolean hide_controls;
private final Option auto_switch_mode_option;
private final Option controller_option;
private final Option second_controller_option;
private final Option controller_type_option;
private final Option dead_zone_option;
private final Option hud_enable_option;
private final Option hud_side_option;
private final Option mouse_speed_option;
private final Option rotation_speed_option;
private final Option reset_option;
private final String controller_mappings_url_text = I18n.translate("lambdacontrols.controller.mappings.2", Formatting.GOLD.toString(), GAMEPAD_TOOL_URL, Formatting.RESET.toString());
private ButtonListWidget list;
private SpruceLabelWidget gamepad_tool_url_label;
public LambdaControlsSettingsScreen(Screen parent, @NotNull GameOptions options)
public LambdaControlsSettingsScreen(Screen parent, @NotNull GameOptions options, boolean hide_controls)
{
super(new TranslatableText("lambdacontrols.title.settings"));
this.mod = LambdaControls.get();
this.parent = parent;
this.options = options;
this.auto_switch_mode_option = new BooleanOption("lambdacontrols.menu.auto_switch_mode", game_options -> this.mod.config.has_auto_switch_mode(),
(game_options, new_value) -> this.mod.config.set_auto_switch_mode(new_value));
this.hide_controls = hide_controls;
this.auto_switch_mode_option = new SpruceBooleanOption("lambdacontrols.menu.auto_switch_mode", game_options -> this.mod.config.has_auto_switch_mode(),
(game_options, new_value) -> this.mod.config.set_auto_switch_mode(new_value), new TranslatableText("lambdacontrols.tooltip.auto_switch_mode"));
this.controller_option = new CyclingOption("lambdacontrols.menu.controller", (game_options, amount) -> {
int current_id = this.mod.config.get_controller().get_id();
current_id += amount;
@@ -68,15 +77,34 @@ public class LambdaControlsSettingsScreen extends Screen
else
return option.getDisplayPrefix() + controller_name;
});
this.controller_type_option = new CyclingOption("lambdacontrols.menu.controller_type",
this.second_controller_option = new SpruceCyclingOption("lambdacontrols.menu.controller2",
(game_options, amount) -> {
int current_id = this.mod.config.get_second_controller().map(Controller::get_id).orElse(-1);
current_id += amount;
if (current_id > GLFW.GLFW_JOYSTICK_LAST)
current_id = -1;
this.mod.config.set_second_controller(current_id == -1 ? null : Controller.by_id(current_id));
}, (game_options, option) -> this.mod.config.get_second_controller().map(controller -> {
String controller_name = controller.get_name();
if (!controller.is_connected())
return option.getDisplayPrefix() + Formatting.RED + controller_name;
else if (!controller.is_gamepad())
return option.getDisplayPrefix() + Formatting.GOLD + controller_name;
else
return option.getDisplayPrefix() + controller_name;
}).orElse(option.getDisplayPrefix() + Formatting.RED + I18n.translate("options.off")),
new TranslatableText("lambdacontrols.tooltip.controller2"));
this.controller_type_option = new SpruceCyclingOption("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());
this.hud_enable_option = new BooleanOption("lambdacontrols.menu.hud_enable", (game_options) -> this.mod.config.is_hud_enabled(),
(game_options, new_value) -> this.mod.config.set_hud_enabled(new_value));
this.hud_side_option = new CyclingOption("lambdacontrols.menu.hud_side",
(game_options, option) -> option.getDisplayPrefix() + this.mod.config.get_controller_type().get_translated_name(),
new TranslatableText("lambdacontrols.tooltip.controller_type"));
this.hud_enable_option = new SpruceBooleanOption("lambdacontrols.menu.hud_enable", (game_options) -> this.mod.config.is_hud_enabled(),
(game_options, new_value) -> this.mod.config.set_hud_enabled(new_value), new TranslatableText("lambdacontrols.tooltip.hud_enable"));
this.hud_side_option = new SpruceCyclingOption("lambdacontrols.menu.hud_side",
(game_options, amount) -> this.mod.config.set_hud_side(this.mod.config.get_hud_side().next()),
(game_options, option) -> option.getDisplayPrefix() + this.mod.config.get_hud_side().get_translated_name());
this.dead_zone_option = new DoubleOption("lambdacontrols.menu.dead_zone", 0.05, 1.0, 0.05F, game_options -> this.mod.config.get_dead_zone(),
(game_options, option) -> option.getDisplayPrefix() + this.mod.config.get_hud_side().get_translated_name(),
new TranslatableText("lambdacontrols.tooltip.hud_side"));
this.dead_zone_option = new SpruceDoubleOption("lambdacontrols.menu.dead_zone", 0.05, 1.0, 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);
@@ -84,19 +112,26 @@ public class LambdaControlsSettingsScreen extends Screen
}, (game_options, option) -> {
String value = String.valueOf(option.get(options));
return option.getDisplayPrefix() + value.substring(0, Math.min(value.length(), 5));
});
this.rotation_speed_option = new DoubleOption("lambdacontrols.menu.rotation_speed", 0.0, 50.0, 0.5F, game_options -> this.mod.config.get_rotation_speed(),
}, new TranslatableText("lambdacontrols.tooltip.dead_zone"));
this.rotation_speed_option = new SpruceDoubleOption("lambdacontrols.menu.rotation_speed", 0.0, 50.0, 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));
this.mouse_speed_option = new DoubleOption("lambdacontrols.menu.mouse_speed", 0.0, 50.0, 0.5F, game_options -> this.mod.config.get_mouse_speed(),
}, (game_options, option) -> option.getDisplayPrefix() + option.get(options),
new TranslatableText("lambdacontrols.tooltip.rotation_speed"));
this.mouse_speed_option = new SpruceDoubleOption("lambdacontrols.menu.mouse_speed", 0.0, 50.0, 0.5F, game_options -> this.mod.config.get_mouse_speed(),
(game_options, new_value) -> {
synchronized (this.mod.config) {
this.mod.config.set_mouse_speed(new_value);
}
}, (game_options, option) -> option.getDisplayPrefix() + option.get(options));
}, (game_options, option) -> option.getDisplayPrefix() + option.get(options),
new TranslatableText("lambdacontrols.tooltip.mouse_speed"));
this.reset_option = new SpruceResetOption(btn -> {
this.mod.config.reset();
MinecraftClient client = MinecraftClient.getInstance();
this.init(client, client.getWindow().getScaledWidth(), client.getWindow().getScaledHeight());
});
}
@Override
@@ -123,36 +158,45 @@ public class LambdaControlsSettingsScreen extends Screen
{
super.init();
int button_height = 20;
this.addButton(new ButtonWidget(this.width / 2 - 155, 18, 150, button_height, I18n.translate("lambdacontrols.menu.controls_mode") + ": " + this.mod.config.get_controls_mode().get_translated_name(),
SpruceButtonWidget controls_mode_btn = new SpruceButtonWidget(this.width / 2 - 155, 18, this.hide_controls ? 310 : 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, 18, 150, button_height, I18n.translate("options.controls"),
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));
}));
});
controls_mode_btn.set_tooltip(new TranslatableText("lambdacontrols.tooltip.controls_mode"));
this.addButton(controls_mode_btn);
if (!this.hide_controls)
this.addButton(new ButtonWidget(this.width / 2 - 155 + 160, 18, 150, button_height, I18n.translate("options.controls"),
btn -> {
if (this.mod.config.get_controls_mode() == ControlsMode.CONTROLLER)
this.minecraft.openScreen(new LambdaControlsControlsScreen(this, true));
else
this.minecraft.openScreen(new ControlsOptionsScreen(this, this.minecraft.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.addSingleOptionEntry(new SpruceSeparatorOption("lambdacontrols.menu.title.general", true, null));
this.list.addOptionEntry(this.rotation_speed_option, this.mouse_speed_option);
this.list.addSingleOptionEntry(this.auto_switch_mode_option);
this.list.addSingleOptionEntry(new SpruceSeparatorOption("lambdacontrols.menu.title.controller", true, null));
this.list.addSingleOptionEntry(this.controller_option);
this.list.addSingleOptionEntry(this.second_controller_option);
this.list.addOptionEntry(this.controller_type_option, this.dead_zone_option);
this.list.addSingleOptionEntry(new ReloadControllerMappingsOption());
this.list.addSingleOptionEntry(new SpruceSeparatorOption("lambdacontrols.menu.title.hud", true, null));
this.list.addOptionEntry(this.hud_enable_option, this.hud_side_option);
this.children.add(this.list);
this.gamepad_tool_url_label = new LabelWidget(this.width / 2, this.height - 29 - (5 + this.font.fontHeight) * 2, this.controller_mappings_url_text, this.width,
this.gamepad_tool_url_label = new SpruceLabelWidget(this.width / 2, this.height - 29 - (5 + this.font.fontHeight) * 2, this.controller_mappings_url_text, this.width,
label -> Util.getOperatingSystem().open(GAMEPAD_TOOL_URL), true);
this.gamepad_tool_url_label.set_tooltip_text(I18n.translate("chat.link.open"));
this.gamepad_tool_url_label.set_tooltip(new TranslatableText("chat.link.open"));
this.children.add(this.gamepad_tool_url_label);
this.addButton(new ButtonWidget(this.width / 2 - 155, this.height - 29, 300, button_height, I18n.translate("gui.done"),
this.addButton(this.reset_option.createButton(this.minecraft.options, this.width / 2 - 155, this.height - 29, 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)));
}
@@ -166,5 +210,7 @@ public class LambdaControlsSettingsScreen extends Screen
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.gamepad_tool_url_label.render(mouse_x, mouse_y, delta);
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);
Tooltip.render_all();
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
@@ -9,10 +9,10 @@
package me.lambdaurora.lambdacontrols.gui;
import me.lambdaurora.lambdacontrols.Controller;
import me.lambdaurora.lambdacontrols.controller.Controller;
import me.lambdaurora.spruceui.SpruceButtonWidget;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.widget.AbstractButtonWidget;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.options.GameOptions;
import net.minecraft.client.options.Option;
import net.minecraft.client.resource.language.I18n;
@@ -36,13 +36,15 @@ public class ReloadControllerMappingsOption extends Option implements Nameable
@Override
public AbstractButtonWidget createButton(GameOptions options, int x, int y, int width)
{
return new ButtonWidget(x, y, width, 20, this.get_name(), btn -> {
SpruceButtonWidget button = new SpruceButtonWidget(x, y, width, 20, this.get_name(), btn -> {
MinecraftClient client = MinecraftClient.getInstance();
Controller.update_mappings();
if (client.currentScreen != null)
client.currentScreen.init(client, client.getWindow().getScaledWidth(), client.getWindow().getScaledHeight());
client.getToastManager().add(new SystemToast(SystemToast.Type.TUTORIAL_HINT, new TranslatableText("lambdacontrols.controller.mappings.updated"), null));
});
button.set_tooltip(new TranslatableText("lambdacontrols.tooltip.reload_controller_mappings"));
return button;
}
@Override

View File

@@ -1,62 +0,0 @@
/*
* 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 net.minecraft.client.gui.widget.TexturedButtonWidget;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
/**
* Represents a touchscreen button widget.
*/
public class TouchscreenButtonWidget extends TexturedButtonWidget
{
private final Consumer<Boolean> on_change_state;
public TouchscreenButtonWidget(int x, int y, int width, int height, int u, int v, int hovered_v_offset, Identifier texture, @NotNull Consumer<Boolean> on_changed_state)
{
super(x, y, width, height, u, v, hovered_v_offset, texture, 256, 256, btn -> on_changed_state.accept(true));
this.on_change_state = on_changed_state;
}
@Override
public void onRelease(double mouseX, double mouseY)
{
super.onRelease(mouseX, mouseY);
this.on_change_state.accept(false);
}
@Override
public boolean mouseClicked(double mouseX, double mouseY, int button)
{
if (this.active && this.visible) {
if (this.isValidClickButton(button)) {
boolean clicked = this.clicked(mouseX, mouseY);
if (clicked) {
this.onClick(mouseX, mouseY);
return true;
}
}
return false;
} else
return false;
}
@Override
protected void onDrag(double mouseX, double mouseY, double deltaX, double deltaY)
{
super.onDrag(mouseX, mouseY, deltaX, deltaY);
if (this.active && !this.isHovered)
this.on_change_state.accept(false);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
@@ -12,6 +12,7 @@ package me.lambdaurora.lambdacontrols.gui;
import me.lambdaurora.lambdacontrols.HudSide;
import me.lambdaurora.lambdacontrols.LambdaControls;
import me.lambdaurora.lambdacontrols.util.KeyBindingAccessor;
import me.lambdaurora.spruceui.SpruceTexturedButtonWidget;
import net.minecraft.client.gui.screen.ChatScreen;
import net.minecraft.client.gui.screen.GameMenuScreen;
import net.minecraft.client.gui.screen.Screen;
@@ -35,18 +36,18 @@ import static org.lwjgl.glfw.GLFW.GLFW_GAMEPAD_AXIS_RIGHT_Y;
*/
public class TouchscreenOverlay extends Screen
{
public static final Identifier WIDGETS_LOCATION = new Identifier("lambdacontrols", "textures/gui/widgets.png");
private LambdaControls mod;
private TouchscreenButtonWidget jump_button;
private TouchscreenButtonWidget fly_button;
private TouchscreenButtonWidget fly_up_button;
private TouchscreenButtonWidget fly_down_button;
private int fly_button_enable_ticks = 0;
private int forward_button_tick = 0;
private TouchscreenButtonWidget forward_left_button;
private TouchscreenButtonWidget forward_right_button;
private TouchscreenButtonWidget start_sneak_button;
private TouchscreenButtonWidget end_sneak_button;
public static final Identifier WIDGETS_LOCATION = new Identifier("lambdacontrols", "textures/gui/widgets.png");
private LambdaControls mod;
private SpruceTexturedButtonWidget jump_button;
private SpruceTexturedButtonWidget fly_button;
private SpruceTexturedButtonWidget fly_up_button;
private SpruceTexturedButtonWidget fly_down_button;
private int fly_button_enable_ticks = 0;
private int forward_button_tick = 0;
private SpruceTexturedButtonWidget forward_left_button;
private SpruceTexturedButtonWidget forward_right_button;
private SpruceTexturedButtonWidget start_sneak_button;
private SpruceTexturedButtonWidget end_sneak_button;
public TouchscreenOverlay(@NotNull LambdaControls mod)
{
@@ -108,7 +109,7 @@ public class TouchscreenOverlay extends Screen
this.fly_down_button.visible = true;
if (old_state_fly != this.fly_button.visible) {
this.fly_button_enable_ticks = 5;
this.handle_jump(false);
this.handle_jump(null, false);
} else if (this.fly_button_enable_ticks > 0)
this.fly_button_enable_ticks--;
} else {
@@ -122,9 +123,10 @@ public class TouchscreenOverlay extends Screen
/**
* Handles the jump button.
*
* @param btn The pressed button.
* @param state The state of the jump button.
*/
private void handle_jump(boolean state)
private void handle_jump(ButtonWidget btn, boolean state)
{
((KeyBindingAccessor) this.minecraft.options.keyJump).handle_press_state(state);
}
@@ -182,8 +184,8 @@ public class TouchscreenOverlay extends Screen
sneak_button_x = scaled_width - 10 - 40 - 5;
}
// Swap items hand.
this.addButton(new TouchscreenButtonWidget(swap_hands_x, sneak_button_y, 20, 20, 0, 160, 20, WIDGETS_LOCATION,
state -> {
this.addButton(new SpruceTexturedButtonWidget(swap_hands_x, sneak_button_y, 20, 20, 0, 160, 20, WIDGETS_LOCATION,
(btn, state) -> {
if (state) {
if (!this.minecraft.player.isSpectator()) {
this.minecraft.getNetworkHandler().sendPacket(new PlayerActionC2SPacket(PlayerActionC2SPacket.Action.SWAP_HELD_ITEMS, BlockPos.ORIGIN, Direction.DOWN));
@@ -191,31 +193,31 @@ public class TouchscreenOverlay extends Screen
}
}));
// Drop
this.addButton(new TouchscreenButtonWidget(swap_hands_x, sneak_button_y + 5 + 20, 20, 20, 20, 160, 20, WIDGETS_LOCATION,
state -> ((KeyBindingAccessor) this.minecraft.options.keyDrop).handle_press_state(state)));
this.addButton(new SpruceTexturedButtonWidget(swap_hands_x, sneak_button_y + 5 + 20, 20, 20, 20, 160, 20, WIDGETS_LOCATION,
(btn, state) -> ((KeyBindingAccessor) this.minecraft.options.keyDrop).handle_press_state(state)));
// Jump keys
this.addButton(this.jump_button = new TouchscreenButtonWidget(jump_button_x, sneak_button_y, 20, 20, 0, 40, 20, WIDGETS_LOCATION,
this.addButton(this.jump_button = new SpruceTexturedButtonWidget(jump_button_x, sneak_button_y, 20, 20, 0, 40, 20, WIDGETS_LOCATION,
this::handle_jump));
this.addButton(this.fly_button = new TouchscreenButtonWidget(jump_button_x, sneak_button_y, 20, 20, 20, 40, 20, WIDGETS_LOCATION,
state -> {
this.addButton(this.fly_button = new SpruceTexturedButtonWidget(jump_button_x, sneak_button_y, 20, 20, 20, 40, 20, WIDGETS_LOCATION,
(btn, state) -> {
if (this.fly_button_enable_ticks == 0) this.minecraft.player.abilities.flying = false;
}));
this.addButton(this.fly_up_button = new TouchscreenButtonWidget(jump_button_x, sneak_button_y - 5 - 20, 20, 20, 40, 40, 20, WIDGETS_LOCATION,
this.addButton(this.fly_up_button = new SpruceTexturedButtonWidget(jump_button_x, sneak_button_y - 5 - 20, 20, 20, 40, 40, 20, WIDGETS_LOCATION,
this::handle_jump));
this.addButton(this.fly_down_button = new TouchscreenButtonWidget(jump_button_x, sneak_button_y + 20 + 5, 20, 20, 60, 40, 20, WIDGETS_LOCATION,
state -> ((KeyBindingAccessor) this.minecraft.options.keySneak).handle_press_state(state)));
this.addButton(this.fly_down_button = new SpruceTexturedButtonWidget(jump_button_x, sneak_button_y + 20 + 5, 20, 20, 60, 40, 20, WIDGETS_LOCATION,
(btn, state) -> ((KeyBindingAccessor) this.minecraft.options.keySneak).handle_press_state(state)));
this.update_jump_buttons();
// Movements keys
this.addButton((this.start_sneak_button = new TouchscreenButtonWidget(sneak_button_x, sneak_button_y, 20, 20, 0, 120, 20, WIDGETS_LOCATION,
state -> {
this.addButton((this.start_sneak_button = new SpruceTexturedButtonWidget(sneak_button_x, sneak_button_y, 20, 20, 0, 120, 20, WIDGETS_LOCATION,
(btn, state) -> {
if (state) {
((KeyBindingAccessor) this.minecraft.options.keySneak).handle_press_state(true);
this.start_sneak_button.visible = false;
this.end_sneak_button.visible = true;
}
})));
this.addButton((this.end_sneak_button = new TouchscreenButtonWidget(sneak_button_x, sneak_button_y, 20, 20, 20, 120, 20, WIDGETS_LOCATION,
state -> {
this.addButton((this.end_sneak_button = new SpruceTexturedButtonWidget(sneak_button_x, sneak_button_y, 20, 20, 20, 120, 20, WIDGETS_LOCATION,
(btn, state) -> {
if (state) {
((KeyBindingAccessor) this.minecraft.options.keySneak).handle_press_state(false);
this.end_sneak_button.visible = false;
@@ -223,33 +225,33 @@ public class TouchscreenOverlay extends Screen
}
})));
this.end_sneak_button.visible = false;
this.addButton(this.forward_left_button = new TouchscreenButtonWidget(sneak_button_x - 20 - 5, sneak_button_y - 5 - 20, 20, 20, 80, 80, 20, WIDGETS_LOCATION,
state -> {
this.addButton(this.forward_left_button = new SpruceTexturedButtonWidget(sneak_button_x - 20 - 5, sneak_button_y - 5 - 20, 20, 20, 80, 80, 20, WIDGETS_LOCATION,
(btn, state) -> {
((KeyBindingAccessor) this.minecraft.options.keyForward).handle_press_state(state);
((KeyBindingAccessor) this.minecraft.options.keyLeft).handle_press_state(state);
this.update_forward_buttons_state(state);
}));
this.forward_left_button.visible = false;
this.addButton(new TouchscreenButtonWidget(sneak_button_x, sneak_button_y - 5 - 20, 20, 20, 0, 80, 20, WIDGETS_LOCATION,
state -> {
this.addButton(new SpruceTexturedButtonWidget(sneak_button_x, sneak_button_y - 5 - 20, 20, 20, 0, 80, 20, WIDGETS_LOCATION,
(btn, state) -> {
((KeyBindingAccessor) this.minecraft.options.keyForward).handle_press_state(state);
this.update_forward_buttons_state(state);
this.forward_left_button.visible = true;
this.forward_right_button.visible = true;
}));
this.addButton(this.forward_right_button = new TouchscreenButtonWidget(sneak_button_x + 20 + 5, sneak_button_y - 5 - 20, 20, 20, 100, 80, 20, WIDGETS_LOCATION,
state -> {
this.addButton(this.forward_right_button = new SpruceTexturedButtonWidget(sneak_button_x + 20 + 5, sneak_button_y - 5 - 20, 20, 20, 100, 80, 20, WIDGETS_LOCATION,
(btn, state) -> {
((KeyBindingAccessor) this.minecraft.options.keyForward).handle_press_state(state);
((KeyBindingAccessor) this.minecraft.options.keyRight).handle_press_state(state);
this.update_forward_buttons_state(state);
}));
this.forward_right_button.visible = true;
this.addButton(new TouchscreenButtonWidget(sneak_button_x + 20 + 5, sneak_button_y, 20, 20, 20, 80, 20, WIDGETS_LOCATION,
state -> ((KeyBindingAccessor) this.minecraft.options.keyRight).handle_press_state(state)));
this.addButton(new TouchscreenButtonWidget(sneak_button_x, sneak_button_y + 20 + 5, 20, 20, 40, 80, 20, WIDGETS_LOCATION,
state -> ((KeyBindingAccessor) this.minecraft.options.keyBack).handle_press_state(state)));
this.addButton(new TouchscreenButtonWidget(sneak_button_x - 20 - 5, sneak_button_y, 20, 20, 60, 80, 20, WIDGETS_LOCATION,
state -> ((KeyBindingAccessor) this.minecraft.options.keyLeft).handle_press_state(state)));
this.addButton(new SpruceTexturedButtonWidget(sneak_button_x + 20 + 5, sneak_button_y, 20, 20, 20, 80, 20, WIDGETS_LOCATION,
(btn, state) -> ((KeyBindingAccessor) this.minecraft.options.keyRight).handle_press_state(state)));
this.addButton(new SpruceTexturedButtonWidget(sneak_button_x, sneak_button_y + 20 + 5, 20, 20, 40, 80, 20, WIDGETS_LOCATION,
(btn, state) -> ((KeyBindingAccessor) this.minecraft.options.keyBack).handle_press_state(state)));
this.addButton(new SpruceTexturedButtonWidget(sneak_button_x - 20 - 5, sneak_button_y, 20, 20, 60, 80, 20, WIDGETS_LOCATION,
(btn, state) -> ((KeyBindingAccessor) this.minecraft.options.keyLeft).handle_press_state(state)));
}
@Override

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
@@ -60,10 +60,10 @@ public abstract class AbstractContainerScreenMixin implements AbstractContainerS
MinecraftClient client = MinecraftClient.getInstance();
int x = 10, y = client.getWindow().getScaledHeight() - 10 - 15;
x += LambdaControls.draw_button_tip(x, y, GLFW.GLFW_GAMEPAD_BUTTON_A, "lambdacontrols.action.pickup_all", true, client) + 10;
x += LambdaControls.draw_button_tip(x, y, GLFW.GLFW_GAMEPAD_BUTTON_B, "lambdacontrols.action.exit", true, client) + 10;
x += LambdaControls.draw_button_tip(x, y, GLFW.GLFW_GAMEPAD_BUTTON_X, "lambdacontrols.action.pickup", true, client) + 10;
LambdaControls.draw_button_tip(x, y, GLFW.GLFW_GAMEPAD_BUTTON_Y, "lambdacontrols.action.quick_move", true, client);
x += LambdaControls.draw_button_tip(x, y, new int[]{GLFW.GLFW_GAMEPAD_BUTTON_A}, "lambdacontrols.action.pickup_all", true, client) + 10;
x += LambdaControls.draw_button_tip(x, y, new int[]{GLFW.GLFW_GAMEPAD_BUTTON_B}, "lambdacontrols.action.exit", true, client) + 10;
x += LambdaControls.draw_button_tip(x, y, new int[]{GLFW.GLFW_GAMEPAD_BUTTON_X}, "lambdacontrols.action.pickup", true, client) + 10;
LambdaControls.draw_button_tip(x, y, new int[]{GLFW.GLFW_GAMEPAD_BUTTON_Y}, "lambdacontrols.action.quick_move", true, client);
}
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright © 2020 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.LambdaControlsControlsScreen;
import me.lambdaurora.lambdacontrols.gui.LambdaControlsSettingsScreen;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.options.ControlsOptionsScreen;
import net.minecraft.client.gui.screen.options.GameOptionsScreen;
import net.minecraft.client.gui.widget.AbstractButtonWidget;
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.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
/**
* Injects the new controls settings button.
*/
@Mixin(ControlsOptionsScreen.class)
public class ControlsOptionsScreenMixin extends GameOptionsScreen
{
public ControlsOptionsScreenMixin(Screen parent, GameOptions game_options, Text text)
{
super(parent, game_options, text);
}
@Redirect(method = "init", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/options/ControlsOptionsScreen;addButton(Lnet/minecraft/client/gui/widget/AbstractButtonWidget;)Lnet/minecraft/client/gui/widget/AbstractButtonWidget;", ordinal = 1))
private AbstractButtonWidget on_init(ControlsOptionsScreen screen, AbstractButtonWidget btn)
{
if (this.parent instanceof LambdaControlsControlsScreen)
return this.addButton(btn);
else
return this.addButton(new ButtonWidget(btn.x, btn.y, btn.getWidth(), ((AbstractButtonWidgetAccessor) btn).get_height(), I18n.translate("menu.options"),
b -> this.minecraft.openScreen(new LambdaControlsSettingsScreen(this, this.gameOptions, true))));
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
@@ -9,12 +9,17 @@
package me.lambdaurora.lambdacontrols.mixin;
import me.lambdaurora.lambdacontrols.ControlsMode;
import me.lambdaurora.lambdacontrols.LambdaControls;
import me.lambdaurora.lambdacontrols.gui.LambdaControlsControlsScreen;
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.screen.options.ControlsOptionsScreen;
import net.minecraft.client.gui.widget.AbstractButtonWidget;
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;
@@ -28,10 +33,6 @@ import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(SettingsScreen.class)
public class SettingsScreenMixin extends Screen
{
@Final
@Shadow
private GameOptions settings;
protected SettingsScreenMixin(Text title)
{
super(title);
@@ -40,7 +41,11 @@ public class SettingsScreenMixin extends Screen
@Redirect(method = "init", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/SettingsScreen;addButton(Lnet/minecraft/client/gui/widget/AbstractButtonWidget;)Lnet/minecraft/client/gui/widget/AbstractButtonWidget;", ordinal = 7))
private AbstractButtonWidget on_init(SettingsScreen screen, AbstractButtonWidget btn)
{
return 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))));
if (LambdaControls.get().config.get_controls_mode() == ControlsMode.CONTROLLER) {
return this.addButton(new ButtonWidget(btn.x, btn.y, btn.getWidth(), ((AbstractButtonWidgetAccessor) btn).get_height(), btn.getMessage(),
b -> this.minecraft.openScreen(new LambdaControlsControlsScreen(this, false))));
} else {
return this.addButton(btn);
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
* Copyright © 2020 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*

View File

@@ -10,6 +10,8 @@
"lambdacontrols.action.exit": "Exit",
"lambdacontrols.action.forward": "Forward",
"lambdacontrols.action.hit": "Hit",
"lambdacontrols.action.hotbar_left": "Hotbar left",
"lambdacontrols.action.hotbar_right": "Hotbar right",
"lambdacontrols.action.inventory": "Inventory",
"lambdacontrols.action.jump": "Jump",
"lambdacontrols.action.left": "Left",
@@ -72,6 +74,7 @@
"lambdacontrols.hud_side.right": "right",
"lambdacontrols.menu.auto_switch_mode": "Auto switch mode",
"lambdacontrols.menu.controller": "Controller",
"lambdacontrols.menu.controller2": "Second controller",
"lambdacontrols.menu.controller_type": "Controller type",
"lambdacontrols.menu.controls_mode": "Mode",
"lambdacontrols.menu.dead_zone": "Dead zone",
@@ -79,9 +82,23 @@
"lambdacontrols.menu.hud_side": "HUD side",
"lambdacontrols.menu.invert_right_x_axis": "Invert right X",
"lambdacontrols.menu.invert_right_y_axis": "Invert right Y",
"lambdacontrols.menu.keyboard_controls": "Keyboard controls...",
"lambdacontrols.menu.mouse_speed": "Mouse speed",
"lambdacontrols.menu.reload_controller_mappings": "Reload controller mappings",
"lambdacontrols.menu.rotation_speed": "Rotation speed",
"lambdacontrols.menu.title": "LambdaControls - Settings",
"lambdacontrols.menu.title.controller_controls": "Controller controls"
"lambdacontrols.menu.title.controller": "Controller options",
"lambdacontrols.menu.title.controller_controls": "Controller controls",
"lambdacontrols.menu.title.general": "General options",
"lambdacontrols.menu.title.hud": "HUD options",
"lambdacontrols.tooltip.auto_switch_mode": "Sets whether the controls mode should be switched automatically to Controller if a controller is connected.",
"lambdacontrols.tooltip.controller2": "Defines a second controller to use, which allow Joy-Cons support for example.",
"lambdacontrols.tooltip.controller_type": "Changes the controller type to displays the correct buttons.",
"lambdacontrols.tooltip.controls_mode": "Changes the controls mode.",
"lambdacontrols.tooltip.dead_zone": "Sets the dead zone of the controller's axises.",
"lambdacontrols.tooltip.hud_enable": "Toggles the on-screen controller button indicator.",
"lambdacontrols.tooltip.hud_side": "Changes the position of the HUD.",
"lambdacontrols.tooltip.mouse_speed": "Changes the emulated mouse speed with a controller.",
"lambdacontrols.tooltip.rotation_speed": "Changes the camera rotation speed in controller mode.",
"lambdacontrols.tooltip.reload_controller_mappings": "Reloads the controller mappings file."
}

View File

@@ -0,0 +1,104 @@
{
"key.lambdacontrols.look_down": "Regarder en bas",
"key.lambdacontrols.look_left": "Regarder à gauche",
"key.lambdacontrols.look_right": "Regarder à droite",
"key.lambdacontrols.look_up": "Regarder en haut",
"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.hotbar_left": "Case à gauche de la barre d'action",
"lambdacontrols.action.hotbar_right": "Case à droite de la barre d'action",
"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 gauche",
"lambdacontrols.button.right_thumb": "Stick 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": "(%s%s%s),",
"lambdacontrols.controller.mappings.3": "et mettez les correspondances dans le fichier `%s.minecraft/config/gamecontrollerdb.txt%s`.",
"lambdacontrols.controller.mappings.updated": "Configuration des manettes mise à jour!",
"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.auto_switch_mode": "Changement auto de mode",
"lambdacontrols.menu.controller": "Manette",
"lambdacontrols.menu.controller2": "Deuxième manette",
"lambdacontrols.menu.controller_type": "Type de manette",
"lambdacontrols.menu.controls_mode": "Mode",
"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 stick droit (X)",
"lambdacontrols.menu.invert_right_y_axis": "Inverser le stick droit (Y)",
"lambdacontrols.menu.keyboard_controls": "Contrôles clavier...",
"lambdacontrols.menu.mouse_speed": "Vitesse de la souris",
"lambdacontrols.menu.reload_controller_mappings": "Recharge la configuration des manettes",
"lambdacontrols.menu.rotation_speed": "Vitesse de rotation",
"lambdacontrols.menu.title": "LambdaControls - Paramètres",
"lambdacontrols.menu.title.controller": "Options de manettes",
"lambdacontrols.menu.title.controller_controls": "Contrôles de la manette",
"lambdacontrols.menu.title.general": "Options générales",
"lambdacontrols.menu.title.hud": "Options du HUD",
"lambdacontrols.tooltip.auto_switch_mode": "Détermine si le mode de contrôle doit automatiquement changer sur Manette si une manette est connectée et inversement.",
"lambdacontrols.tooltip.controller2": "Défini une deuxième manette, utile dans le cas d'utilisation de Joy-Cons.",
"lambdacontrols.tooltip.controller_type": "Le type de contrôle n'influe que sur les boutons affichés.",
"lambdacontrols.tooltip.controls_mode": "Change le mode de contrôle.",
"lambdacontrols.tooltip.dead_zone": "Détermine la zone morte des axes de la manette.",
"lambdacontrols.tooltip.hud_enable": "Détermine si l'indicateur des buttons de la manette doit être affiché ou non.",
"lambdacontrols.tooltip.hud_side": "Change la position du HUD.",
"lambdacontrols.tooltip.mouse_speed": "Change la vitesse de la souris émulée par la manette.",
"lambdacontrols.tooltip.rotation_speed": "Change la vitesse de rotation de la caméra.",
"lambdacontrols.tooltip.reload_controller_mappings": "Recharge le fichier de configuration des manettes."
}

View File

@@ -10,6 +10,8 @@
"lambdacontrols.action.exit": "Sortir",
"lambdacontrols.action.forward": "Avancer",
"lambdacontrols.action.hit": "Taper",
"lambdacontrols.action.hotbar_left": "Case à gauche de la barre d'action",
"lambdacontrols.action.hotbar_right": "Case à droite de la barre d'action",
"lambdacontrols.action.inventory": "Inventaire",
"lambdacontrols.action.jump": "Sauter",
"lambdacontrols.action.left": "Aller à gauche",
@@ -36,8 +38,8 @@
"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.left_thumb": "Stick gauche",
"lambdacontrols.button.right_thumb": "Stick droit",
"lambdacontrols.button.dpad_up": "D-Pad haut",
"lambdacontrols.button.dpad_right": "D-Pad droit",
"lambdacontrols.button.dpad_down": "D-Pad bas",
@@ -72,16 +74,31 @@
"lambdacontrols.hud_side.right": "droit",
"lambdacontrols.menu.auto_switch_mode": "Changement auto de mode",
"lambdacontrols.menu.controller": "Manette",
"lambdacontrols.menu.controller2": "Deuxième manette",
"lambdacontrols.menu.controller_type": "Type de manette",
"lambdacontrols.menu.controls_mode": "Mode",
"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.invert_right_x_axis": "Inverser le stick droit (X)",
"lambdacontrols.menu.invert_right_y_axis": "Inverser le stick droit (Y)",
"lambdacontrols.menu.keyboard_controls": "Contrôles clavier...",
"lambdacontrols.menu.mouse_speed": "Vitesse de la souris",
"lambdacontrols.menu.reload_controller_mappings": "Recharge la configuration des manettes",
"lambdacontrols.menu.rotation_speed": "Vitesse de rotation",
"lambdacontrols.menu.title": "LambdaControls - Paramètres",
"lambdacontrols.menu.title.controller_controls": "Contrôles de la manette"
"lambdacontrols.menu.title.controller": "Options de manettes",
"lambdacontrols.menu.title.controller_controls": "Contrôles de la manette",
"lambdacontrols.menu.title.general": "Options générales",
"lambdacontrols.menu.title.hud": "Options du HUD",
"lambdacontrols.tooltip.auto_switch_mode": "Détermine si le mode de contrôle doit automatiquement changer sur Manette si une manette est connectée et inversement.",
"lambdacontrols.tooltip.controller2": "Défini une deuxième manette, utile dans le cas d'utilisation de Joy-Cons.",
"lambdacontrols.tooltip.controller_type": "Le type de contrôle n'influe que sur les boutons affichés.",
"lambdacontrols.tooltip.controls_mode": "Change le mode de contrôle.",
"lambdacontrols.tooltip.dead_zone": "Détermine la zone morte des axes de la manette.",
"lambdacontrols.tooltip.hud_enable": "Détermine si l'indicateur des buttons de la manette doit être affiché ou non.",
"lambdacontrols.tooltip.hud_side": "Change la position du HUD.",
"lambdacontrols.tooltip.mouse_speed": "Change la vitesse de la souris émulée par la manette.",
"lambdacontrols.tooltip.rotation_speed": "Change la vitesse de rotation de la caméra.",
"lambdacontrols.tooltip.reload_controller_mappings": "Recharge le fichier de configuration des manettes."
}

View File

@@ -15,6 +15,8 @@ auto_switch_mode = false
[controller]
# Controller to use.
id = 0
# Second controller to use.
id2 = -1
# Controller's type.
type = "default"
# Controller's dead zone.
@@ -30,36 +32,42 @@ auto_switch_mode = false
# Controller controls.
[controller.controls]
# Attack control.
attack = 105
attack = "105"
# Back control.
back = 201
back = "201"
# Open chat control.
chat = 12
chat = "12"
# Drop item control.
drop_item = 1
drop_item = "1"
# Forward control.
forward = 101
forward = "101"
# Hot-bar left control.
hotbar_left = "4"
# Hot-bar right control.
hotbar_right = "5"
# Inventory control.
inventory = 3
inventory = "3"
# Jump control.
jump = 0
jump = "0"
# Pause game control.
pause_game = 7
pause_game = "7"
# Pick block control.
pick_block = 14
pick_block = "14"
# Show player list control.
player_list = 6
player_list = "6"
# Take screenshot control.
screenshot = 13
screenshot = "11+0"
# Sneak control.
sneak = 10
sneak = "10"
# Sprint control.
sprint = 9
sprint = "9"
# Swap hands control.
swap_hands = 2
swap_hands = "2"
# Toggle perspective control.
toggle_perspective = 11
toggle_perspective = "11+3"
# Toggle smooth camera control.
toggle_smooth_camera = -1
toggle_smooth_camera = "-1"
# Use control.
use = 104
use = "104"
# Zoom control.
zoom = "11+2"

View File

@@ -18,6 +18,9 @@
"entrypoints": {
"client": [
"me.lambdaurora.lambdacontrols.LambdaControls"
],
"modmenu": [
"me.lambdaurora.lambdacontrols.LambdaControlsModMenu"
]
},
"mixins": [
@@ -26,7 +29,11 @@
"depends": {
"fabricloader": ">=0.4.0",
"fabric": "*",
"minecraft": "1.15.x"
"minecraft": "1.15.x",
"spruceui": ">=1.0.1"
},
"recommends": {
"modmenu": ">=1.8.0+build.16"
},
"suggests": {
"flamingo": "*"

View File

@@ -5,10 +5,10 @@
"client": [
"AbstractButtonWidgetAccessor",
"AbstractContainerScreenMixin",
"ControlsOptionsScreenMixin",
"CreativeInventoryScreenMixin",
"EntryListWidgetAccessor",
"GameRendererMixin",
"InGameHudMixin",
"KeyBindingMixin",
"MinecraftClientMixin",
"MouseMixin",
@@ -17,4 +17,4 @@
"injectors": {
"defaultRequire": 1
}
}
}