From 233ae363436736c975072f6ddb7ef66ee7976a3d Mon Sep 17 00:00:00 2001 From: Motschen Date: Mon, 2 Oct 2023 20:33:12 +0200 Subject: [PATCH] Even more touchscreen improvements - Fixed #222 Touch-specific improvements - Interactive items can now be used correctly - Drop button now works - Most Keybinds will now work correctly while in touchscreen mode - Added Touch category to simple options screen --- .../client/MidnightControlsConfig.java | 7 +- .../client/controller/InputHandlers.java | 2 + .../gui/MidnightControlsSettingsScreen.java | 40 +++++++- .../client/gui/TouchscreenOverlay.java | 96 +++++++++++++----- .../client/mixin/GameRendererMixin.java | 3 - .../client/mixin/KeyboardMixin.java | 18 ++++ .../client/mixin/MinecraftClientMixin.java | 13 ++- .../client/mixin/ScreenMixin.java | 8 +- .../client/touch/TouchMode.java | 14 ++- .../client/touch/TouchUtils.java | 6 ++ .../client/touch/gui/ItemUseButtonWidget.java | 43 ++++++++ .../gui}/SilentTexturedButtonWidget.java | 2 +- .../assets/midnightcontrols/lang/en_us.json | 12 +++ .../gui/sprites/binding/debug_screen.png | Bin 0 -> 182 bytes .../resources/midnightcontrols.mixins.json | 3 +- 15 files changed, 218 insertions(+), 49 deletions(-) create mode 100644 src/main/java/eu/midnightdust/midnightcontrols/client/mixin/KeyboardMixin.java create mode 100644 src/main/java/eu/midnightdust/midnightcontrols/client/touch/gui/ItemUseButtonWidget.java rename src/main/java/eu/midnightdust/midnightcontrols/client/{gui/widget => touch/gui}/SilentTexturedButtonWidget.java (97%) create mode 100644 src/main/resources/assets/midnightcontrols/textures/gui/sprites/binding/debug_screen.png diff --git a/src/main/java/eu/midnightdust/midnightcontrols/client/MidnightControlsConfig.java b/src/main/java/eu/midnightdust/midnightcontrols/client/MidnightControlsConfig.java index 7123955..af96a6b 100644 --- a/src/main/java/eu/midnightdust/midnightcontrols/client/MidnightControlsConfig.java +++ b/src/main/java/eu/midnightdust/midnightcontrols/client/MidnightControlsConfig.java @@ -83,12 +83,15 @@ public class MidnightControlsConfig extends MidnightConfig { @Entry(category = "screens", name = "Arrow screens") public static List arrowScreens = Lists.newArrayList(ChatScreen.class.getCanonicalName()); @Entry(category = "screens", name = "WASD screens") public static List wasdScreens = Lists.newArrayList("com.ultreon.devices.core.Laptop"); @Entry(category = "touch", name = "Screens with close button") public static List closeButtonScreens = Lists.newArrayList(ChatScreen.class.getCanonicalName(), AdvancementsScreen.class.getCanonicalName(), RingScreen.class.getCanonicalName()); - @Entry(category = "touch", name = "midnightcontrols.menu.touch_speed", isSlider = true, min = 0, max = 150, precision = 10) public static double touchSpeed = 25.0; + @Entry(category = "touch", name = "midnightcontrols.menu.touch_speed", isSlider = true, min = 0, max = 150, precision = 10) public static double touchSpeed = 50.0; + @Entry(category = "touch", name = "midnightcontrols.menu.invert_touch") public static boolean invertTouch = false; @Entry(category = "touch", name = "midnightcontrols.menu.touch_mode") public static TouchMode touchMode = TouchMode.CROSSHAIR; + @Entry(category = "touch", name = "midnightcontrols.menu.touch_break_delay", isSlider = true, min = 50, max = 500) public static int touchBreakDelay = 120; @Entry(category = "touch", name = "midnightcontrols.menu.touch_transparency", isSlider = true, min = 0, max = 100) public static int touchTransparency = 75; @Entry(category = "touch", name = "Touch Outline Color", isColor = true) public static String touchOutlineColorHex = "#ffffff"; @Entry(category = "touch", name = "Touch Outline Alpha", isSlider = true, min = 0, max = 255) public static int touchOutlineColorAlpha = 150; - @Entry(category = "touch", name = "Left Touch button bindings") public static List leftTouchBinds = Lists.newArrayList("controls_ring","debug_screen"); + @Entry(category = "touch", name = "Left Touch button bindings") public static List leftTouchBinds = Lists.newArrayList("debug_screen", "screenshot","toggle_perspective"); + @Entry(category = "touch", name = "Right Touch button bindings") public static List rightTouchBinds = Lists.newArrayList("screenshot","toggle_perspective", "use"); @Entry @Hidden public static Map BINDING = new HashMap<>(); diff --git a/src/main/java/eu/midnightdust/midnightcontrols/client/controller/InputHandlers.java b/src/main/java/eu/midnightdust/midnightcontrols/client/controller/InputHandlers.java index d917f91..ca320eb 100644 --- a/src/main/java/eu/midnightdust/midnightcontrols/client/controller/InputHandlers.java +++ b/src/main/java/eu/midnightdust/midnightcontrols/client/controller/InputHandlers.java @@ -191,6 +191,8 @@ public class InputHandlers { } public static PressAction handlePage(boolean next) { return (client, button, value, action) -> { + if (action == ButtonState.RELEASE) + return false; if (client.currentScreen instanceof CreativeInventoryScreen) { try { return client.currentScreen.children().stream().filter(element -> element instanceof PressableWidget) diff --git a/src/main/java/eu/midnightdust/midnightcontrols/client/gui/MidnightControlsSettingsScreen.java b/src/main/java/eu/midnightdust/midnightcontrols/client/gui/MidnightControlsSettingsScreen.java index 70fa1a4..1831d0c 100644 --- a/src/main/java/eu/midnightdust/midnightcontrols/client/gui/MidnightControlsSettingsScreen.java +++ b/src/main/java/eu/midnightdust/midnightcontrols/client/gui/MidnightControlsSettingsScreen.java @@ -143,6 +143,12 @@ public class MidnightControlsSettingsScreen extends SpruceScreen { Text.translatable(key.concat(".tooltip")) ); } + // Touch options + private final SpruceOption touchSpeedOption; + private final SpruceOption touchBreakDelayOption; + private final SpruceOption invertTouchOption; + private final SpruceOption touchTransparencyOption; + private final SpruceOption touchModeOption; private final MutableText controllerMappingsUrlText = Text.literal("(") .append(Text.literal(GAMEPAD_TOOL_URL).formatted(Formatting.GOLD)) @@ -191,7 +197,7 @@ public class MidnightControlsSettingsScreen extends SpruceScreen { this.mouseSpeedOption = new SpruceDoubleOption("midnightcontrols.menu.mouse_speed", 0.0, 150.0, .5f, () -> MidnightControlsConfig.mouseSpeed, value -> MidnightControlsConfig.mouseSpeed = value, option -> option.getDisplayText(Text.literal(String.valueOf(option.get()))), - Text.translatable("midnightcontrols.menu.joystick_as_mouse.tooltip")); + Text.translatable("midnightcontrols.menu.mouse_speed.tooltip")); this.joystickAsMouseOption = new SpruceToggleBooleanOption("midnightcontrols.menu.joystick_as_mouse", () -> MidnightControlsConfig.joystickAsMouse, value -> MidnightControlsConfig.joystickAsMouse = value, Text.translatable("midnightcontrols.menu.joystick_as_mouse.tooltip")); @@ -284,6 +290,25 @@ public class MidnightControlsSettingsScreen extends SpruceScreen { value -> MidnightControlsConfig.virtualMouse = value, Text.translatable("midnightcontrols.menu.virtual_mouse.tooltip")); this.hideCursorOption = new SpruceToggleBooleanOption("midnightcontrols.menu.hide_cursor", () -> MidnightControlsConfig.hideNormalMouse, value -> MidnightControlsConfig.hideNormalMouse = value, Text.translatable("midnightcontrols.menu.hide_cursor.tooltip")); + // Touch options + this.touchModeOption = new SpruceCyclingOption("midnightcontrols.menu.touch_mode", + amount -> MidnightControlsConfig.touchMode = MidnightControlsConfig.touchMode.next(), + option -> option.getDisplayText(MidnightControlsConfig.touchMode.getTranslatedText()), + Text.translatable("midnightcontrols.menu.touch_mode.tooltip")); + this.touchSpeedOption = new SpruceDoubleOption("midnightcontrols.menu.touch_speed", 0.0, 150.0, .5f, + () -> MidnightControlsConfig.touchSpeed, + value -> MidnightControlsConfig.touchSpeed = value, option -> option.getDisplayText(Text.literal(String.valueOf(option.get()))), + Text.translatable("midnightcontrols.menu.touch_speed.tooltip")); + this.touchBreakDelayOption = new SpruceDoubleOption("midnightcontrols.menu.touch_break_delay", 50, 500, 1f, + () -> (double) MidnightControlsConfig.touchBreakDelay, + value -> MidnightControlsConfig.touchBreakDelay = value.intValue(), option -> option.getDisplayText(Text.literal(String.valueOf(option.get()))), + Text.translatable("midnightcontrols.menu.touch_break_delay.tooltip")); + this.touchTransparencyOption = new SpruceDoubleOption("midnightcontrols.menu.touch_transparency", 0, 100, 1f, + () -> (double) MidnightControlsConfig.touchTransparency, + value -> MidnightControlsConfig.touchTransparency = value.intValue(), option -> option.getDisplayText(Text.literal(String.valueOf(option.get()))), + Text.translatable("midnightcontrols.menu.touch_break_delay.tooltip")); + this.invertTouchOption = new SpruceToggleBooleanOption("midnightcontrols.menu.invert_touch", () -> MidnightControlsConfig.invertTouch, + value -> MidnightControlsConfig.invertTouch = value, Text.translatable("midnightcontrols.menu.invert_touch.tooltip")); } @Override @@ -337,6 +362,8 @@ public class MidnightControlsSettingsScreen extends SpruceScreen { tabs.addSeparatorEntry(Text.translatable("midnightcontrols.menu.separator.controller")); tabs.addTabEntry(Text.translatable("midnightcontrols.menu.title.controller"), null, this::buildControllerTab); + tabs.addTabEntry(Text.translatable("midnightcontrols.menu.title.touch"), null, + this::buildTouchTab); tabs.addTabEntry(Text.translatable("midnightcontrols.menu.title.mappings.string"), null, this::buildMappingsStringEditorTab); } @@ -431,6 +458,17 @@ public class MidnightControlsSettingsScreen extends SpruceScreen { root.addChild(labels); return root; } + public SpruceOptionListWidget buildTouchTab(int width, int height) { + var list = new SpruceOptionListWidget(Position.origin(), width, height); + list.setBackground(new MidnightControlsBackground(130)); + list.addSingleOptionEntry(this.touchSpeedOption); + list.addSingleOptionEntry(this.invertTouchOption); + list.addSingleOptionEntry(new SpruceSeparatorOption("midnightcontrols.menu.title.hud", true, null)); + list.addSingleOptionEntry(this.touchModeOption); + list.addSingleOptionEntry(this.touchBreakDelayOption); + list.addSingleOptionEntry(this.touchTransparencyOption); + return list; + } public SpruceContainerWidget buildMappingsStringEditorTab(int width, int height) { return new MappingsStringInputWidget(Position.origin(), width, height); diff --git a/src/main/java/eu/midnightdust/midnightcontrols/client/gui/TouchscreenOverlay.java b/src/main/java/eu/midnightdust/midnightcontrols/client/gui/TouchscreenOverlay.java index 6d3aaf5..e89cbd9 100644 --- a/src/main/java/eu/midnightdust/midnightcontrols/client/gui/TouchscreenOverlay.java +++ b/src/main/java/eu/midnightdust/midnightcontrols/client/gui/TouchscreenOverlay.java @@ -12,7 +12,6 @@ package eu.midnightdust.midnightcontrols.client.gui; import dev.lambdaurora.spruceui.Position; import dev.lambdaurora.spruceui.widget.SpruceButtonWidget; import eu.midnightdust.lib.util.PlatformFunctions; -import eu.midnightdust.midnightcontrols.MidnightControls; import eu.midnightdust.midnightcontrols.MidnightControlsConstants; import eu.midnightdust.midnightcontrols.client.ButtonState; import eu.midnightdust.midnightcontrols.client.HudSide; @@ -21,35 +20,33 @@ import eu.midnightdust.midnightcontrols.client.MidnightControlsConfig; import eu.midnightdust.midnightcontrols.client.compat.EmotecraftCompat; import eu.midnightdust.midnightcontrols.client.controller.ButtonBinding; import eu.midnightdust.midnightcontrols.client.controller.InputManager; -import eu.midnightdust.midnightcontrols.client.gui.widget.SilentTexturedButtonWidget; +import eu.midnightdust.midnightcontrols.client.touch.gui.ItemUseButtonWidget; +import eu.midnightdust.midnightcontrols.client.touch.gui.SilentTexturedButtonWidget; import eu.midnightdust.midnightcontrols.client.touch.TouchUtils; import eu.midnightdust.midnightcontrols.client.util.KeyBindingAccessor; -import io.github.kosmx.emotes.arch.gui.EmoteMenuImpl; import net.minecraft.block.BlockState; -import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.screen.*; import net.minecraft.client.gui.screen.ingame.InventoryScreen; import net.minecraft.client.gui.widget.TextIconButtonWidget; import net.minecraft.client.option.KeyBinding; +import net.minecraft.client.texture.MissingSprite; +import net.minecraft.client.texture.Sprite; import net.minecraft.client.util.InputUtil; -import net.minecraft.item.ItemStack; +import net.minecraft.item.*; import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket; import net.minecraft.text.Text; -import net.minecraft.util.Arm; -import net.minecraft.util.Identifier; +import net.minecraft.util.*; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.hit.EntityHitResult; import net.minecraft.util.hit.HitResult; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; -import net.minecraft.util.math.MathHelper; import org.jetbrains.annotations.NotNull; import org.lwjgl.glfw.GLFW; +import java.util.List; import java.util.Objects; -import java.util.Timer; -import java.util.TimerTask; import static org.lwjgl.glfw.GLFW.GLFW_GAMEPAD_AXIS_RIGHT_X; import static org.lwjgl.glfw.GLFW.GLFW_GAMEPAD_AXIS_RIGHT_Y; @@ -63,6 +60,7 @@ public class TouchscreenOverlay extends Screen { private SilentTexturedButtonWidget inventoryButton; private SilentTexturedButtonWidget swapHandsButton; private SilentTexturedButtonWidget dropButton; + private ItemUseButtonWidget useButton; private SilentTexturedButtonWidget jumpButton; private SilentTexturedButtonWidget flyButton; private SilentTexturedButtonWidget flyUpButton; @@ -118,6 +116,7 @@ public class TouchscreenOverlay extends Screen { private void updateJumpButtons() { assert this.client != null; assert this.client.player != null; + float transparency = MidnightControlsConfig.touchTransparency / 100f; if (this.client.player.getAbilities().flying) { boolean oldStateFly = this.flyButton.isVisible(); @@ -125,6 +124,9 @@ public class TouchscreenOverlay extends Screen { this.flyButton.setVisible(true); this.flyUpButton.setVisible(true); this.flyDownButton.setVisible(true); + this.flyButton.setAlpha(transparency); + this.flyUpButton.setAlpha(transparency); + this.flyDownButton.setAlpha(transparency); if (oldStateFly != this.flyButton.isVisible()) { this.flyButtonEnableTicks = 5; this.setJump(false); @@ -135,6 +137,7 @@ public class TouchscreenOverlay extends Screen { this.flyButton.setVisible(false); this.flyUpButton.setVisible(false); this.flyDownButton.setVisible(false); + this.jumpButton.setAlpha(transparency); } } @@ -217,8 +220,14 @@ public class TouchscreenOverlay extends Screen { } },0, 160, 20, WIDGETS_LOCATION)); // Drop - this.addDrawableChild(this.dropButton = new SilentTexturedButtonWidget(Position.of(swapHandsX, sneakButtonY + 5 + 20), 20, 20, Text.empty(), btn -> - client.player.getInventory().dropSelectedItem(false), 20, 160, 20, WIDGETS_LOCATION)); + this.addDrawableChild(this.dropButton = new SilentTexturedButtonWidget(Position.of(swapHandsX, sneakButtonY + 5 + 20), 20, 20, Text.empty(), btn -> { + if (btn.isActive() && !client.player.isSpectator() && client.player.dropSelectedItem(false)) { + client.player.swingHand(Hand.MAIN_HAND); + } + }, 20, 160, 20, WIDGETS_LOCATION)); + // Use + this.addDrawableChild(this.useButton = new ItemUseButtonWidget(Position.of(width/2-25, height - 70), 50, 17, Text.translatable(MidnightControlsConstants.NAMESPACE+".action.eat"), btn -> + client.interactionManager.interactItem(client.player, client.player.getActiveHand()))); // Jump keys this.addDrawableChild(this.jumpButton = new SilentTexturedButtonWidget(Position.of(jumpButtonX, sneakButtonY), 20, 20, Text.empty(), this::handleJump, 0, 40, 20, WIDGETS_LOCATION)); this.addDrawableChild(this.flyButton = new SilentTexturedButtonWidget(Position.of(jumpButtonX, sneakButtonY), 20, 20, Text.empty(),btn -> { @@ -277,29 +286,37 @@ public class TouchscreenOverlay extends Screen { this.addDrawableChild(this.leftButton = new SilentTexturedButtonWidget(Position.of(sneakButtonX - 20 - 5, sneakButtonY), 20, 20, Text.empty(), btn -> ((KeyBindingAccessor) this.client.options.leftKey).midnightcontrols$handlePressState(btn.isActive()), 60, 80, 20, WIDGETS_LOCATION )); - Identifier emptySprite = new Identifier(MidnightControlsConstants.NAMESPACE, "touch/empty"); - for (int i = 0; i < MidnightControlsConfig.leftTouchBinds.size(); i++) { - String bindName = MidnightControlsConfig.leftTouchBinds.get(i); - ButtonBinding binding = InputManager.getBinding(bindName); - if (binding == null) continue; - boolean hasTexture = client.getTextureManager().getOrDefault(new Identifier(MidnightControlsConstants.NAMESPACE, "textures/gui/sprites/icon/"+bindName+".png"), null) != null; - var button = TextIconButtonWidget.builder(Text.translatable(binding.getTranslationKey()), b -> binding.handle(client, 1, ButtonState.PRESS), false) - .texture(hasTexture ? new Identifier(MidnightControlsConstants.NAMESPACE, "icon/"+bindName) : emptySprite, 20, 20).dimension(20, 20).build(); - button.setPosition(i > 1 ? 3 : 3+(i*23), 3); - button.setAlpha(MidnightControlsConfig.touchTransparency / 100f); - this.addDrawableChild(button); - } + initCustomButtons(true); + initCustomButtons(false); this.setButtonProperties(MidnightControlsConfig.touchTransparency / 100f); TouchscreenOverlay.instance = this; } + private void initCustomButtons(boolean left) { + assert client != null; + Identifier emptySprite = new Identifier(MidnightControlsConstants.NAMESPACE, "touch/empty"); + List list = left ? MidnightControlsConfig.leftTouchBinds : MidnightControlsConfig.rightTouchBinds; + Sprite missingSprite = client.getGuiAtlasManager().getSprite(MissingSprite.getMissingSpriteId()); + for (int i = 0; i < list.size(); i++) { + String bindName = list.get(i); + ButtonBinding binding = InputManager.getBinding(bindName); + if (binding == null) continue; + boolean hasTexture = client.getGuiAtlasManager().getSprite(new Identifier(MidnightControlsConstants.NAMESPACE, "binding/"+bindName)) != missingSprite; + if (MidnightControlsConfig.debug) System.out.println(left +" "+new Identifier(MidnightControlsConstants.NAMESPACE, "binding/"+bindName)+" "+ hasTexture); + var button = TextIconButtonWidget.builder(Text.translatable("binding.getTranslationKey()"), b -> binding.handle(client, 1, ButtonState.PRESS), hasTexture) + .texture(hasTexture ? new Identifier(MidnightControlsConstants.NAMESPACE, "binding/"+bindName) : emptySprite, 20, 20).dimension(20, 20).build(); + button.setPosition(left ? (3+(i*23)) : this.width-(23+(i*23)), 3); + button.setAlpha(MidnightControlsConfig.touchTransparency / 100f); + this.addDrawableChild(button); + } + } private void setButtonProperties(float transparency) { this.inventoryButton.setAlpha(transparency); this.dropButton.setAlpha(transparency); this.swapHandsButton.setAlpha(transparency); this.jumpButton.setAlpha(transparency); this.flyButton.setAlpha(transparency); - this.flyUpButton.setAlpha(transparency); + this.flyUpButton.setAlpha(transparency);this.useButton.setAlpha(Math.min(transparency+0.1f, 1.0f)); this.flyDownButton.setAlpha(transparency); this.startSneakButton.setAlpha(transparency); this.endSneakButton.setAlpha(transparency); @@ -309,6 +326,7 @@ public class TouchscreenOverlay extends Screen { this.leftButton.setAlpha(transparency); this.rightButton.setAlpha(transparency); this.backButton.setAlpha(transparency); + this.useButton.setAlpha(Math.min(transparency+0.1f, 1.0f)); this.endSneakButton.setVisible(false); this.forwardLeftButton.setVisible(false); this.forwardRightButton.setVisible(false); @@ -318,6 +336,7 @@ public class TouchscreenOverlay extends Screen { public void tick() { assert this.client != null; assert this.client.interactionManager != null; + assert this.client.player != null; if (this.forwardButtonTick > 0) { --this.forwardButtonTick; @@ -325,10 +344,11 @@ public class TouchscreenOverlay extends Screen { this.forwardLeftButton.setVisible(false); this.forwardRightButton.setVisible(false); } + this.useButton.setVisible(client.player.getMainHandStack() != null && (client.player.getMainHandStack().getUseAction() != UseAction.NONE || client.player.getMainHandStack().getItem() instanceof ArmorItem) && !TouchUtils.hasInWorldUseAction(client.player.getMainHandStack())); this.updateJumpButtons(); double scaleFactor = client.getWindow().getScaleFactor(); - if (clickStartTime > 0 && System.currentTimeMillis() - clickStartTime >= 100) this.mouseHeldDown(client.mouse.getX() / scaleFactor, client.mouse.getY() / scaleFactor); + if (clickStartTime > 0 && System.currentTimeMillis() - clickStartTime >= MidnightControlsConfig.touchBreakDelay) this.mouseHeldDown(client.mouse.getX() / scaleFactor, client.mouse.getY() / scaleFactor); else client.interactionManager.cancelBlockBreaking(); } @@ -361,9 +381,15 @@ public class TouchscreenOverlay extends Screen { assert client.world != null; assert client.interactionManager != null; clickStartTime = -1; + + if (client.player.getMainHandStack() != null && TouchUtils.hasInWorldUseAction(client.player.getMainHandStack())) { + client.interactionManager.stopUsingItem(client.player); + return true; + } HitResult result = TouchUtils.getTargettedObject(mouseX, mouseY); if (result == null) return false; + if (result instanceof BlockHitResult blockHit) { BlockPos blockPos = blockHit.getBlockPos().offset(blockHit.getSide()); BlockState state = client.world.getBlockState(blockPos); @@ -385,6 +411,7 @@ public class TouchscreenOverlay extends Screen { } if (result instanceof EntityHitResult entityHit) { client.interactionManager.attackEntity(client.player, entityHit.getEntity()); + client.player.swingHand(Hand.MAIN_HAND); } } clickStartTime = -1; @@ -395,15 +422,24 @@ public class TouchscreenOverlay extends Screen { assert client.player != null; assert client.interactionManager != null; if (!isDragging()) { + if (client.player.getMainHandStack() != null && TouchUtils.hasInWorldUseAction(client.player.getMainHandStack())) { + client.interactionManager.interactItem(client.player, client.player.getActiveHand()); + return; + } HitResult result = TouchUtils.getTargettedObject(mouseX, mouseY); if (result == null || firstHitResult == null) return; + if (result instanceof BlockHitResult blockHit && firstHitResult instanceof BlockHitResult firstBlock && blockHit.getBlockPos().equals(firstBlock.getBlockPos())) { if (MidnightControlsConfig.debug) System.out.println(blockHit.getBlockPos().toString()); - client.interactionManager.updateBlockBreakingProgress(blockHit.getBlockPos(), blockHit.getSide()); + if (client.interactionManager.updateBlockBreakingProgress(blockHit.getBlockPos(), blockHit.getSide())) { + client.player.swingHand(Hand.MAIN_HAND); + } else client.interactionManager.cancelBlockBreaking(); firstHitResult = TouchUtils.getTargettedObject(mouseX, mouseY); } else if (result instanceof EntityHitResult entityHit && firstHitResult instanceof EntityHitResult firstEntity && entityHit.getEntity().getUuid().compareTo(firstEntity.getEntity().getUuid()) == 0) { - client.interactionManager.interactEntity(client.player, entityHit.getEntity(), client.player.getActiveHand()); + if (client.interactionManager.interactEntity(client.player, entityHit.getEntity(), client.player.getActiveHand()) == ActionResult.SUCCESS) { + client.player.swingHand(Hand.MAIN_HAND); + } firstHitResult = TouchUtils.getTargettedObject(mouseX, mouseY); } } @@ -412,6 +448,10 @@ public class TouchscreenOverlay extends Screen { @Override public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { if (button == GLFW.GLFW_MOUSE_BUTTON_1 && this.client != null) { + if (!MidnightControlsConfig.invertTouch) { + deltaX = -deltaX; + deltaY = -deltaY; + } if (deltaY > 0.01) this.mod.input.handleLook(this.client, GLFW_GAMEPAD_AXIS_RIGHT_Y, (float) Math.abs((deltaY / 3.0)*MidnightControlsConfig.touchSpeed/100), 2); else this.mod.input.handleLook(this.client, GLFW_GAMEPAD_AXIS_RIGHT_Y, (float) Math.abs((deltaY / 3.0)*MidnightControlsConfig.touchSpeed/100), 1); diff --git a/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/GameRendererMixin.java b/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/GameRendererMixin.java index 036dcb3..082da55 100644 --- a/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/GameRendererMixin.java +++ b/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/GameRendererMixin.java @@ -14,14 +14,11 @@ import eu.midnightdust.midnightcontrols.ControlsMode; import eu.midnightdust.midnightcontrols.client.MidnightControlsClient; import eu.midnightdust.midnightcontrols.client.MidnightControlsConfig; import eu.midnightdust.midnightcontrols.client.gui.MidnightControlsRenderer; -import eu.midnightdust.midnightcontrols.client.gui.TouchscreenOverlay; import eu.midnightdust.midnightcontrols.client.touch.TouchUtils; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.render.GameRenderer; -import net.minecraft.client.util.Window; import net.minecraft.client.util.math.MatrixStack; -import org.joml.Matrix4f; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; diff --git a/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/KeyboardMixin.java b/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/KeyboardMixin.java new file mode 100644 index 0000000..7bc6a2e --- /dev/null +++ b/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/KeyboardMixin.java @@ -0,0 +1,18 @@ +package eu.midnightdust.midnightcontrols.client.mixin; + +import eu.midnightdust.midnightcontrols.client.gui.TouchscreenOverlay; +import net.minecraft.client.Keyboard; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.screen.Screen; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(Keyboard.class) +public class KeyboardMixin { + @Redirect(method = "onKey", at = @At(value = "FIELD", target = "Lnet/minecraft/client/MinecraftClient;currentScreen:Lnet/minecraft/client/gui/screen/Screen;")) + private Screen midnightcontrols$ignoreTouchOverlay(MinecraftClient instance) { + if (instance.currentScreen instanceof TouchscreenOverlay) return null; + return instance.currentScreen; + } +} diff --git a/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/MinecraftClientMixin.java b/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/MinecraftClientMixin.java index 6a4f275..daa4b7e 100644 --- a/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/MinecraftClientMixin.java +++ b/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/MinecraftClientMixin.java @@ -9,21 +9,15 @@ package eu.midnightdust.midnightcontrols.client.mixin; -import eu.midnightdust.midnightcontrols.MidnightControls; import eu.midnightdust.midnightcontrols.MidnightControlsFeature; import eu.midnightdust.midnightcontrols.client.MidnightControlsClient; import eu.midnightdust.midnightcontrols.client.MidnightControlsConfig; -import eu.midnightdust.midnightcontrols.client.MidnightInput; -import eu.midnightdust.midnightcontrols.client.gui.MidnightControlsRenderer; import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.client.network.ClientPlayerInteractionManager; import net.minecraft.client.render.BufferBuilderStorage; 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; import net.minecraft.util.ActionResult; @@ -35,7 +29,6 @@ import net.minecraft.util.math.Direction; import net.minecraft.util.math.Vec3d; import org.jetbrains.annotations.Nullable; import org.lwjgl.glfw.GLFW; -import org.objectweb.asm.Opcodes; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -157,4 +150,10 @@ public abstract class MinecraftClientMixin { } } } + // This is always supposed to be located at before the line 'this.profiler.swap("Keybindings");' +// @Redirect(method = "tick", at = @At(value = "FIELD",target = "Lnet/minecraft/client/MinecraftClient;currentScreen:Lnet/minecraft/client/gui/screen/Screen;", ordinal = 6)) +// private Screen midnightcontrols$ignoreTouchOverlay(MinecraftClient instance) { +// if (instance.currentScreen instanceof TouchscreenOverlay) return null; +// return instance.currentScreen; +// } } diff --git a/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/ScreenMixin.java b/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/ScreenMixin.java index 6ec8f16..ba20636 100644 --- a/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/ScreenMixin.java +++ b/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/ScreenMixin.java @@ -6,7 +6,7 @@ import eu.midnightdust.midnightcontrols.client.ButtonState; import eu.midnightdust.midnightcontrols.client.MidnightControlsConfig; import eu.midnightdust.midnightcontrols.client.controller.ButtonBinding; import eu.midnightdust.midnightcontrols.client.controller.InputHandlers; -import eu.midnightdust.midnightcontrols.client.gui.widget.SilentTexturedButtonWidget; +import eu.midnightdust.midnightcontrols.client.touch.gui.SilentTexturedButtonWidget; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.Drawable; import net.minecraft.client.gui.Element; @@ -31,10 +31,8 @@ public abstract class ScreenMixin { @Inject(method = "init(Lnet/minecraft/client/MinecraftClient;II)V", at = @At("TAIL")) public void midnightcontrols$addCloseButton(MinecraftClient client, int width, int height, CallbackInfo ci) { if (MidnightControlsConfig.controlsMode == ControlsMode.TOUCHSCREEN && (MidnightControlsConfig.closeButtonScreens.stream().anyMatch(s -> this.getClass().getName().startsWith(s) || ((Object)this) instanceof HandledScreen))) { - SilentTexturedButtonWidget closeButton = new SilentTexturedButtonWidget(Position.of(this.width - 30, 10), 20, 20, Text.empty(), btn -> - InputHandlers.handleExit().press(client, ButtonBinding.BACK, 0f, ButtonState.PRESS), 20, 160, 20, WIDGETS_LOCATION); - closeButton.setAlpha(MidnightControlsConfig.touchTransparency / 100f); - this.addDrawableChild(closeButton); + this.addDrawableChild(new SilentTexturedButtonWidget(Position.of(this.width - 30, 10), 20, 20, Text.empty(), btn -> + InputHandlers.handleExit().press(client, ButtonBinding.BACK, 0f, ButtonState.PRESS), 20, 160, 20, WIDGETS_LOCATION)); } } } diff --git a/src/main/java/eu/midnightdust/midnightcontrols/client/touch/TouchMode.java b/src/main/java/eu/midnightdust/midnightcontrols/client/touch/TouchMode.java index c6c69a8..241b850 100644 --- a/src/main/java/eu/midnightdust/midnightcontrols/client/touch/TouchMode.java +++ b/src/main/java/eu/midnightdust/midnightcontrols/client/touch/TouchMode.java @@ -1,5 +1,17 @@ package eu.midnightdust.midnightcontrols.client.touch; +import net.minecraft.text.Text; +import org.jetbrains.annotations.NotNull; + public enum TouchMode { - CROSSHAIR, FINGER_POS + CROSSHAIR, FINGER_POS; + public Text getTranslatedText() { + return Text.translatable("midnightcontrols.midnightconfig.enum."+this.getClass().getSimpleName()+"."+this.name()); + } + public @NotNull TouchMode next() { + var v = values(); + if (v.length == this.ordinal() + 1) + return v[0]; + return v[this.ordinal() + 1]; + } } diff --git a/src/main/java/eu/midnightdust/midnightcontrols/client/touch/TouchUtils.java b/src/main/java/eu/midnightdust/midnightcontrols/client/touch/TouchUtils.java index 9e622d9..ebf8aff 100644 --- a/src/main/java/eu/midnightdust/midnightcontrols/client/touch/TouchUtils.java +++ b/src/main/java/eu/midnightdust/midnightcontrols/client/touch/TouchUtils.java @@ -4,6 +4,8 @@ import eu.midnightdust.midnightcontrols.client.MidnightControlsConfig; import net.minecraft.client.MinecraftClient; import net.minecraft.client.render.Camera; import net.minecraft.entity.projectile.ProjectileUtil; +import net.minecraft.item.ItemStack; +import net.minecraft.util.UseAction; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.hit.EntityHitResult; import net.minecraft.util.hit.HitResult; @@ -57,4 +59,8 @@ public class TouchUtils { return new Vec3d(target.x, target.y, target.z).add(camera.getPos()); } + public static boolean hasInWorldUseAction(ItemStack stack) { + UseAction action = stack.getUseAction(); + return action == UseAction.BOW || action == UseAction.BRUSH || action == UseAction.SPEAR; + } } diff --git a/src/main/java/eu/midnightdust/midnightcontrols/client/touch/gui/ItemUseButtonWidget.java b/src/main/java/eu/midnightdust/midnightcontrols/client/touch/gui/ItemUseButtonWidget.java new file mode 100644 index 0000000..d3681c4 --- /dev/null +++ b/src/main/java/eu/midnightdust/midnightcontrols/client/touch/gui/ItemUseButtonWidget.java @@ -0,0 +1,43 @@ +package eu.midnightdust.midnightcontrols.client.touch.gui; + +import dev.lambdaurora.spruceui.Position; +import dev.lambdaurora.spruceui.widget.SpruceButtonWidget; +import eu.midnightdust.midnightcontrols.MidnightControlsConstants; +import eu.midnightdust.midnightcontrols.client.MidnightControlsConfig; +import net.minecraft.item.ArmorItem; +import net.minecraft.item.PotionItem; +import net.minecraft.text.Text; +import net.minecraft.util.UseAction; + +public class ItemUseButtonWidget extends SpruceButtonWidget { + + public ItemUseButtonWidget(Position position, int width, int height, Text message, PressAction action) { + super(position, width, height, message, action); + } + @Override + protected void onRelease(double mouseX, double mouseY) { + assert client.player != null; + assert client.interactionManager != null; + UseAction action = client.player.getMainHandStack().getUseAction(); + if (action == UseAction.SPYGLASS || action == UseAction.TOOT_HORN) client.interactionManager.stopUsingItem(client.player); + super.onRelease(mouseX, mouseY); + } + + @Override + public void setVisible(boolean visible) { + if (visible && client.player != null && client.player.getMainHandStack() != null) { + UseAction action = client.player.getMainHandStack().getUseAction(); + if (action == UseAction.EAT) { + this.setMessage(Text.translatable(MidnightControlsConstants.NAMESPACE+".action.eat")); + } else if (action == UseAction.DRINK) { + this.setMessage(Text.translatable(MidnightControlsConstants.NAMESPACE+".action.drink")); + } else if (client.player.getMainHandStack().getItem() instanceof ArmorItem) { + this.setMessage(Text.translatable(MidnightControlsConstants.NAMESPACE+".action.equip")); + } else if (!action.equals(UseAction.NONE)) { + this.setMessage(Text.translatable(MidnightControlsConstants.NAMESPACE+".action.use")); + } + } + this.setAlpha(MidnightControlsConfig.touchTransparency / 100f); + super.setVisible(visible); + } +} diff --git a/src/main/java/eu/midnightdust/midnightcontrols/client/gui/widget/SilentTexturedButtonWidget.java b/src/main/java/eu/midnightdust/midnightcontrols/client/touch/gui/SilentTexturedButtonWidget.java similarity index 97% rename from src/main/java/eu/midnightdust/midnightcontrols/client/gui/widget/SilentTexturedButtonWidget.java rename to src/main/java/eu/midnightdust/midnightcontrols/client/touch/gui/SilentTexturedButtonWidget.java index 013f68c..e7ae416 100644 --- a/src/main/java/eu/midnightdust/midnightcontrols/client/gui/widget/SilentTexturedButtonWidget.java +++ b/src/main/java/eu/midnightdust/midnightcontrols/client/touch/gui/SilentTexturedButtonWidget.java @@ -1,4 +1,4 @@ -package eu.midnightdust.midnightcontrols.client.gui.widget; +package eu.midnightdust.midnightcontrols.client.touch.gui; import dev.lambdaurora.spruceui.Position; import dev.lambdaurora.spruceui.widget.SpruceTexturedButtonWidget; diff --git a/src/main/resources/assets/midnightcontrols/lang/en_us.json b/src/main/resources/assets/midnightcontrols/lang/en_us.json index 11b5107..1a0a458 100644 --- a/src/main/resources/assets/midnightcontrols/lang/en_us.json +++ b/src/main/resources/assets/midnightcontrols/lang/en_us.json @@ -19,6 +19,8 @@ "midnightcontrols.midnightconfig.enum.ControlsMode.TOUCHSCREEN": "Touchscreen (WIP)", "midnightcontrols.midnightconfig.enum.HudSide.LEFT": "Left", "midnightcontrols.midnightconfig.enum.HudSide.RIGHT": "Right", + "midnightcontrols.midnightconfig.enum.TouchMode.CROSSHAIR": "At Crosshair", + "midnightcontrols.midnightconfig.enum.TouchMode.FINGER_POS": "Finger Position", "key.midnightcontrols.look_down": "Look down", "key.midnightcontrols.look_left": "Look left", "key.midnightcontrols.look_right": "Look right", @@ -30,6 +32,9 @@ "midnightcontrols.action.controls_ring": "Open Unbound Keybind Ring", "midnightcontrols.action.debug_screen": "Open Debug HUD (F3)", "midnightcontrols.action.drop_item": "Drop Item", + "midnightcontrols.action.drink": "Drink", + "midnightcontrols.action.eat": "Eat", + "midnightcontrols.action.equip": "Equip", "midnightcontrols.action.exit": "Exit Screen", "midnightcontrols.action.forward": "Forward", "midnightcontrols.action.hit": "Hit", @@ -195,7 +200,13 @@ "midnightcontrols.menu.title.general": "General Options", "midnightcontrols.menu.title.hud": "HUD Options", "midnightcontrols.menu.title.mappings.string": "Mappings File Editor", + "midnightcontrols.menu.title.touch": "Touch Options", "midnightcontrols.menu.title.visual": "Appearance Options", + "midnightcontrols.menu.touch_break_delay": "Touch Break Delay", + "midnightcontrols.menu.touch_speed": "Touch Speed", + "midnightcontrols.menu.invert_touch": "Invert Touch Direction", + "midnightcontrols.menu.touch_mode": "Touch Interaction Mode", + "midnightcontrols.menu.touch_transparency": "Touch HUD Transparency", "midnightcontrols.menu.unfocused_input": "Unfocused Input", "midnightcontrols.menu.unfocused_input.tooltip": "Allows controller input when the window is not focused.", "midnightcontrols.menu.virtual_mouse": "Virtual Mouse", @@ -213,6 +224,7 @@ "midnightcontrols.midnightconfig.category.misc": "Miscellaneous", "midnightcontrols.midnightconfig.category.screens": "Screens", "midnightcontrols.midnightconfig.category.gameplay": "Gameplay", + "midnightcontrols.midnightconfig.category.touch": "Touch", "midnightcontrols.midnightconfig.category.visual": "Visual", "modmenu.descriptionTranslation.midnightcontrols": "Adds controller support and enhanced controls overall.\nForked from LambdaControls, which sadly got discontinued." } diff --git a/src/main/resources/assets/midnightcontrols/textures/gui/sprites/binding/debug_screen.png b/src/main/resources/assets/midnightcontrols/textures/gui/sprites/binding/debug_screen.png new file mode 100644 index 0000000000000000000000000000000000000000..fadab721b356ab6465d925f8875bd9a6897a663f GIT binary patch literal 182 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE;At*47)h{fr*lQ!}mP~c&)pJ;uA zm^fmnXlh^ub4qW`c_o2{ubl3x{8bv zgXcYxu`bV;7#B<_^2xYc<)>|6?80I!+b4EYwyr(Q{$J37RZ1-nW`%xT7-`?@)o+;e fbfeAxXR_jFtLylu{GIt1=nw`^S3j3^P6