mirror of
https://github.com/TeamMidnightDust/MidnightControls.git
synced 2025-12-13 07:15:10 +01:00
Add analog movements and WIP action ring.
This commit is contained in:
@@ -61,12 +61,12 @@ public class LambdaControlsConfig
|
||||
protected final FileConfig config = FileConfig.builder("config/lambdacontrols.toml").concurrent().defaultResource("/config.toml").build();
|
||||
private final LambdaControlsClient mod;
|
||||
private ControlsMode controlsMode;
|
||||
private ControllerType controllerType;
|
||||
private ControllerType controllerType;
|
||||
// Gameplay.
|
||||
private boolean shouldRenderReacharoundOutline;
|
||||
private int[] reacharoundOutlineColor;
|
||||
private boolean shouldRenderReacharoundOutline;
|
||||
private int[] reacharoundOutlineColor;
|
||||
// Controller settings
|
||||
private double deadZone;
|
||||
private double deadZone;
|
||||
private double rotationSpeed;
|
||||
private double mouseSpeed;
|
||||
private boolean unfocusedInput;
|
||||
|
||||
@@ -11,7 +11,6 @@ package me.lambdaurora.lambdacontrols.client;
|
||||
|
||||
import io.github.prospector.modmenu.api.ConfigScreenFactory;
|
||||
import io.github.prospector.modmenu.api.ModMenuApi;
|
||||
import me.lambdaurora.lambdacontrols.LambdaControlsConstants;
|
||||
import me.lambdaurora.lambdacontrols.client.gui.LambdaControlsSettingsScreen;
|
||||
|
||||
/**
|
||||
|
||||
@@ -32,6 +32,7 @@ import net.minecraft.client.gui.screen.ingame.CreativeInventoryScreen;
|
||||
import net.minecraft.client.gui.screen.ingame.HandledScreen;
|
||||
import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen;
|
||||
import net.minecraft.client.gui.screen.multiplayer.MultiplayerServerListWidget;
|
||||
import net.minecraft.client.gui.screen.pack.ResourcePackScreen;
|
||||
import net.minecraft.client.gui.screen.world.WorldListWidget;
|
||||
import net.minecraft.client.gui.widget.AbstractPressableButtonWidget;
|
||||
import net.minecraft.client.gui.widget.AlwaysSelectedEntryListWidget;
|
||||
@@ -63,24 +64,25 @@ import static org.lwjgl.glfw.GLFW.*;
|
||||
* Represents the LambdaControls' input handler.
|
||||
*
|
||||
* @author LambdAurora
|
||||
* @version 1.3.2
|
||||
* @version 1.4.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class LambdaInput
|
||||
{
|
||||
private static final Map<Integer, Integer> BUTTON_COOLDOWNS = new HashMap<>();
|
||||
private static final Map<Integer, Integer> BUTTON_COOLDOWNS = new HashMap<>();
|
||||
private final LambdaControlsConfig config;
|
||||
// Cooldowns
|
||||
private int actionGuiCooldown = 0;
|
||||
private boolean ignoreNextARelease = false;
|
||||
private double targetYaw = 0.0;
|
||||
private double targetPitch = 0.0;
|
||||
private float prevXAxis = 0.F;
|
||||
private float prevYAxis = 0.F;
|
||||
private int targetMouseX = 0;
|
||||
private int targetMouseY = 0;
|
||||
private float mouseSpeedX = 0.F;
|
||||
private float mouseSpeedY = 0.F;
|
||||
private int actionGuiCooldown = 0;
|
||||
private boolean ignoreNextARelease = false;
|
||||
private double targetYaw = 0.0;
|
||||
private double targetPitch = 0.0;
|
||||
private float prevXAxis = 0.F;
|
||||
private float prevYAxis = 0.F;
|
||||
private int targetMouseX = 0;
|
||||
private int targetMouseY = 0;
|
||||
private float mouseSpeedX = 0.F;
|
||||
private float mouseSpeedY = 0.F;
|
||||
private int inventoryInteractionCooldown = 0;
|
||||
|
||||
public LambdaInput(@NotNull LambdaControlsClient mod)
|
||||
{
|
||||
@@ -157,6 +159,9 @@ public class LambdaInput
|
||||
screen.focusedBinding = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.inventoryInteractionCooldown > 0)
|
||||
this.inventoryInteractionCooldown--;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -214,6 +219,7 @@ public class LambdaInput
|
||||
((MouseAccessor) client.mouse).lambdacontrols_onCursorPos(client.getWindow().getHandle(), 0, 0);
|
||||
INPUT_MANAGER.resetMouseTarget(client);
|
||||
}
|
||||
this.inventoryInteractionCooldown = 5;
|
||||
}
|
||||
|
||||
private void fetchButtonInput(@NotNull MinecraftClient client, @NotNull GLFWGamepadState gamepadState, boolean leftJoycon)
|
||||
@@ -329,9 +335,11 @@ public class LambdaInput
|
||||
double mouseX = client.mouse.getX() * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth();
|
||||
double mouseY = client.mouse.getY() * (double) client.getWindow().getScaledHeight() / (double) client.getWindow().getHeight();
|
||||
if (action == 0) {
|
||||
client.currentScreen.mouseClicked(mouseX, mouseY, GLFW.GLFW_MOUSE_BUTTON_1);
|
||||
Screen.wrapScreenError(() -> client.currentScreen.mouseClicked(mouseX, mouseY, GLFW.GLFW_MOUSE_BUTTON_1),
|
||||
"mouseClicked event handler", client.currentScreen.getClass().getCanonicalName());
|
||||
} else if (action == 1) {
|
||||
client.currentScreen.mouseReleased(mouseX, mouseY, GLFW.GLFW_MOUSE_BUTTON_1);
|
||||
Screen.wrapScreenError(() -> client.currentScreen.mouseReleased(mouseX, mouseY, GLFW.GLFW_MOUSE_BUTTON_1),
|
||||
"mouseReleased event handler", client.currentScreen.getClass().getCanonicalName());
|
||||
}
|
||||
this.actionGuiCooldown = 5;
|
||||
} else {
|
||||
@@ -355,6 +363,9 @@ public class LambdaInput
|
||||
if (client.interactionManager == null || client.player == null)
|
||||
return false;
|
||||
|
||||
if (this.inventoryInteractionCooldown > 0)
|
||||
return true;
|
||||
|
||||
if (button == GLFW.GLFW_GAMEPAD_BUTTON_B) {
|
||||
client.player.closeHandledScreen();
|
||||
return true;
|
||||
@@ -457,6 +468,17 @@ public class LambdaInput
|
||||
BUTTON_COOLDOWNS.put(axisAsButton(axis, false), 5);
|
||||
}
|
||||
}
|
||||
|
||||
float axisValue = absValue < this.config.getDeadZone() ? 0.f : (float) (absValue - this.config.getDeadZone());
|
||||
axisValue /= (1.0 - this.config.getDeadZone());
|
||||
if (currentPlusState)
|
||||
InputManager.BUTTON_VALUES.put(axisAsButton(axis, true), axisValue);
|
||||
else
|
||||
InputManager.BUTTON_VALUES.put(axisAsButton(axis, true), 0.f);
|
||||
if (currentMinusState)
|
||||
InputManager.BUTTON_VALUES.put(axisAsButton(axis, false), axisValue);
|
||||
else
|
||||
InputManager.BUTTON_VALUES.put(axisAsButton(axis, false), 0.f);
|
||||
}
|
||||
|
||||
double deadZone = this.config.getDeadZone();
|
||||
@@ -481,6 +503,7 @@ public class LambdaInput
|
||||
if (axis == GLFW_GAMEPAD_AXIS_RIGHT_Y) {
|
||||
CreativeInventoryScreen screen = (CreativeInventoryScreen) client.currentScreen;
|
||||
CreativeInventoryScreenAccessor accessor = (CreativeInventoryScreenAccessor) screen;
|
||||
// @TODO allow rebinding to left stick
|
||||
if (accessor.lambdacontrols_hasScrollbar() && absValue >= deadZone) {
|
||||
screen.mouseScrolled(0.0, 0.0, -value);
|
||||
}
|
||||
@@ -677,7 +700,7 @@ public class LambdaInput
|
||||
|
||||
public static boolean isScreenInteractive(@NotNull Screen screen)
|
||||
{
|
||||
return !(screen instanceof AdvancementsScreen || screen instanceof HandledScreen || LambdaControlsCompat.requireMouseOnScreen(screen));
|
||||
return !(screen instanceof AdvancementsScreen || screen instanceof HandledScreen || screen instanceof ResourcePackScreen || LambdaControlsCompat.requireMouseOnScreen(screen));
|
||||
}
|
||||
|
||||
// Inspired from https://github.com/MrCrayfish/Controllable/blob/1.14.X/src/main/java/com/mrcrayfish/controllable/client/ControllerInput.java#L686.
|
||||
|
||||
@@ -31,7 +31,8 @@ public enum VirtualMouseSkin implements Nameable
|
||||
|
||||
private String name;
|
||||
|
||||
VirtualMouseSkin(String name) {
|
||||
VirtualMouseSkin(String name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.screen.ingame.HandledScreen;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.screen.slot.Slot;
|
||||
import net.minecraft.util.hit.BlockHitResult;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -18,7 +18,7 @@ import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Represents HQM compatibility handler.
|
||||
*
|
||||
* <p>
|
||||
* This is bad.
|
||||
*
|
||||
* @author LambdAurora
|
||||
@@ -27,8 +27,8 @@ import java.util.Optional;
|
||||
*/
|
||||
public class HQMCompat implements CompatHandler
|
||||
{
|
||||
public static final String GUI_BASE_CLASS_PATH = "hardcorequesting.client.interfaces.GuiBase";
|
||||
private Optional<Class<?>> guiBaseClass;
|
||||
public static final String GUI_BASE_CLASS_PATH = "hardcorequesting.client.interfaces.GuiBase";
|
||||
private Optional<Class<?>> guiBaseClass;
|
||||
|
||||
@Override
|
||||
public void handle(@NotNull LambdaControlsClient mod)
|
||||
|
||||
@@ -14,7 +14,6 @@ import me.lambdaurora.lambdacontrols.client.controller.InputManager;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.util.hit.BlockHitResult;
|
||||
import org.aperlambda.lambdacommon.utils.LambdaReflection;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -132,7 +131,8 @@ public class LambdaControlsCompat
|
||||
* @param screen The screen.
|
||||
* @return True if the handle was fired and succeed, else false.
|
||||
*/
|
||||
public static boolean handleMenuBack(@NotNull MinecraftClient client, @NotNull Screen screen) {
|
||||
public static boolean handleMenuBack(@NotNull MinecraftClient client, @NotNull Screen screen)
|
||||
{
|
||||
for (CompatHandler handler : HANDLERS) {
|
||||
if (handler.handleMenuBack(client, screen))
|
||||
return true;
|
||||
|
||||
@@ -36,5 +36,7 @@ public class OkZoomerCompat implements CompatHandler
|
||||
.category(ButtonBinding.MISC_CATEGORY)
|
||||
.linkKeybind(OkZoomerClientMod.zoomKeyBinding)
|
||||
.register();
|
||||
|
||||
// @TODO Zoom in and out
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ import static org.lwjgl.glfw.GLFW.*;
|
||||
* Represents a compatibility handler for REI.
|
||||
*
|
||||
* @author LambdAurora
|
||||
* @version 1.3.2
|
||||
* @version 1.4.0
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public class ReiCompat implements CompatHandler
|
||||
@@ -79,7 +79,7 @@ public class ReiCompat implements CompatHandler
|
||||
InputManager.registerBinding(new ButtonBinding.Builder(new Identifier("rei", "show_usage"))
|
||||
.buttons(GLFW_GAMEPAD_BUTTON_RIGHT_THUMB)
|
||||
.filter((client, binding) -> InputHandlers.inInventory(client, binding) || isViewingScreen(client.currentScreen))
|
||||
.action((client, button, action) -> {
|
||||
.action((client, button, value, action) -> {
|
||||
if (action != ButtonState.RELEASE)
|
||||
return false;
|
||||
Optional<ContainerScreenOverlay> overlay = ScreenHelper.getOptionalOverlay();
|
||||
@@ -130,7 +130,7 @@ public class ReiCompat implements CompatHandler
|
||||
|
||||
private static PressAction handlePage(boolean next)
|
||||
{
|
||||
return (client, button, action) -> {
|
||||
return (client, button, value, action) -> {
|
||||
if (action == ButtonState.RELEASE)
|
||||
return false;
|
||||
|
||||
@@ -160,7 +160,7 @@ public class ReiCompat implements CompatHandler
|
||||
*/
|
||||
private static PressAction handleTab(boolean next)
|
||||
{
|
||||
return (client, button, action) -> {
|
||||
return (client, button, value, action) -> {
|
||||
if (action != ButtonState.RELEASE)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ import me.lambdaurora.lambdacontrols.client.ButtonState;
|
||||
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.text.Text;
|
||||
import net.minecraft.text.TranslatableText;
|
||||
import org.aperlambda.lambdacommon.Identifier;
|
||||
@@ -33,7 +32,7 @@ import static org.lwjgl.glfw.GLFW.*;
|
||||
* Represents a button binding.
|
||||
*
|
||||
* @author LambdAurora
|
||||
* @version 1.3.0
|
||||
* @version 1.4.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class ButtonBinding implements Nameable
|
||||
@@ -45,21 +44,25 @@ public class ButtonBinding implements Nameable
|
||||
public static final ButtonCategory MISC_CATEGORY;
|
||||
|
||||
public static final ButtonBinding ATTACK = new Builder("attack").buttons(axisAsButton(GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER, true)).onlyInGame().register();
|
||||
public static final ButtonBinding BACK = new Builder("back").buttons(axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_Y, false)).onlyInGame().register();
|
||||
public static final ButtonBinding BACK = new Builder("back").buttons(axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_Y, false))
|
||||
.action(MovementHandler.HANDLER).onlyInGame().register();
|
||||
public static final ButtonBinding CHAT = new Builder("chat").buttons(GLFW_GAMEPAD_BUTTON_DPAD_RIGHT).onlyInGame().cooldown(true).register();
|
||||
public static final ButtonBinding DROP_ITEM = new Builder("drop_item").buttons(GLFW_GAMEPAD_BUTTON_B).onlyInGame().cooldown(true).register();
|
||||
public static final ButtonBinding FORWARD = new Builder("forward").buttons(axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_Y, true)).onlyInGame().register();
|
||||
public static final ButtonBinding FORWARD = new Builder("forward").buttons(axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_Y, true))
|
||||
.action(MovementHandler.HANDLER).onlyInGame().register();
|
||||
public static final ButtonBinding HOTBAR_LEFT = new Builder("hotbar_left").buttons(GLFW_GAMEPAD_BUTTON_LEFT_BUMPER)
|
||||
.action(InputHandlers.handleHotbar(false)).onlyInGame().cooldown(true).register();
|
||||
public static final ButtonBinding HOTBAR_RIGHT = new Builder("hotbar_right").buttons(GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER)
|
||||
.action(InputHandlers.handleHotbar(true)).onlyInGame().cooldown(true).register();
|
||||
public static final ButtonBinding INVENTORY = new Builder("inventory").buttons(GLFW_GAMEPAD_BUTTON_Y).onlyInGame().cooldown(true).register();
|
||||
public static final ButtonBinding JUMP = new Builder("jump").buttons(GLFW_GAMEPAD_BUTTON_A).onlyInGame().register();
|
||||
public static final ButtonBinding LEFT = new Builder("left").buttons(axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_X, false)).onlyInGame().register();
|
||||
public static final ButtonBinding LEFT = new Builder("left").buttons(axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_X, false))
|
||||
.action(MovementHandler.HANDLER).onlyInGame().register();
|
||||
public static final ButtonBinding PAUSE_GAME = new Builder("pause_game").buttons(GLFW_GAMEPAD_BUTTON_START).action(InputHandlers::handlePauseGame).cooldown(true).register();
|
||||
public static final ButtonBinding PICK_BLOCK = new Builder("pick_block").buttons(GLFW_GAMEPAD_BUTTON_DPAD_LEFT).onlyInGame().cooldown(true).register();
|
||||
public static final ButtonBinding PLAYER_LIST = new Builder("player_list").buttons(GLFW_GAMEPAD_BUTTON_BACK).onlyInGame().register();
|
||||
public static final ButtonBinding RIGHT = new Builder("right").buttons(axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_X, true)).register();
|
||||
public static final ButtonBinding RIGHT = new Builder("right").buttons(axisAsButton(GLFW_GAMEPAD_AXIS_LEFT_X, true))
|
||||
.action(MovementHandler.HANDLER).register();
|
||||
public static final ButtonBinding SCREENSHOT = new Builder("screenshot").buttons(GLFW_GAMEPAD_BUTTON_DPAD_UP, GLFW_GAMEPAD_BUTTON_A)
|
||||
.action(InputHandlers::handleScreenshot).cooldown(true).register();
|
||||
public static final ButtonBinding SLOT_DOWN = new Builder("slot_down").buttons(GLFW_GAMEPAD_BUTTON_DPAD_DOWN)
|
||||
@@ -229,7 +232,7 @@ public class ButtonBinding implements Nameable
|
||||
* @param client The client instance.
|
||||
* @param state The state.
|
||||
*/
|
||||
public void handle(@NotNull MinecraftClient client, @NotNull ButtonState state)
|
||||
public void handle(@NotNull MinecraftClient client, float value, @NotNull ButtonState state)
|
||||
{
|
||||
if (state == ButtonState.REPEAT && this.hasCooldown && this.cooldown != 0)
|
||||
return;
|
||||
@@ -238,7 +241,7 @@ public class ButtonBinding implements Nameable
|
||||
|
||||
}
|
||||
for (int i = this.actions.size() - 1; i >= 0; i--) {
|
||||
if (this.actions.get(i).press(client, this, state))
|
||||
if (this.actions.get(i).press(client, this, value, state))
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -254,8 +257,7 @@ public class ButtonBinding implements Nameable
|
||||
*
|
||||
* @return The translation key.
|
||||
*/
|
||||
public @NotNull
|
||||
String getTranslationKey()
|
||||
public @NotNull String getTranslationKey()
|
||||
{
|
||||
return "lambdacontrols.action." + this.getName();
|
||||
}
|
||||
@@ -283,6 +285,18 @@ public class ButtonBinding implements Nameable
|
||||
return positive ? 100 + axis : 200 + axis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the specified button is an axis or not.
|
||||
*
|
||||
* @param button The button.
|
||||
* @return True if the button is an axis, else false.
|
||||
*/
|
||||
public static boolean isAxis(int button)
|
||||
{
|
||||
button %= 500;
|
||||
return button >= 100;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the second Joycon's specified button code.
|
||||
*
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
package me.lambdaurora.lambdacontrols.client.controller;
|
||||
|
||||
import me.lambdaurora.lambdacontrols.client.ButtonState;
|
||||
import me.lambdaurora.lambdacontrols.client.LambdaInput;
|
||||
import me.lambdaurora.lambdacontrols.client.mixin.AdvancementsScreenAccessor;
|
||||
import me.lambdaurora.lambdacontrols.client.mixin.CreativeInventoryScreenAccessor;
|
||||
import me.lambdaurora.lambdacontrols.client.mixin.RecipeBookWidgetAccessor;
|
||||
@@ -38,7 +39,7 @@ import java.util.stream.Collectors;
|
||||
* Represents some input handlers.
|
||||
*
|
||||
* @author LambdAurora
|
||||
* @version 1.3.0
|
||||
* @version 1.4.0
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public class InputHandlers
|
||||
@@ -49,7 +50,7 @@ public class InputHandlers
|
||||
|
||||
public static PressAction handleHotbar(boolean next)
|
||||
{
|
||||
return (client, button, action) -> {
|
||||
return (client, button, value, action) -> {
|
||||
if (action == ButtonState.RELEASE)
|
||||
return false;
|
||||
|
||||
@@ -74,6 +75,8 @@ public class InputHandlers
|
||||
RecipeBookWidgetAccessor recipeBook = (RecipeBookWidgetAccessor) ((InventoryScreen) client.currentScreen).getRecipeBookWidget();
|
||||
List<RecipeGroupButtonWidget> tabs = recipeBook.getTabButtons();
|
||||
RecipeGroupButtonWidget currentTab = recipeBook.getCurrentTab();
|
||||
if (currentTab == null)
|
||||
return false;
|
||||
int nextTab = tabs.indexOf(currentTab) + (next ? 1 : -1);
|
||||
if (nextTab < 0)
|
||||
nextTab = tabs.size() - 1;
|
||||
@@ -83,10 +86,13 @@ public class InputHandlers
|
||||
recipeBook.setCurrentTab(currentTab = tabs.get(nextTab));
|
||||
currentTab.setToggled(true);
|
||||
recipeBook.lambdacontrols_refreshResults(true);
|
||||
return true;
|
||||
} else if (client.currentScreen instanceof AdvancementsScreen) {
|
||||
AdvancementsScreenAccessor screen = (AdvancementsScreenAccessor) client.currentScreen;
|
||||
List<AdvancementTab> tabs = screen.getTabs().values().stream().distinct().collect(Collectors.toList());
|
||||
AdvancementTab tab = screen.getSelectedTab();
|
||||
if (tab == null)
|
||||
return false;
|
||||
for (int i = 0; i < tabs.size(); i++) {
|
||||
if (tabs.get(i).equals(tab)) {
|
||||
int nextTab = i + (next ? 1 : -1);
|
||||
@@ -98,12 +104,13 @@ public class InputHandlers
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
public static boolean handlePauseGame(@NotNull MinecraftClient client, @NotNull ButtonBinding binding, @NotNull ButtonState action)
|
||||
public static boolean handlePauseGame(@NotNull MinecraftClient client, @NotNull ButtonBinding binding, float value, @NotNull ButtonState action)
|
||||
{
|
||||
if (action == ButtonState.PRESS) {
|
||||
// If in game, then pause the game.
|
||||
@@ -125,15 +132,15 @@ public class InputHandlers
|
||||
* @param action The action done on the binding.
|
||||
* @return True if handled, else false.
|
||||
*/
|
||||
public static boolean handleScreenshot(@NotNull MinecraftClient client, @NotNull ButtonBinding binding, @NotNull ButtonState action)
|
||||
public static boolean handleScreenshot(@NotNull MinecraftClient client, @NotNull ButtonBinding binding, float value, @NotNull ButtonState action)
|
||||
{
|
||||
if (action == ButtonState.PRESS)
|
||||
if (action == ButtonState.RELEASE)
|
||||
ScreenshotUtils.saveScreenshot(client.runDirectory, client.getWindow().getFramebufferWidth(), client.getWindow().getFramebufferHeight(), client.getFramebuffer(),
|
||||
text -> client.execute(() -> client.inGameHud.getChatHud().addMessage(text)));
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean handleToggleSneak(@NotNull MinecraftClient client, @NotNull ButtonBinding button, @NotNull ButtonState action)
|
||||
public static boolean handleToggleSneak(@NotNull MinecraftClient client, @NotNull ButtonBinding button, float value, @NotNull ButtonState action)
|
||||
{
|
||||
if (client.player != null && !client.player.abilities.flying) {
|
||||
button.asKeyBinding().filter(binding -> action == ButtonState.PRESS).ifPresent(binding -> ((KeyBindingAccessor) binding).lambdacontrols_handlePressState(!binding.isPressed()));
|
||||
@@ -144,7 +151,7 @@ public class InputHandlers
|
||||
|
||||
public static PressAction handleInventorySlotPad(int direction)
|
||||
{
|
||||
return (client, binding, action) -> {
|
||||
return (client, binding, value, action) -> {
|
||||
if (!(client.currentScreen instanceof HandledScreen && action != ButtonState.RELEASE))
|
||||
return false;
|
||||
|
||||
@@ -235,6 +242,20 @@ public class InputHandlers
|
||||
return client.currentScreen == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the client is in a non-interactive screen (which means require mouse input) or not.
|
||||
*
|
||||
* @param client The client instance.
|
||||
* @param binding The affected binding.
|
||||
* @return True if the client is in a non-interactive screen, else false.
|
||||
*/
|
||||
public static boolean inNonInteractiveScreens(@NotNull MinecraftClient client, @NotNull ButtonBinding binding)
|
||||
{
|
||||
if (client.currentScreen == null)
|
||||
return false;
|
||||
return !LambdaInput.isScreenInteractive(client.currentScreen);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the client is in an inventory or not.
|
||||
*
|
||||
|
||||
@@ -19,6 +19,7 @@ import net.minecraft.client.options.KeyBinding;
|
||||
import net.minecraft.client.util.InputUtil;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import org.aperlambda.lambdacommon.Identifier;
|
||||
import org.aperlambda.lambdacommon.utils.Pair;
|
||||
import org.aperlambda.lambdacommon.utils.function.PairPredicate;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
@@ -32,7 +33,7 @@ import java.util.stream.Stream;
|
||||
* Represents an input manager for controllers.
|
||||
*
|
||||
* @author LambdAurora
|
||||
* @version 1.3.0
|
||||
* @version 1.4.0
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public class InputManager
|
||||
@@ -41,6 +42,7 @@ 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 final Map<Integer, Float> BUTTON_VALUES = new HashMap<>();
|
||||
private int prevTargetMouseX = 0;
|
||||
private int prevTargetMouseY = 0;
|
||||
private int targetMouseX = 0;
|
||||
@@ -244,6 +246,23 @@ public class InputManager
|
||||
return state;
|
||||
}
|
||||
|
||||
public static float getBindingValue(@NotNull ButtonBinding binding, @NotNull ButtonState state)
|
||||
{
|
||||
if (state.isUnpressed())
|
||||
return 0.f;
|
||||
|
||||
float value = 0.f;
|
||||
for (int btn : binding.getButton()) {
|
||||
if (ButtonBinding.isAxis(btn)) {
|
||||
value = BUTTON_VALUES.getOrDefault(btn, 1.f);
|
||||
break;
|
||||
} else {
|
||||
value = 1.f;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the button has duplicated bindings.
|
||||
*
|
||||
@@ -317,7 +336,7 @@ public class InputManager
|
||||
public static void updateBindings(@NotNull MinecraftClient client)
|
||||
{
|
||||
List<Integer> skipButtons = new ArrayList<>();
|
||||
Map<ButtonBinding, ButtonState> states = new HashMap<>();
|
||||
Map<ButtonBinding, Pair<ButtonState, Float>> states = new HashMap<>();
|
||||
for (ButtonBinding binding : BINDINGS) {
|
||||
ButtonState state = binding.isAvailable(client) ? getBindingState(binding) : ButtonState.NONE;
|
||||
if (skipButtons.stream().anyMatch(btn -> containsButton(binding.getButton(), btn))) {
|
||||
@@ -330,12 +349,15 @@ public class InputManager
|
||||
binding.update();
|
||||
if (binding.pressed)
|
||||
Arrays.stream(binding.getButton()).forEach(skipButtons::add);
|
||||
states.put(binding, state);
|
||||
|
||||
float value = getBindingValue(binding, state);
|
||||
|
||||
states.put(binding, Pair.of(state, value));
|
||||
}
|
||||
|
||||
states.forEach((binding, state) -> {
|
||||
if (state != ButtonState.NONE) {
|
||||
binding.handle(client, state);
|
||||
if (state.key != ButtonState.NONE) {
|
||||
binding.handle(client, state.value, state.key);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -363,12 +385,12 @@ public class InputManager
|
||||
|
||||
/**
|
||||
* Returns a new key binding instance.
|
||||
* @param id The identifier of the key binding.
|
||||
* @param type The type.
|
||||
* @param code The code.
|
||||
*
|
||||
* @param id The identifier of the key binding.
|
||||
* @param type The type.
|
||||
* @param code The code.
|
||||
* @param category The category of the key binding.
|
||||
* @return The key binding.
|
||||
*
|
||||
* @see #makeKeyBinding(Identifier, InputUtil.Type, int, String)
|
||||
*/
|
||||
public static @NotNull KeyBinding makeKeyBinding(@NotNull net.minecraft.util.Identifier id, InputUtil.Type type, int code, @NotNull String category)
|
||||
@@ -378,12 +400,12 @@ public class InputManager
|
||||
|
||||
/**
|
||||
* Returns a new key binding instance.
|
||||
* @param id The identifier of the key binding.
|
||||
* @param type The type.
|
||||
* @param code The code.
|
||||
*
|
||||
* @param id The identifier of the key binding.
|
||||
* @param type The type.
|
||||
* @param code The code.
|
||||
* @param category The category of the key binding.
|
||||
* @return The key binding.
|
||||
*
|
||||
* @see #makeKeyBinding(net.minecraft.util.Identifier, InputUtil.Type, int, String)
|
||||
*/
|
||||
public static @NotNull KeyBinding makeKeyBinding(@NotNull Identifier id, InputUtil.Type type, int code, @NotNull String category)
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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.client.controller;
|
||||
|
||||
import me.lambdaurora.lambdacontrols.client.ButtonState;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Represents the movement handler.
|
||||
*
|
||||
* @author LambdAurora
|
||||
* @version 1.4.0
|
||||
* @since 1.4.0
|
||||
*/
|
||||
public final class MovementHandler implements PressAction
|
||||
{
|
||||
public static final MovementHandler HANDLER = new MovementHandler();
|
||||
private boolean shouldOverrideMovement = false;
|
||||
private boolean pressingForward = false;
|
||||
private boolean pressingBack = false;
|
||||
private boolean pressingLeft = false;
|
||||
private boolean pressingRight = false;
|
||||
private float movementForward = 0.f;
|
||||
private float movementSideways = 0.f;
|
||||
|
||||
private MovementHandler()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies movement input of this handler to the player's input.
|
||||
*
|
||||
* @param player The client player.
|
||||
*/
|
||||
public void applyMovement(@NotNull ClientPlayerEntity player)
|
||||
{
|
||||
if (!this.shouldOverrideMovement)
|
||||
return;
|
||||
player.input.pressingForward = this.pressingForward;
|
||||
player.input.pressingBack = this.pressingBack;
|
||||
player.input.pressingLeft = this.pressingLeft;
|
||||
player.input.pressingRight = this.pressingRight;
|
||||
player.input.movementForward = this.movementForward;
|
||||
player.input.movementSideways = this.movementSideways;
|
||||
this.shouldOverrideMovement = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean press(@NotNull MinecraftClient client, @NotNull ButtonBinding button, float value, @NotNull ButtonState action)
|
||||
{
|
||||
if (client.currentScreen != null || client.player == null)
|
||||
return this.shouldOverrideMovement = false;
|
||||
|
||||
int direction = 0;
|
||||
if (button == ButtonBinding.FORWARD || button == ButtonBinding.LEFT)
|
||||
direction = 1;
|
||||
else if (button == ButtonBinding.BACK || button == ButtonBinding.RIGHT)
|
||||
direction = -1;
|
||||
|
||||
if (direction == 0)
|
||||
return false;
|
||||
|
||||
this.shouldOverrideMovement = true;
|
||||
|
||||
value = (float) Math.pow(value, 2);
|
||||
|
||||
if (button == ButtonBinding.FORWARD || button == ButtonBinding.BACK) {
|
||||
// Handle forward movement.
|
||||
this.pressingForward = direction > 0;
|
||||
this.pressingBack = direction < 0;
|
||||
this.movementForward = direction * value;
|
||||
|
||||
// Slowing down if sneaking.
|
||||
if (client.player.input.sneaking)
|
||||
this.movementForward *= 0.3D;
|
||||
} else {
|
||||
// Handle sideways movement.
|
||||
this.pressingLeft = direction > 0;
|
||||
this.pressingRight = direction < 0;
|
||||
this.movementSideways = direction * value;
|
||||
|
||||
// Slowing down if sneaking.
|
||||
if (client.player.input.sneaking)
|
||||
this.movementSideways *= 0.3D;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -18,13 +18,13 @@ import org.jetbrains.annotations.NotNull;
|
||||
* Represents a press action callback.
|
||||
*
|
||||
* @author LambdAurora
|
||||
* @version 1.1.0
|
||||
* @version 1.4.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface PressAction
|
||||
{
|
||||
PressAction DEFAULT_ACTION = (client, button, action) -> {
|
||||
PressAction DEFAULT_ACTION = (client, button, value, action) -> {
|
||||
if (action == ButtonState.REPEAT || client.currentScreen != null)
|
||||
return false;
|
||||
button.asKeyBinding().ifPresent(binding -> ((KeyBindingAccessor) binding).lambdacontrols_handlePressState(button.isButtonDown()));
|
||||
@@ -37,5 +37,5 @@ public interface PressAction
|
||||
* @param client The client instance.
|
||||
* @param action The action done.
|
||||
*/
|
||||
boolean press(@NotNull MinecraftClient client, @NotNull ButtonBinding button, @NotNull ButtonState action);
|
||||
boolean press(@NotNull MinecraftClient client, @NotNull ButtonBinding button, float value, @NotNull ButtonState action);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ package me.lambdaurora.lambdacontrols.client.mixin;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import me.lambdaurora.lambdacontrols.client.LambdaControlsClient;
|
||||
import me.lambdaurora.lambdacontrols.client.controller.MovementHandler;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.input.Input;
|
||||
import net.minecraft.client.network.AbstractClientPlayerEntity;
|
||||
@@ -69,6 +70,12 @@ public abstract class ClientPlayerEntityMixin extends AbstractClientPlayerEntity
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "tickMovement", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/input/Input;tick(Z)V", shift = At.Shift.AFTER))
|
||||
public void onInputUpdate(CallbackInfo ci)
|
||||
{
|
||||
MovementHandler.HANDLER.applyMovement((ClientPlayerEntity) (Object) this);
|
||||
}
|
||||
|
||||
@Inject(method = "tickMovement", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;isCamera()Z"))
|
||||
public void onTickMovement(CallbackInfo ci)
|
||||
{
|
||||
|
||||
@@ -17,7 +17,6 @@ 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 net.minecraft.text.TranslatableText;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
|
||||
@@ -22,15 +22,12 @@ import net.minecraft.screen.slot.SlotActionType;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Represents the mixin for the class ContainerScreen.
|
||||
*/
|
||||
|
||||
@@ -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.client.ring;
|
||||
|
||||
import me.lambdaurora.lambdacontrols.client.util.KeyBindingAccessor;
|
||||
import net.minecraft.client.options.KeyBinding;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class KeyBindingRingAction extends RingAction
|
||||
{
|
||||
public final KeyBinding binding;
|
||||
|
||||
public KeyBindingRingAction(@NotNull KeyBinding binding)
|
||||
{
|
||||
this.binding = binding;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getName()
|
||||
{
|
||||
return this.binding.getTranslationKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAction(@NotNull RingButtonMode mode)
|
||||
{
|
||||
KeyBindingAccessor accessor = (KeyBindingAccessor) this.binding;
|
||||
switch (mode) {
|
||||
case PRESS:
|
||||
case HOLD:
|
||||
accessor.lambdacontrols_handlePressState(this.activated);
|
||||
break;
|
||||
case TOGGLE:
|
||||
accessor.lambdacontrols_handlePressState(!this.binding.isPressed());
|
||||
this.activated = !this.binding.isPressed();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.client.ring;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents a key binding ring.
|
||||
*
|
||||
* @author LambdAurora
|
||||
* @version 1.4.0
|
||||
* @since 1.4.0
|
||||
*/
|
||||
public class LambdaRing
|
||||
{
|
||||
private final List<RingPage> pages = new ArrayList<>(Collections.singletonList(new RingPage()));
|
||||
private int currentPage = 0;
|
||||
|
||||
public LambdaRing()
|
||||
{
|
||||
}
|
||||
|
||||
public @NotNull RingPage getCurrentPage()
|
||||
{
|
||||
if (this.currentPage >= this.pages.size())
|
||||
this.currentPage = this.pages.size() - 1;
|
||||
else if (this.currentPage < 0)
|
||||
this.currentPage = 0;
|
||||
return this.pages.get(this.currentPage);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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.client.ring;
|
||||
|
||||
import net.minecraft.text.TranslatableText;
|
||||
import org.aperlambda.lambdacommon.utils.Nameable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Represents a ring action.
|
||||
*
|
||||
* @author LambdAurora
|
||||
* @version 1.4.0
|
||||
* @since 1.4.0
|
||||
*/
|
||||
public abstract class RingAction implements Nameable
|
||||
{
|
||||
protected boolean activated = false;
|
||||
|
||||
/**
|
||||
* Gets the translated name of the ring action.
|
||||
*
|
||||
* @return The translated name.
|
||||
*/
|
||||
public TranslatableText getTranslatedName()
|
||||
{
|
||||
return new TranslatableText(this.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the action is activated or not.
|
||||
*
|
||||
* @return True if the action is activated, else false.
|
||||
*/
|
||||
public boolean isActivated()
|
||||
{
|
||||
return this.activated;
|
||||
}
|
||||
|
||||
public void activate(@NotNull RingButtonMode mode)
|
||||
{
|
||||
this.activated = !this.activated;
|
||||
|
||||
this.onAction(mode);
|
||||
}
|
||||
|
||||
public abstract void onAction(@NotNull RingButtonMode mode);
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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.client.ring;
|
||||
|
||||
import net.minecraft.client.resource.language.I18n;
|
||||
import org.aperlambda.lambdacommon.utils.Nameable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Represents the mode of a ring button.
|
||||
*
|
||||
* @author LambdAurora
|
||||
* @version 1.4.0
|
||||
* @since 1.4.0
|
||||
*/
|
||||
public enum RingButtonMode implements Nameable
|
||||
{
|
||||
PRESS("press"),
|
||||
HOLD("hold"),
|
||||
TOGGLE("toggle");
|
||||
|
||||
private String name;
|
||||
|
||||
RingButtonMode(@NotNull String name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next ring button mode available.
|
||||
*
|
||||
* @return The next ring button mode.
|
||||
*/
|
||||
public RingButtonMode next()
|
||||
{
|
||||
RingButtonMode[] v = values();
|
||||
if (v.length == this.ordinal() + 1)
|
||||
return v[0];
|
||||
return v[this.ordinal() + 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the translated name of this ring button mode.
|
||||
*
|
||||
* @return The translated name of this ring button mode.
|
||||
*/
|
||||
public String getTranslatedName()
|
||||
{
|
||||
return I18n.translate("lambdacontrols.ring.button_mode." + this.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getName()
|
||||
{
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
@@ -10,13 +10,15 @@
|
||||
package me.lambdaurora.lambdacontrols.client.ring;
|
||||
|
||||
/**
|
||||
* Represents a key binding ring.
|
||||
* Represents a ring page.
|
||||
*
|
||||
* @author LambdAurora
|
||||
* @version 1.4.0
|
||||
* @since 1.4.0
|
||||
*/
|
||||
public class KeyBindingRing
|
||||
public class RingPage
|
||||
{
|
||||
private RingAction[] actions = new RingAction[8];
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user