From 756e7d102d1043cdc94764c7219ebe65a9d5d344 Mon Sep 17 00:00:00 2001 From: LambdAurora Date: Sat, 27 Jun 2020 18:21:46 +0200 Subject: [PATCH 1/2] Improve rotation algorithm. --- fabric/build.gradle | 2 +- .../client/LambdaControlsClient.java | 2 +- .../lambdacontrols/client/LambdaInput.java | 42 +++++++++--------- .../lambdacontrols/textures/gui/cursor.png | Bin 0 -> 1087 bytes 4 files changed, 24 insertions(+), 22 deletions(-) create mode 100644 fabric/src/main/resources/assets/lambdacontrols/textures/gui/cursor.png diff --git a/fabric/build.gradle b/fabric/build.gradle index 1242bd7..a4b46ab 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'fabric-loom' version '0.2.6-SNAPSHOT' + id 'fabric-loom' version '0.4-SNAPSHOT' id 'java-library' id 'maven-publish' } diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaControlsClient.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaControlsClient.java index 0310531..03216f0 100644 --- a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaControlsClient.java +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaControlsClient.java @@ -131,7 +131,7 @@ public class LambdaControlsClient extends LambdaControls implements ClientModIni public void onRender(MinecraftClient client) { - this.input.onRender(client); + this.input.onRender(client.getTickDelta(), client); } /** diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaInput.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaInput.java index 407ed21..0e6c6cd 100644 --- a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaInput.java +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaInput.java @@ -41,6 +41,7 @@ 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.entity.player.PlayerEntity; import net.minecraft.item.BlockItem; import net.minecraft.item.ItemStack; import net.minecraft.util.hit.BlockHitResult; @@ -80,8 +81,6 @@ public class LambdaInput private int actionGuiCooldown = 0; private int ignoreNextA = 0; // Sneak state. - private double prevTargetYaw = 0.0; - private double prevTargetPitch = 0.0; private double targetYaw = 0.0; private double targetPitch = 0.0; private float prevXAxis = 0.F; @@ -103,8 +102,8 @@ public class LambdaInput */ public void onTick(@NotNull MinecraftClient client) { - this.prevTargetYaw = this.targetYaw; - this.prevTargetPitch = this.targetPitch; + this.targetYaw = 0.F; + this.targetPitch = 0.F; // Handles the key bindings. if (LambdaControlsClient.BINDING_LOOK_UP.isPressed()) { @@ -189,20 +188,24 @@ public class LambdaInput * * @param client The client instance. */ - public void onRender(@NotNull MinecraftClient client) + public void onRender(float tickDelta, @NotNull MinecraftClient client) { - if ((client.currentScreen == null || client.currentScreen instanceof TouchscreenOverlay) && - (this.prevTargetYaw != this.targetYaw || this.prevTargetPitch != this.targetPitch)) { - float deltaYaw = (float) ((this.targetYaw - client.player.prevYaw) * client.getTickDelta()); - float deltaPitch = (float) ((this.targetPitch - client.player.prevPitch) * client.getTickDelta()); - float rotationYaw = client.player.prevYaw + deltaYaw; - float rotationPitch = client.player.prevPitch + deltaPitch; + if (!(client.currentScreen == null || client.currentScreen instanceof TouchscreenOverlay)) + return; + + PlayerEntity player = client.player; + if (player == null) + return; + + if (this.targetYaw != 0F || this.targetPitch != 0F) { + float rotationYaw = (float) (player.prevYaw + (this.targetYaw / 0.10) * tickDelta); + float rotationPitch = (float) (player.prevPitch + (this.targetPitch / 0.10) * tickDelta); client.player.yaw = rotationYaw; client.player.pitch = MathHelper.clamp(rotationPitch, -90.F, 90.F); if (client.player.isRiding()) { client.player.getVehicle().copyPositionAndRotation(client.player); } - client.getTutorialManager().onUpdateMouse(deltaPitch, deltaYaw); + client.getTutorialManager().onUpdateMouse(this.targetPitch, this.targetYaw); } } @@ -437,6 +440,7 @@ public class LambdaInput if (client.currentScreen == null) { // Handles the look direction. + absValue -= this.config.getDeadZone(); this.handleLook(client, axis, (float) (absValue / (1.0 - this.config.getDeadZone())), state); } else { boolean allowMouseControl = true; @@ -570,7 +574,7 @@ public class LambdaInput /** * Handles the look direction input. * - * @param client The client isntance. + * @param client The client instance. * @param axis The axis to change. * @param value The value of the look. * @param state The state. @@ -579,21 +583,19 @@ public class LambdaInput { // Handles the look direction. if (client.player != null) { - double powValue = Math.pow(value, 4.0); + double powValue = Math.pow(value, 2.0); if (axis == GLFW_GAMEPAD_AXIS_RIGHT_Y) { if (state == 2) { - this.targetPitch = client.player.pitch - this.config.getRightYAxisSign() * (this.config.getRotationSpeed() * powValue) * 0.33D; - this.targetPitch = MathHelper.clamp(this.targetPitch, -90.0D, 90.0D); + this.targetPitch = -this.config.getRightYAxisSign() * (this.config.getRotationSpeed() * powValue) * 0.33D; } else if (state == 1) { - this.targetPitch = client.player.pitch + this.config.getRightYAxisSign() * (this.config.getRotationSpeed() * powValue) * 0.33D; - this.targetPitch = MathHelper.clamp(this.targetPitch, -90.0D, 90.0D); + this.targetPitch = this.config.getRightYAxisSign() * (this.config.getRotationSpeed() * powValue) * 0.33D; } } if (axis == GLFW_GAMEPAD_AXIS_RIGHT_X) { if (state == 2) { - this.targetYaw = client.player.yaw - this.config.getRightXAxisSign() * (this.config.getRotationSpeed() * powValue) * 0.33D; + this.targetYaw = -this.config.getRightXAxisSign() * (this.config.getRotationSpeed() * powValue) * 0.33D; } else if (state == 1) { - this.targetYaw = client.player.yaw + this.config.getRightXAxisSign() * (this.config.getRotationSpeed() * powValue) * 0.33D; + this.targetYaw = this.config.getRightXAxisSign() * (this.config.getRotationSpeed() * powValue) * 0.33D; } } } diff --git a/fabric/src/main/resources/assets/lambdacontrols/textures/gui/cursor.png b/fabric/src/main/resources/assets/lambdacontrols/textures/gui/cursor.png new file mode 100644 index 0000000000000000000000000000000000000000..3b7ae917a43da00e7a03160328398bc1b2b61ff7 GIT binary patch literal 1087 zcmV-F1i<@=P)#WSyTCXX^Z}*oZ}E!LE9GGEJOpVl8Xrg-3UW)!dx&kw6J5jJKKNw6d*uh{LTCRU zW!Q@V000SaNLh0L09-}@09-}^6qG|j0007ZNklFkSnW;l;hYsY!!4q;|@drHZJ z2}NGOa|%3VUKzc68QBl333ROa~fGu^*jIoU#H-+m4=pno)O^SkW6H=NOCLAhM;T zWU@$^7F8;_Q|sLxw@1@4{7g7J1z9K5@~!zIvIl7Cba%m8Hxv&=%9O{b9)P>Kw74Ro zCadAQc0y}QE-BQF0C&z(W700Ghi}Iw0l6WwZo*5qXz7>|u9yN0IG@k6hw#}VAviJI z<#JKIr{TJJpcIsuFh%41Xypq#jC zY2_C+TM6H_6S4};n^AOyywP|!BgAOhj+X<5dXwr^;0@u=Hd`~X84>^h002ovPDHLk FV1j)3=LrA+ literal 0 HcmV?d00001 From ff672f05a13fcbb99dd3cab206dba0f86af3fddc Mon Sep 17 00:00:00 2001 From: LambdAurora Date: Sat, 27 Jun 2020 18:40:35 +0200 Subject: [PATCH 2/2] :bookmark: LambdaControls v1.2.0: Fast block placement, virtual mouse, etc. --- .../client/LambdaControlsClient.java | 1 + .../client/LambdaControlsConfig.java | 78 +++++++++++++++---- .../lambdacontrols/client/LambdaInput.java | 7 +- .../client/VirtualMouseSkin.java | 77 ++++++++++++++++++ .../client/controller/InputManager.java | 5 +- .../client/gui/LambdaControlsRenderer.java | 78 ++++++++++++++++++- .../gui/LambdaControlsSettingsScreen.java | 11 ++- .../client/mixin/MinecraftClientMixin.java | 7 ++ .../client/mixin/MouseMixin.java | 4 +- .../assets/lambdacontrols/lang/en_us.json | 9 ++- .../assets/lambdacontrols/lang/fr_ca.json | 9 ++- .../assets/lambdacontrols/lang/fr_fr.json | 9 ++- fabric/src/main/resources/config.toml | 4 + 13 files changed, 273 insertions(+), 26 deletions(-) create mode 100644 fabric/src/main/java/me/lambdaurora/lambdacontrols/client/VirtualMouseSkin.java diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaControlsClient.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaControlsClient.java index 03216f0..6c8ad38 100644 --- a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaControlsClient.java +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaControlsClient.java @@ -54,6 +54,7 @@ public class LambdaControlsClient extends LambdaControls implements ClientModIni InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_4, "key.categories.movement").build(); public static final Identifier CONTROLLER_BUTTONS = new Identifier(LambdaControlsConstants.NAMESPACE, "textures/gui/controller_buttons.png"); public static final Identifier CONTROLLER_AXIS = new Identifier(LambdaControlsConstants.NAMESPACE, "textures/gui/controller_axis.png"); + public static final Identifier CURSOR_TEXTURE = new Identifier(LambdaControlsConstants.NAMESPACE, "textures/gui/cursor.png"); public final LambdaControlsConfig config = new LambdaControlsConfig(this); public final LambdaInput input = new LambdaInput(this); private LambdaControlsHud hud; diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaControlsConfig.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaControlsConfig.java index 4ece990..b4ccf21 100644 --- a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaControlsConfig.java +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaControlsConfig.java @@ -34,23 +34,25 @@ import static org.lwjgl.glfw.GLFW.GLFW_GAMEPAD_AXIS_LEFT_Y; public class LambdaControlsConfig { // General - private static final ControlsMode DEFAULT_CONTROLS_MODE = ControlsMode.DEFAULT; - private static final boolean DEFAULT_AUTO_SWITCH_MODE = false; + private static final ControlsMode DEFAULT_CONTROLS_MODE = ControlsMode.DEFAULT; + private static final boolean DEFAULT_AUTO_SWITCH_MODE = false; // HUD - private static final boolean DEFAULT_HUD_ENABLE = true; - private static final HudSide DEFAULT_HUD_SIDE = HudSide.LEFT; + private static final boolean DEFAULT_HUD_ENABLE = true; + private static final HudSide DEFAULT_HUD_SIDE = HudSide.LEFT; // Gameplay - private static final boolean DEFAULT_FAST_BLOCK_INTERACTION = true; - private static final boolean DEFAULT_FLY_DRIFTING = false; - private static final boolean DEFAULT_FLY_VERTICAL_DRIFTING = true; - private static final boolean DEFAULT_FRONT_BLOCK_PLACING = false; - private static final boolean DEFAULT_FRONT_BLOCK_OUTLINE = true; + private static final boolean DEFAULT_FAST_BLOCK_INTERACTION = true; + private static final boolean DEFAULT_FLY_DRIFTING = false; + private static final boolean DEFAULT_FLY_VERTICAL_DRIFTING = true; + private static final boolean DEFAULT_FRONT_BLOCK_PLACING = false; + private static final boolean DEFAULT_FRONT_BLOCK_OUTLINE = true; // Controller - 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 boolean DEFAULT_UNFOCUSED_INPUT = false; + 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 boolean DEFAULT_UNFOCUSED_INPUT = false; + private static final boolean DEFAULT_VIRTUAL_MOUSE = false; + private static final VirtualMouseSkin DEFAULT_VIRTUAL_MOUSE_SKIN = VirtualMouseSkin.DEFAULT_LIGHT; private static final Pattern BUTTON_BINDING_PATTERN = Pattern.compile("(-?\\d+)\\+?"); @@ -66,6 +68,8 @@ public class LambdaControlsConfig private double rotationSpeed; private double mouseSpeed; private boolean unfocusedInput; + private boolean virtualMouse; + private VirtualMouseSkin virtualMouseSkin; // HUD settings. private boolean hudEnable; private HudSide hudSide; @@ -98,6 +102,8 @@ public class LambdaControlsConfig this.rotationSpeed = this.config.getOrElse("controller.rotation_speed", DEFAULT_ROTATION_SPEED); this.mouseSpeed = this.config.getOrElse("controller.mouse_speed", DEFAULT_MOUSE_SPEED); this.unfocusedInput = this.config.getOrElse("controller.unfocused_input", DEFAULT_UNFOCUSED_INPUT); + this.virtualMouse = this.config.getOrElse("controller.virtual_mouse", DEFAULT_VIRTUAL_MOUSE); + this.virtualMouseSkin = VirtualMouseSkin.byId(this.config.getOrElse("controller.virtual_mouse_skin", DEFAULT_VIRTUAL_MOUSE_SKIN.getName())).orElse(DEFAULT_VIRTUAL_MOUSE_SKIN); // Controller controls. InputManager.loadButtonBindings(this); } @@ -111,6 +117,7 @@ public class LambdaControlsConfig this.config.set("controller.rotation_speed", this.rotationSpeed); this.config.set("controller.mouse_speed", this.mouseSpeed); this.config.set("controller.unfocused_input", this.unfocusedInput); + this.config.set("controller.virtual_mouse", this.virtualMouse); this.config.save(); this.mod.log("Configuration saved."); } @@ -165,6 +172,8 @@ public class LambdaControlsConfig this.setRotationSpeed(DEFAULT_ROTATION_SPEED); this.setMouseSpeed(DEFAULT_MOUSE_SPEED); this.setUnfocusedInput(DEFAULT_UNFOCUSED_INPUT); + this.setVirtualMouse(DEFAULT_VIRTUAL_MOUSE); + this.setVirtualMouseSkin(DEFAULT_VIRTUAL_MOUSE_SKIN); // HUD this.setHudEnabled(DEFAULT_HUD_ENABLE); this.setHudSide(DEFAULT_HUD_SIDE); @@ -577,6 +586,47 @@ public class LambdaControlsConfig this.unfocusedInput = unfocusedInput; } + /** + * Returns whether the mouse is virtual or not. + * + * @return True if the mouse is virtual, else false. + */ + public boolean hasVirtualMouse() + { + return this.virtualMouse; + } + + /** + * Sets whether the mouse is virtual or not. + * + * @param virtualMouse True if the mouse is virtual, else false. + */ + public void setVirtualMouse(boolean virtualMouse) + { + this.virtualMouse = virtualMouse; + } + + /** + * Gets the virtual mouse skin. + * + * @return The virtual mouse skin. + */ + public VirtualMouseSkin getVirtualMouseSkin() + { + return this.virtualMouseSkin; + } + + /** + * Sets the virtual mouse skin. + * + * @param skin The virtual mouse skin. + */ + public void setVirtualMouseSkin(VirtualMouseSkin skin) + { + this.virtualMouseSkin = skin; + this.config.set("controller.virtual_mouse_skin", skin.getName()); + } + /** * Gets the right X axis sign. * diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaInput.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaInput.java index 0e6c6cd..6b51788 100644 --- a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaInput.java +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/LambdaInput.java @@ -20,6 +20,7 @@ import me.lambdaurora.lambdacontrols.client.mixin.AdvancementsScreenAccessor; import me.lambdaurora.lambdacontrols.client.mixin.CreativeInventoryScreenAccessor; import me.lambdaurora.lambdacontrols.client.mixin.EntryListWidgetAccessor; import me.lambdaurora.lambdacontrols.client.util.ContainerScreenAccessor; +import me.lambdaurora.lambdacontrols.client.util.MouseAccessor; import me.lambdaurora.spruceui.SpruceLabelWidget; import net.minecraft.block.Block; import net.minecraft.block.BlockState; @@ -80,7 +81,6 @@ public class LambdaInput // Cooldowns private int actionGuiCooldown = 0; private int ignoreNextA = 0; - // Sneak state. private double targetYaw = 0.0; private double targetPitch = 0.0; private float prevXAxis = 0.F; @@ -221,6 +221,9 @@ public class LambdaInput if (client.currentScreen == null) { this.mouseSpeedX = this.mouseSpeedY = 0.0F; INPUT_MANAGER.resetMousePosition(windowWidth, windowHeight); + } else if (isScreenInteractive(client.currentScreen) && this.config.hasVirtualMouse()) { + ((MouseAccessor) client.mouse).lambdacontrols_onCursorPos(client.getWindow().getHandle(), 0, 0); + INPUT_MANAGER.resetMouseTarget(client); } } @@ -615,7 +618,7 @@ public class LambdaInput } } - private static boolean isScreenInteractive(@NotNull Screen screen) + public static boolean isScreenInteractive(@NotNull Screen screen) { return !(screen instanceof AdvancementsScreen || screen instanceof ContainerScreen || LambdaControlsCompat.requireMouseOnScreen(screen)); } diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/VirtualMouseSkin.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/VirtualMouseSkin.java new file mode 100644 index 0000000..83c310d --- /dev/null +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/VirtualMouseSkin.java @@ -0,0 +1,77 @@ +/* + * Copyright © 2020 LambdAurora + * + * This file is part of LambdaControls. + * + * Licensed under the MIT license. For more information, + * see the LICENSE file. + */ + +package me.lambdaurora.lambdacontrols.client; + +import net.minecraft.client.resource.language.I18n; +import org.aperlambda.lambdacommon.utils.Nameable; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; +import java.util.Optional; + +/** + * Represents the virtual mouse skins. + * + * @version 1.2.0 + * @since 1.2.0 + */ +public enum VirtualMouseSkin implements Nameable +{ + DEFAULT_LIGHT("default_light"), + DEFAULT_DARK("default_dark"), + SECOND_LIGHT("second_light"), + SECOND_DARK("second_dark"); + + private String name; + + VirtualMouseSkin(String name) { + this.name = name; + } + + /** + * Returns the next virtual mouse skin available. + * + * @return The next available virtual mouse skin. + */ + public VirtualMouseSkin next() + { + VirtualMouseSkin[] v = values(); + if (v.length == this.ordinal() + 1) + return v[0]; + return v[this.ordinal() + 1]; + } + + /** + * Gets the translated name of this controller type. + * + * @return The translated name of this controller type. + */ + public String getTranslatedName() + { + return I18n.translate("lambdacontrols.virtual_mouse.skin." + this.getName()); + } + + @Override + public @NotNull String getName() + { + return this.name; + } + + /** + * Gets the controller type from its identifier. + * + * @param id The identifier of the controller type. + * @return The controller type if found, else empty. + */ + public static Optional byId(@NotNull String id) + { + return Arrays.stream(values()).filter(mode -> mode.getName().equalsIgnoreCase(id)).findFirst(); + } +} diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/controller/InputManager.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/controller/InputManager.java index 5cd2f83..66aff9f 100644 --- a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/controller/InputManager.java +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/controller/InputManager.java @@ -30,7 +30,7 @@ import java.util.stream.Stream; * Represents an input manager for controllers. * * @author LambdAurora - * @version 1.1.0 + * @version 1.2.0 * @since 1.1.0 */ public class InputManager @@ -72,7 +72,8 @@ public class InputManager if (this.prevTargetMouseX != this.targetMouseX || this.prevTargetMouseY != this.targetMouseY) { double mouseX = this.prevTargetMouseX + (this.targetMouseX - this.prevTargetMouseX) * client.getTickDelta() + 0.5; double mouseY = this.prevTargetMouseY + (this.targetMouseY - this.prevTargetMouseY) * client.getTickDelta() + 0.5; - GLFW.glfwSetCursorPos(client.getWindow().getHandle(), mouseX, mouseY); + if (!LambdaControlsClient.get().config.hasVirtualMouse()) + GLFW.glfwSetCursorPos(client.getWindow().getHandle(), mouseX, mouseY); ((MouseAccessor) client.mouse).lambdacontrols_onCursorPos(client.getWindow().getHandle(), mouseX, mouseY); } } diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/gui/LambdaControlsRenderer.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/gui/LambdaControlsRenderer.java index 0106476..0fd9c5c 100644 --- a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/gui/LambdaControlsRenderer.java +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/gui/LambdaControlsRenderer.java @@ -9,18 +9,24 @@ package me.lambdaurora.lambdacontrols.client.gui; -import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem; import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; import me.lambdaurora.lambdacontrols.client.controller.ButtonBinding; +import me.lambdaurora.lambdacontrols.client.util.ContainerScreenAccessor; import net.minecraft.client.MinecraftClient; import net.minecraft.client.font.TextRenderer; import net.minecraft.client.gui.DrawableHelper; +import net.minecraft.client.gui.screen.ingame.ContainerScreen; import net.minecraft.client.resource.language.I18n; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.container.Slot; import org.aperlambda.lambdacommon.utils.Pair; import org.jetbrains.annotations.NotNull; import org.lwjgl.glfw.GLFW; +import java.util.Comparator; +import java.util.Optional; + /** * Represents the LambdaControls renderer. * @@ -185,7 +191,7 @@ public class LambdaControlsRenderer } client.getTextureManager().bindTexture(axis ? LambdaControlsClient.CONTROLLER_AXIS : LambdaControlsClient.CONTROLLER_BUTTONS); - GlStateManager.disableDepthTest(); + RenderSystem.disableDepthTest(); int assetSize = axis ? AXIS_SIZE : BUTTON_SIZE; @@ -194,7 +200,7 @@ public class LambdaControlsRenderer (float) buttonOffset, (float) (controllerType * (axis ? AXIS_SIZE : BUTTON_SIZE)), assetSize, assetSize, 256, 256); - GlStateManager.enableDepthTest(); + RenderSystem.enableDepthTest(); return ICON_SIZE; } @@ -222,4 +228,70 @@ public class LambdaControlsRenderer { return 15 + 5 + textRenderer.getStringWidth(action); } + + public static void renderVirtualCursor(@NotNull MatrixStack matrices, @NotNull MinecraftClient client) + { + if (!LambdaControlsClient.get().config.hasVirtualMouse() || client.currentScreen == null) + return; + + int mouseX = (int) (client.mouse.getX() * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth()); + int mouseY = (int) (client.mouse.getY() * (double) client.getWindow().getScaledHeight() / (double) client.getWindow().getHeight()); + + boolean hoverSlot = false; + + if (client.currentScreen instanceof ContainerScreen) { + ContainerScreen inventoryScreen = (ContainerScreen) client.currentScreen; + ContainerScreenAccessor accessor = (ContainerScreenAccessor) inventoryScreen; + int guiLeft = accessor.getX(); + int guiTop = accessor.getY(); + + // Finds the closest slot in the GUI within 14 pixels. + int finalMouseX = mouseX; + int finalMouseY = mouseY; + Optional> closestSlot = inventoryScreen.getContainer().slots.parallelStream() + .map(slot -> { + int x = guiLeft + slot.xPosition + 8; + int y = guiTop + slot.yPosition + 8; + + // Distance between the slot and the cursor. + double distance = Math.sqrt(Math.pow(x - finalMouseX, 2) + Math.pow(y - finalMouseY, 2)); + return Pair.of(slot, distance); + }).filter(entry -> entry.value <= 9.0) + .min(Comparator.comparingDouble(p -> p.value)); + + if (closestSlot.isPresent()) { + Slot slot = closestSlot.get().key; + mouseX = guiLeft + slot.xPosition; + mouseY = guiTop + slot.yPosition; + hoverSlot = true; + } + } + + if (!hoverSlot) { + mouseX -= 8; + mouseY -= 8; + } + + drawCursor(matrices, mouseX, mouseY, hoverSlot, client); + } + + /** + * Draws the virtual cursor. + * + * @param matrices The matrix stack. + * @param x X coordinate. + * @param y Y coordinate. + * @param hoverSlot True if hovering a slot, else false. + * @param client The client instance. + */ + public static void drawCursor(@NotNull MatrixStack matrices, int x, int y, boolean hoverSlot, @NotNull MinecraftClient client) + { + client.getTextureManager().bindTexture(LambdaControlsClient.CURSOR_TEXTURE); + + RenderSystem.disableDepthTest(); + + RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F); + DrawableHelper.blit(x, y, hoverSlot ? 16.F : 0.F, LambdaControlsClient.get().config.getVirtualMouseSkin().ordinal() * 16.F, 16, 16, 32, 64); + RenderSystem.enableDepthTest(); + } } diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/gui/LambdaControlsSettingsScreen.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/gui/LambdaControlsSettingsScreen.java index d61a3c5..bdc1fd7 100644 --- a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/gui/LambdaControlsSettingsScreen.java +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/gui/LambdaControlsSettingsScreen.java @@ -58,6 +58,8 @@ public class LambdaControlsSettingsScreen extends Screen private final Option invertsRightXAxis; private final Option invertsRightYAxis; private final Option unfocusedInputOption; + private final Option virtualMouseOption; + private final Option virtualMouseSkinOption; // Hud options private final Option hudEnableOption; private final Option hudSideOption; @@ -163,6 +165,12 @@ public class LambdaControlsSettingsScreen extends Screen }, null, true); this.unfocusedInputOption = new SpruceBooleanOption("lambdacontrols.menu.unfocused_input", this.mod.config::hasUnfocusedInput, this.mod.config::setUnfocusedInput, new TranslatableText("lambdacontrols.tooltip.unfocused_input"), true); + this.virtualMouseOption = new SpruceBooleanOption("lambdacontrols.menu.virtual_mouse", this.mod.config::hasVirtualMouse, + this.mod.config::setVirtualMouse, new TranslatableText("lambdacontrols.tooltip.virtual_mouse"), true); + this.virtualMouseSkinOption = new SpruceCyclingOption("lambdacontrols.menu.virtual_mouse.skin", + amount -> this.mod.config.setVirtualMouseSkin(this.mod.config.getVirtualMouseSkin().next()), + option -> option.getDisplayPrefix() + this.mod.config.getVirtualMouseSkin().getTranslatedName(), + null); // HUD options this.hudEnableOption = new SpruceBooleanOption("lambdacontrols.menu.hud_enable", this.mod.config::isHudEnabled, this.mod::setHudEnabled, new TranslatableText("lambdacontrols.tooltip.hud_enable"), true); @@ -236,7 +244,8 @@ public class LambdaControlsSettingsScreen extends Screen this.list.addSingleOptionEntry(this.secondControllerOption); this.list.addOptionEntry(this.controllerTypeOption, this.deadZoneOption); this.list.addOptionEntry(this.invertsRightXAxis, this.invertsRightYAxis); - this.list.addSingleOptionEntry(this.unfocusedInputOption); + this.list.addOptionEntry(this.unfocusedInputOption, this.virtualMouseOption); + this.list.addSingleOptionEntry(this.virtualMouseSkinOption); this.list.addSingleOptionEntry(new ReloadControllerMappingsOption()); // HUD options this.list.addSingleOptionEntry(new SpruceSeparatorOption("lambdacontrols.menu.title.hud", true, null)); diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/mixin/MinecraftClientMixin.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/mixin/MinecraftClientMixin.java index 874d53c..d5ee3f5 100644 --- a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/mixin/MinecraftClientMixin.java +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/mixin/MinecraftClientMixin.java @@ -12,12 +12,14 @@ package me.lambdaurora.lambdacontrols.client.mixin; import me.lambdaurora.lambdacontrols.LambdaControlsFeature; import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; import me.lambdaurora.lambdacontrols.client.LambdaInput; +import me.lambdaurora.lambdacontrols.client.gui.LambdaControlsRenderer; import me.lambdaurora.lambdacontrols.client.util.FrontBlockPlaceResultAccessor; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.client.network.ClientPlayerInteractionManager; import net.minecraft.client.render.GameRenderer; +import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.world.ClientWorld; import net.minecraft.item.BlockItem; import net.minecraft.item.ItemStack; @@ -128,6 +130,11 @@ public abstract class MinecraftClientMixin implements FrontBlockPlaceResultAcces LambdaControlsClient.get().onRender((MinecraftClient) (Object) (this)); } + @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/GameRenderer;render(FJZ)V", shift = At.Shift.AFTER)) + private void renderVirtualCursor(boolean fullRender, CallbackInfo ci) { + LambdaControlsRenderer.renderVirtualCursor(new MatrixStack(), (MinecraftClient) (Object) this); + } + @Inject(method = "disconnect(Lnet/minecraft/client/gui/screen/Screen;)V", at = @At("RETURN")) private void onLeave(@Nullable Screen screen, CallbackInfo ci) { diff --git a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/mixin/MouseMixin.java b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/mixin/MouseMixin.java index d168f56..61bf4db 100644 --- a/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/mixin/MouseMixin.java +++ b/fabric/src/main/java/me/lambdaurora/lambdacontrols/client/mixin/MouseMixin.java @@ -11,6 +11,7 @@ package me.lambdaurora.lambdacontrols.client.mixin; import me.lambdaurora.lambdacontrols.ControlsMode; import me.lambdaurora.lambdacontrols.client.LambdaControlsClient; +import me.lambdaurora.lambdacontrols.client.LambdaControlsConfig; import me.lambdaurora.lambdacontrols.client.util.MouseAccessor; import net.minecraft.client.Mouse; import org.spongepowered.asm.mixin.Mixin; @@ -31,7 +32,8 @@ public abstract class MouseMixin implements MouseAccessor @Inject(method = "lockCursor", at = @At("HEAD"), cancellable = true) private void onMouseLocked(CallbackInfo ci) { - if (LambdaControlsClient.get().config.getControlsMode() == ControlsMode.TOUCHSCREEN) + LambdaControlsConfig config = LambdaControlsClient.get().config; + if (config.getControlsMode() == ControlsMode.TOUCHSCREEN || config.hasVirtualMouse()) ci.cancel(); } } diff --git a/fabric/src/main/resources/assets/lambdacontrols/lang/en_us.json b/fabric/src/main/resources/assets/lambdacontrols/lang/en_us.json index 37658d3..3647f38 100644 --- a/fabric/src/main/resources/assets/lambdacontrols/lang/en_us.json +++ b/fabric/src/main/resources/assets/lambdacontrols/lang/en_us.json @@ -100,6 +100,8 @@ "lambdacontrols.menu.title.hud": "HUD Options", "lambdacontrols.menu.unbound": "Unbound", "lambdacontrols.menu.unfocused_input": "Unfocused Input", + "lambdacontrols.menu.virtual_mouse": "Virtual Mouse", + "lambdacontrols.menu.virtual_mouse.skin": "Virtual Mouse Skin", "lambdacontrols.narrator.unbound": "Unbound %s", "lambdacontrols.not_bound": "Not bound", "lambdacontrols.tooltip.auto_switch_mode": "If the controls mode should be switched to Controller automatically if one is connected.", @@ -116,5 +118,10 @@ "lambdacontrols.tooltip.mouse_speed": "The controller's emulated mouse speed.", "lambdacontrols.tooltip.rotation_speed": "The camera rotation speed in controller mode.", "lambdacontrols.tooltip.reload_controller_mappings": "Reloads the controller mappings file.", - "lambdacontrols.tooltip.unfocused_input": "Allow controller input when the window is not focused." + "lambdacontrols.tooltip.unfocused_input": "Allow controller input when the window is not focused.", + "lambdacontrols.tooltip.virtual_mouse": "Enable the virtual mouse which is handful in the case of a splitscreen.", + "lambdacontrols.virtual_mouse.skin.default_light": "Default Light", + "lambdacontrols.virtual_mouse.skin.default_dark": "Default Dark", + "lambdacontrols.virtual_mouse.skin.second_light": "Second Light", + "lambdacontrols.virtual_mouse.skin.second_dark": "Second Dark" } \ No newline at end of file diff --git a/fabric/src/main/resources/assets/lambdacontrols/lang/fr_ca.json b/fabric/src/main/resources/assets/lambdacontrols/lang/fr_ca.json index 6ae0610..fac99fd 100644 --- a/fabric/src/main/resources/assets/lambdacontrols/lang/fr_ca.json +++ b/fabric/src/main/resources/assets/lambdacontrols/lang/fr_ca.json @@ -99,6 +99,8 @@ "lambdacontrols.menu.title.hud": "Options du HUD", "lambdacontrols.menu.unbound": "Délier", "lambdacontrols.menu.unfocused_input": "Entrée en fond", + "lambdacontrols.menu.virtual_mouse": "Souris virtuelle", + "lambdacontrols.menu.virtual_mouse.skin": "Apparence souris virtuelle", "lambdacontrols.narrator.unbound": "Délier %s", "lambdacontrols.not_bound": "Non défini", "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.", @@ -114,5 +116,10 @@ "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.", - "lambdacontrols.tooltip.unfocused_input": "Autorise les entrées manette quand la fenêtre n'est pas sélectionnée." + "lambdacontrols.tooltip.unfocused_input": "Autorise les entrées manette quand la fenêtre n'est pas sélectionnée.", + "lambdacontrols.tooltip.virtual_mouse": "Active la souris virtuelle qui est pratique dans le cas d'un écran partagé.", + "lambdacontrols.virtual_mouse.skin.default_light": "défaut clair", + "lambdacontrols.virtual_mouse.skin.default_dark": "défaut foncé", + "lambdacontrols.virtual_mouse.skin.second_light": "second clair", + "lambdacontrols.virtual_mouse.skin.second_dark": "second foncé" } \ No newline at end of file diff --git a/fabric/src/main/resources/assets/lambdacontrols/lang/fr_fr.json b/fabric/src/main/resources/assets/lambdacontrols/lang/fr_fr.json index 6ae0610..fac99fd 100644 --- a/fabric/src/main/resources/assets/lambdacontrols/lang/fr_fr.json +++ b/fabric/src/main/resources/assets/lambdacontrols/lang/fr_fr.json @@ -99,6 +99,8 @@ "lambdacontrols.menu.title.hud": "Options du HUD", "lambdacontrols.menu.unbound": "Délier", "lambdacontrols.menu.unfocused_input": "Entrée en fond", + "lambdacontrols.menu.virtual_mouse": "Souris virtuelle", + "lambdacontrols.menu.virtual_mouse.skin": "Apparence souris virtuelle", "lambdacontrols.narrator.unbound": "Délier %s", "lambdacontrols.not_bound": "Non défini", "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.", @@ -114,5 +116,10 @@ "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.", - "lambdacontrols.tooltip.unfocused_input": "Autorise les entrées manette quand la fenêtre n'est pas sélectionnée." + "lambdacontrols.tooltip.unfocused_input": "Autorise les entrées manette quand la fenêtre n'est pas sélectionnée.", + "lambdacontrols.tooltip.virtual_mouse": "Active la souris virtuelle qui est pratique dans le cas d'un écran partagé.", + "lambdacontrols.virtual_mouse.skin.default_light": "défaut clair", + "lambdacontrols.virtual_mouse.skin.default_dark": "défaut foncé", + "lambdacontrols.virtual_mouse.skin.second_light": "second clair", + "lambdacontrols.virtual_mouse.skin.second_dark": "second foncé" } \ No newline at end of file diff --git a/fabric/src/main/resources/config.toml b/fabric/src/main/resources/config.toml index 4ac0d55..cea7cc0 100644 --- a/fabric/src/main/resources/config.toml +++ b/fabric/src/main/resources/config.toml @@ -49,6 +49,10 @@ auto_switch_mode = false invert_right_y_axis = false # Allow unfocused input. unfocused_input = false + # Virtual mouse. + virtual_mouse = false + # Virtual mouse skin + virtual_mouse_skin = "default_light" # Controller controls. [controller.controls] # Attack control.