From 1186c9c2412352b800d874e1e2ecae9d1828e4bb Mon Sep 17 00:00:00 2001 From: Motschen Date: Sat, 30 Sep 2023 20:27:03 +0200 Subject: [PATCH] Another round of improvements Mostly related to touch screen support - Added selection outlines for Break-at-Finger mode - Breaking blocks/interacting with entities will now just check if the target changed, not the finger position - Added the ability to create custom touch buttons out of ButtonBindings - Redesigned top touch buttons - Added emote touch button when Emotecraft is installed - Updated SpruceUI - Removed old mixins --- gradle.properties | 2 +- .../client/MidnightControlsConfig.java | 7 +- .../client/compat/EmotecraftCompat.java | 7 +- .../client/gui/RingScreen.java | 1 - .../client/gui/TouchscreenOverlay.java | 207 ++++++++++++------ .../widget/SilentTexturedButtonWidget.java | 13 ++ .../mixin/ControlsOptionsScreenMixin.java | 2 +- .../client/mixin/EntryListWidgetAccessor.java | 21 -- .../client/mixin/GameOptionsMixin.java | 36 --- .../client/mixin/ScreenMixin.java | 6 +- .../client/mixin/WorldRendererMixin.java | 38 ++++ .../icon/{button.png => controller.png} | Bin .../textures/gui/sprites/touch/chat.png | Bin 0 -> 168 bytes .../textures/gui/sprites/touch/emote.png | Bin 0 -> 197 bytes .../textures/gui/sprites/touch/empty.png | Bin 0 -> 68 bytes .../textures/gui/sprites/touch/pause.png | Bin 0 -> 126 bytes .../resources/midnightcontrols.mixins.json | 2 - 17 files changed, 213 insertions(+), 129 deletions(-) delete mode 100644 src/main/java/eu/midnightdust/midnightcontrols/client/mixin/EntryListWidgetAccessor.java delete mode 100644 src/main/java/eu/midnightdust/midnightcontrols/client/mixin/GameOptionsMixin.java rename src/main/resources/assets/midnightcontrols/textures/gui/sprites/icon/{button.png => controller.png} (100%) create mode 100644 src/main/resources/assets/midnightcontrols/textures/gui/sprites/touch/chat.png create mode 100644 src/main/resources/assets/midnightcontrols/textures/gui/sprites/touch/emote.png create mode 100644 src/main/resources/assets/midnightcontrols/textures/gui/sprites/touch/empty.png create mode 100644 src/main/resources/assets/midnightcontrols/textures/gui/sprites/touch/pause.png diff --git a/gradle.properties b/gradle.properties index d43ae89..1f41585 100644 --- a/gradle.properties +++ b/gradle.properties @@ -17,7 +17,7 @@ modrinth_id=bXX9h73M # currently not on the main fabric site, check on the maven: https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api fabric_version=0.89.2+1.20.2 sodium_version=mc1.19.2-0.4.4 -spruceui_version=5.0.0+1.20 +spruceui_version=5.0.3+1.20.2 midnightlib_version=1.5.0-fabric modmenu_version=7.0.0 emotecraft_version=2.1.3-SNAPSHOT-build.29-MC1.19-fabric diff --git a/src/main/java/eu/midnightdust/midnightcontrols/client/MidnightControlsConfig.java b/src/main/java/eu/midnightdust/midnightcontrols/client/MidnightControlsConfig.java index 820978c..7123955 100644 --- a/src/main/java/eu/midnightdust/midnightcontrols/client/MidnightControlsConfig.java +++ b/src/main/java/eu/midnightdust/midnightcontrols/client/MidnightControlsConfig.java @@ -18,6 +18,7 @@ import eu.midnightdust.midnightcontrols.MidnightControlsFeature; import eu.midnightdust.midnightcontrols.client.controller.ButtonBinding; import eu.midnightdust.midnightcontrols.client.controller.Controller; import eu.midnightdust.midnightcontrols.client.controller.InputManager; +import eu.midnightdust.midnightcontrols.client.gui.RingScreen; import eu.midnightdust.midnightcontrols.client.touch.TouchMode; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.ChatScreen; @@ -81,9 +82,13 @@ public class MidnightControlsConfig extends MidnightConfig { "me.shedaniel.clothconfig2.gui.ClothConfigScreen", "com.mamiyaotaru.voxelmap.gui.GuiWaypoints", "com.mamiyaotaru.voxelmap.gui.GuiPersistentMap"); @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()); + @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_mode") public static TouchMode touchMode = TouchMode.CROSSHAIR; + @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 @Hidden public static Map BINDING = new HashMap<>(); diff --git a/src/main/java/eu/midnightdust/midnightcontrols/client/compat/EmotecraftCompat.java b/src/main/java/eu/midnightdust/midnightcontrols/client/compat/EmotecraftCompat.java index 74af0f5..ba3430a 100644 --- a/src/main/java/eu/midnightdust/midnightcontrols/client/compat/EmotecraftCompat.java +++ b/src/main/java/eu/midnightdust/midnightcontrols/client/compat/EmotecraftCompat.java @@ -1,16 +1,21 @@ package eu.midnightdust.midnightcontrols.client.compat; import eu.midnightdust.midnightcontrols.client.controller.InputManager; +import io.github.kosmx.emotes.arch.gui.EmoteMenuImpl; import io.github.kosmx.emotes.arch.gui.screen.ingame.FastChosseScreen; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.Screen; public class EmotecraftCompat { + private static final MinecraftClient client = MinecraftClient.getInstance(); + public static void openEmotecraftScreen(Screen parent) { + client.setScreen(new EmoteMenuImpl(parent)); + } public static boolean isEmotecraftScreen(Screen screen) { return screen instanceof FastChosseScreen; } public static void handleEmoteSelector(int index) { - MinecraftClient client = MinecraftClient.getInstance(); + if (client.currentScreen instanceof FastChosseScreen) { int x = client.getWindow().getWidth() / 2; int y = client.getWindow().getHeight() / 2; diff --git a/src/main/java/eu/midnightdust/midnightcontrols/client/gui/RingScreen.java b/src/main/java/eu/midnightdust/midnightcontrols/client/gui/RingScreen.java index 1c6fecf..c3b3e64 100644 --- a/src/main/java/eu/midnightdust/midnightcontrols/client/gui/RingScreen.java +++ b/src/main/java/eu/midnightdust/midnightcontrols/client/gui/RingScreen.java @@ -15,7 +15,6 @@ import eu.midnightdust.midnightcontrols.client.ring.RingPage; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.widget.ButtonWidget; -import net.minecraft.client.util.math.MatrixStack; import net.minecraft.text.Text; /** 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 4ef1a75..6d3aaf5 100644 --- a/src/main/java/eu/midnightdust/midnightcontrols/client/gui/TouchscreenOverlay.java +++ b/src/main/java/eu/midnightdust/midnightcontrols/client/gui/TouchscreenOverlay.java @@ -11,13 +11,22 @@ 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; import eu.midnightdust.midnightcontrols.client.MidnightControlsClient; 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.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; @@ -34,9 +43,14 @@ 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.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; @@ -45,17 +59,27 @@ import static org.lwjgl.glfw.GLFW.GLFW_GAMEPAD_AXIS_RIGHT_Y; */ public class TouchscreenOverlay extends Screen { public static final Identifier WIDGETS_LOCATION = new Identifier("midnightcontrols", "textures/gui/widgets.png"); - private MidnightControlsClient mod; + private final MidnightControlsClient mod; + private SilentTexturedButtonWidget inventoryButton; + private SilentTexturedButtonWidget swapHandsButton; + private SilentTexturedButtonWidget dropButton; private SilentTexturedButtonWidget jumpButton; private SilentTexturedButtonWidget flyButton; private SilentTexturedButtonWidget flyUpButton; private SilentTexturedButtonWidget flyDownButton; - private int flyButtonEnableTicks = 0; - private int forwardButtonTick = 0; + private SilentTexturedButtonWidget forwardButton; private SilentTexturedButtonWidget forwardLeftButton; private SilentTexturedButtonWidget forwardRightButton; + private SilentTexturedButtonWidget leftButton; + private SilentTexturedButtonWidget rightButton; + private SilentTexturedButtonWidget backButton; private SilentTexturedButtonWidget startSneakButton; private SilentTexturedButtonWidget endSneakButton; + private int flyButtonEnableTicks = 0; + private int forwardButtonTick = 0; + public long clickStartTime; + public HitResult firstHitResult = null; + public static TouchscreenOverlay instance; public TouchscreenOverlay(@NotNull MidnightControlsClient mod) { super(Text.literal("Touchscreen overlay")); @@ -63,23 +87,18 @@ public class TouchscreenOverlay extends Screen { } @Override - public boolean shouldPause() - { + public boolean shouldPause() { return false; } @Override public void renderInGameBackground(DrawContext context) {} - private void pauseGame(boolean bl) { - if (this.client == null) - return; - boolean bl2 = this.client.isIntegratedServerRunning() && !this.client.getServer().isRemote(); - if (bl2) { - this.client.setScreen(new GameMenuScreen(!bl)); + private void pauseGame() { + assert this.client != null; + this.client.setScreen(new GameMenuScreen(true)); + if (this.client.isIntegratedServerRunning() && !Objects.requireNonNull(this.client.getServer()).isRemote()) { this.client.getSoundManager().pauseAll(); - } else { - this.client.setScreen(new GameMenuScreen(true)); } } @@ -90,19 +109,17 @@ public class TouchscreenOverlay extends Screen { * */ private void updateForwardButtonsState(boolean state) { - if (state) - this.forwardButtonTick = -1; - else - this.forwardButtonTick = 20; + this.forwardButtonTick = state ? -1 : 20; } /** * Updates the jump buttons. */ private void updateJumpButtons() { - if (this.client == null) - return; - if (!this.client.interactionManager.isFlyingLocked()) { + assert this.client != null; + assert this.client.player != null; + + if (this.client.player.getAbilities().flying) { boolean oldStateFly = this.flyButton.isVisible(); this.jumpButton.setVisible(false); this.flyButton.setVisible(true); @@ -127,6 +144,7 @@ public class TouchscreenOverlay extends Screen { * @param btn The pressed button. */ private void handleJump(SpruceButtonWidget btn) { + assert this.client != null; ((KeyBindingAccessor) this.client.options.jumpKey).midnightcontrols$handlePressState(btn.isActive()); } /** @@ -135,18 +153,32 @@ public class TouchscreenOverlay extends Screen { * @param state The state. */ private void setJump(boolean state) { + assert this.client != null; ((KeyBindingAccessor) this.client.options.jumpKey).midnightcontrols$handlePressState(state); } @Override protected void init() { super.init(); + assert this.client != null; + assert this.client.player != null; + assert this.client.interactionManager != null; int scaledWidth = this.client.getWindow().getScaledWidth(); int scaledHeight = this.client.getWindow().getScaledHeight(); - TextIconButtonWidget chatButton = TextIconButtonWidget.builder(Text.empty(), btn -> this.client.setScreen(new ChatScreen("")), true).width(20).texture(new Identifier("icon/language"), 15, 15).build(); - chatButton.setPosition(scaledWidth / 2 - 20, 0); + int emoteOffset = 0; + if (PlatformFunctions.isModLoaded("emotecraft")) { + emoteOffset = 10; + TextIconButtonWidget emoteButton = TextIconButtonWidget.builder(Text.empty(), btn -> EmotecraftCompat.openEmotecraftScreen(this), true).width(20).texture(new Identifier(MidnightControlsConstants.NAMESPACE, "touch/emote"), 20, 20).build(); + emoteButton.setPosition(scaledWidth / 2 - 30, 0); + this.addDrawableChild(emoteButton); + } + + TextIconButtonWidget chatButton = TextIconButtonWidget.builder(Text.empty(), btn -> this.client.setScreen(new ChatScreen("")), true).width(20).texture(new Identifier(MidnightControlsConstants.NAMESPACE, "touch/chat"), 20, 20).build(); + chatButton.setPosition(scaledWidth / 2 - 20 + emoteOffset, 0); this.addDrawableChild(chatButton); - this.addDrawableChild(new SilentTexturedButtonWidget(Position.of(scaledWidth / 2, 0), 20, 20, Text.empty(), btn -> this.pauseGame(false), 0, 0, 20, WIDGETS_LOCATION, 256, 256)); + TextIconButtonWidget pauseButton = TextIconButtonWidget.builder(Text.empty(), btn -> this.pauseGame(), true).width(20).texture(new Identifier(MidnightControlsConstants.NAMESPACE, "touch/pause"), 20, 20).build(); + pauseButton.setPosition(scaledWidth / 2 + emoteOffset, 0); + this.addDrawableChild(pauseButton); // Inventory buttons. int inventoryButtonX = scaledWidth / 2; int inventoryButtonY = scaledHeight - 16 - 5; @@ -155,7 +187,7 @@ public class TouchscreenOverlay extends Screen { } else { inventoryButtonX = inventoryButtonX + 91 + 4; } - this.addDrawableChild(new SilentTexturedButtonWidget(Position.of(inventoryButtonX, inventoryButtonY), 20, 20, Text.empty(), btn -> { + this.addDrawableChild(this.inventoryButton = new SilentTexturedButtonWidget(Position.of(inventoryButtonX, inventoryButtonY), 20, 20, Text.empty(), btn -> { if (this.client.interactionManager.hasRidingInventory()) { this.client.player.openRidingInventory(); } else { @@ -176,16 +208,16 @@ public class TouchscreenOverlay extends Screen { sneakButtonX = scaledWidth - 10 - 40 - 5; } // Swap items hand. - this.addDrawableChild(new SilentTexturedButtonWidget(Position.of(swapHandsX, sneakButtonY), 20, 20, Text.empty(), + this.addDrawableChild(this.swapHandsButton = new SilentTexturedButtonWidget(Position.of(swapHandsX, sneakButtonY), 20, 20, Text.empty(), button -> { if (button.isActive()) { if (!this.client.player.isSpectator()) { - this.client.getNetworkHandler().sendPacket(new PlayerActionC2SPacket(PlayerActionC2SPacket.Action.SWAP_ITEM_WITH_OFFHAND, BlockPos.ORIGIN, Direction.DOWN)); + Objects.requireNonNull(this.client.getNetworkHandler()).sendPacket(new PlayerActionC2SPacket(PlayerActionC2SPacket.Action.SWAP_ITEM_WITH_OFFHAND, BlockPos.ORIGIN, Direction.DOWN)); } } },0, 160, 20, WIDGETS_LOCATION)); // Drop - this.addDrawableChild(new SilentTexturedButtonWidget(Position.of(swapHandsX, sneakButtonY + 5 + 20), 20, 20, Text.empty(), btn -> + 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)); // Jump keys this.addDrawableChild(this.jumpButton = new SilentTexturedButtonWidget(Position.of(jumpButtonX, sneakButtonY), 20, 20, Text.empty(), this::handleJump, 0, 40, 20, WIDGETS_LOCATION)); @@ -216,15 +248,13 @@ public class TouchscreenOverlay extends Screen { this.startSneakButton.setVisible(true); } }, 20, 120, 20, WIDGETS_LOCATION))); - this.endSneakButton.setVisible(false); this.addDrawableChild(this.forwardLeftButton = new SilentTexturedButtonWidget(Position.of(sneakButtonX - 20 - 5, sneakButtonY - 5 - 20), 20, 20, Text.empty(), btn -> { ((KeyBindingAccessor) this.client.options.forwardKey).midnightcontrols$handlePressState(btn.isActive()); ((KeyBindingAccessor) this.client.options.leftKey).midnightcontrols$handlePressState(btn.isActive()); this.updateForwardButtonsState(btn.isActive()); }, 80, 80, 20, WIDGETS_LOCATION )); - this.forwardLeftButton.setVisible(false); - this.addDrawableChild(new SilentTexturedButtonWidget(Position.of(sneakButtonX, sneakButtonY - 5 - 20), 20, 20, Text.empty(), btn -> { + this.addDrawableChild(this.forwardButton = new SilentTexturedButtonWidget(Position.of(sneakButtonX, sneakButtonY - 5 - 20), 20, 20, Text.empty(), btn -> { ((KeyBindingAccessor) this.client.options.forwardKey).midnightcontrols$handlePressState(btn.isActive()); this.updateForwardButtonsState(btn.isActive()); this.forwardLeftButton.setVisible(true); @@ -237,36 +267,71 @@ public class TouchscreenOverlay extends Screen { this.updateForwardButtonsState(btn.isActive()); }, 100, 80, 20, WIDGETS_LOCATION )); - this.forwardRightButton.setVisible(false); - this.addDrawableChild(new SilentTexturedButtonWidget(Position.of(sneakButtonX + 20 + 5, sneakButtonY), 20, 20, Text.empty(), + + this.addDrawableChild(this.rightButton =new SilentTexturedButtonWidget(Position.of(sneakButtonX + 20 + 5, sneakButtonY), 20, 20, Text.empty(), btn -> ((KeyBindingAccessor) this.client.options.rightKey).midnightcontrols$handlePressState(btn.isActive()), 20, 80, 20, WIDGETS_LOCATION )); - this.addDrawableChild(new SilentTexturedButtonWidget(Position.of(sneakButtonX, sneakButtonY + 20 + 5), 20, 20, Text.empty(), + this.addDrawableChild(this.backButton = new SilentTexturedButtonWidget(Position.of(sneakButtonX, sneakButtonY + 20 + 5), 20, 20, Text.empty(), btn -> ((KeyBindingAccessor) this.client.options.backKey).midnightcontrols$handlePressState(btn.isActive()), 40, 80, 20, WIDGETS_LOCATION )); - this.addDrawableChild(new SilentTexturedButtonWidget(Position.of(sneakButtonX - 20 - 5, sneakButtonY), 20, 20, Text.empty(), + 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); + } + + this.setButtonProperties(MidnightControlsConfig.touchTransparency / 100f); + TouchscreenOverlay.instance = this; + } + 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.flyDownButton.setAlpha(transparency); + this.startSneakButton.setAlpha(transparency); + this.endSneakButton.setAlpha(transparency); + this.forwardButton.setAlpha(transparency); + this.forwardLeftButton.setAlpha(Math.max(0.05f, transparency-0.1f)); + this.forwardRightButton.setAlpha(Math.max(0.05f, transparency-0.1f)); + this.leftButton.setAlpha(transparency); + this.rightButton.setAlpha(transparency); + this.backButton.setAlpha(transparency); + this.endSneakButton.setVisible(false); + this.forwardLeftButton.setVisible(false); + this.forwardRightButton.setVisible(false); } @Override public void tick() { + assert this.client != null; + assert this.client.interactionManager != null; + if (this.forwardButtonTick > 0) { - this.forwardButtonTick--; - } else if (this.forwardButtonTick == 0) { - if (this.forwardLeftButton.isVisible()) - this.forwardLeftButton.setVisible(false); - if (this.forwardRightButton.isVisible()) - this.forwardRightButton.setVisible(false); + --this.forwardButtonTick; + } else { + this.forwardLeftButton.setVisible(false); + this.forwardRightButton.setVisible(false); } this.updateJumpButtons(); + double scaleFactor = client.getWindow().getScaleFactor(); - if (clickStartTime > 0 && System.currentTimeMillis() - clickStartTime >= 100) mouseHeldDown(client.mouse.getX() / scaleFactor, client.mouse.getY() / scaleFactor); + if (clickStartTime > 0 && System.currentTimeMillis() - clickStartTime >= 100) this.mouseHeldDown(client.mouse.getX() / scaleFactor, client.mouse.getY() / scaleFactor); else client.interactionManager.cancelBlockBreaking(); } - private long clickStartTime; - private double[] firstPosition = new double[2]; @Override public boolean mouseClicked(double mouseX, double mouseY, int button) { int centerX = this.width / 2; @@ -280,21 +345,26 @@ public class TouchscreenOverlay extends Screen { } } else { clickStartTime = System.currentTimeMillis(); - firstPosition[0] = mouseX; - firstPosition[1] = mouseY; + boolean bl = super.mouseClicked(mouseX, mouseY, button); + if (!bl) firstHitResult = TouchUtils.getTargettedObject(mouseX, mouseY); + return bl; } return super.mouseClicked(mouseX, mouseY, button); } @Override public boolean mouseReleased(double mouseX, double mouseY, int button) { + firstHitResult = null; if (!super.mouseReleased(mouseX, mouseY, button) && System.currentTimeMillis() - clickStartTime < 200) { + assert client != null; + assert client.player != null; + assert client.world != null; + assert client.interactionManager != null; clickStartTime = -1; HitResult result = TouchUtils.getTargettedObject(mouseX, mouseY); if (result == null) return false; - if (result.getType() == HitResult.Type.BLOCK) { - BlockHitResult blockHit = (BlockHitResult) result; + if (result instanceof BlockHitResult blockHit) { BlockPos blockPos = blockHit.getBlockPos().offset(blockHit.getSide()); BlockState state = client.world.getBlockState(blockPos); @@ -313,30 +383,30 @@ public class TouchscreenOverlay extends Screen { } } } - if (result.getType() == HitResult.Type.ENTITY) { - client.interactionManager.attackEntity(client.player, ((EntityHitResult)result).getEntity()); + if (result instanceof EntityHitResult entityHit) { + client.interactionManager.attackEntity(client.player, entityHit.getEntity()); } } - firstPosition = new double[2]; clickStartTime = -1; return false; } - public boolean mouseHeldDown(double mouseX, double mouseY) { - System.out.println(mouseX + " " + firstPosition[0]); - if (!isDragging() && Math.abs(mouseX-firstPosition[0]) < 1 && Math.abs(mouseY-firstPosition[1]) < 1) { + public void mouseHeldDown(double mouseX, double mouseY) { + assert client != null; + assert client.player != null; + assert client.interactionManager != null; + if (!isDragging()) { HitResult result = TouchUtils.getTargettedObject(mouseX, mouseY); - if (result == null) return false; - - if (result.getType() == HitResult.Type.BLOCK) { - BlockHitResult blockHit = (BlockHitResult) result; - System.out.println(blockHit.getBlockPos().toString()); - return client.interactionManager.updateBlockBreakingProgress(blockHit.getBlockPos(), blockHit.getSide()); + 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()); + firstHitResult = TouchUtils.getTargettedObject(mouseX, mouseY); } - if (result.getType() == HitResult.Type.ENTITY) { - client.interactionManager.interactEntity(client.player, ((EntityHitResult)result).getEntity(), client.player.getActiveHand()); + 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()); + firstHitResult = TouchUtils.getTargettedObject(mouseX, mouseY); } } - return false; } @Override @@ -349,13 +419,23 @@ public class TouchscreenOverlay extends Screen { if (deltaX > 0.01) this.mod.input.handleLook(this.client, GLFW_GAMEPAD_AXIS_RIGHT_X, (float) Math.abs((deltaX / 3.0)*MidnightControlsConfig.touchSpeed/100), 2); else this.mod.input.handleLook(this.client, GLFW_GAMEPAD_AXIS_RIGHT_X, (float) Math.abs((deltaX / 3.0)*MidnightControlsConfig.touchSpeed/100), 1); + + HitResult result = TouchUtils.getTargettedObject(mouseX, mouseY); + if (result != null && firstHitResult != null) { + if (result instanceof BlockHitResult blockHit && firstHitResult instanceof BlockHitResult firstBlock && !blockHit.getBlockPos().equals(firstBlock.getBlockPos())) { + firstHitResult = null; + } else if (result instanceof EntityHitResult entityHit && firstHitResult instanceof EntityHitResult firstEntity && entityHit.getEntity().getUuid().compareTo(firstEntity.getEntity().getUuid()) != 0) { + firstHitResult = null; + } + } } return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY); } @Override public boolean keyPressed(int keyCode, int scanCode, int modifiers) { + //client.currentScreen = null; KeyBinding.onKeyPressed(InputUtil.fromKeyCode(keyCode, scanCode)); - //return false; + super.keyPressed(keyCode,scanCode,modifiers); return true; } @@ -363,6 +443,7 @@ public class TouchscreenOverlay extends Screen { @Override public void render(DrawContext context, int mouseX, int mouseY, float delta) { super.render(context, mouseX, mouseY, delta); + context.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f); context.fill(mouseX-10, mouseY-10, mouseX+10, mouseY+10, 0xFFFFFF); } } diff --git a/src/main/java/eu/midnightdust/midnightcontrols/client/gui/widget/SilentTexturedButtonWidget.java b/src/main/java/eu/midnightdust/midnightcontrols/client/gui/widget/SilentTexturedButtonWidget.java index 7861ac5..013f68c 100644 --- a/src/main/java/eu/midnightdust/midnightcontrols/client/gui/widget/SilentTexturedButtonWidget.java +++ b/src/main/java/eu/midnightdust/midnightcontrols/client/gui/widget/SilentTexturedButtonWidget.java @@ -23,4 +23,17 @@ public class SilentTexturedButtonWidget extends SpruceTexturedButtonWidget { } @Override public void playDownSound() {} + @Override + protected void onRelease(double mouseX, double mouseY) { + this.setActive(false); + super.onClick(mouseX, mouseY); + super.onRelease(mouseX, mouseY); + this.setActive(true); + } + @Override + public void onClick(double mouseX, double mouseY) { + this.setActive(true); + super.onClick(mouseX, mouseY); + this.setActive(false); + } } diff --git a/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/ControlsOptionsScreenMixin.java b/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/ControlsOptionsScreenMixin.java index 590118f..e1fc3c4 100644 --- a/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/ControlsOptionsScreenMixin.java +++ b/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/ControlsOptionsScreenMixin.java @@ -33,7 +33,7 @@ public abstract class ControlsOptionsScreenMixin extends GameOptionsScreen { @Inject(method = "init", at = @At(value = "INVOKE", ordinal = 1, shift = At.Shift.AFTER, target = "Lnet/minecraft/client/gui/screen/option/ControlsOptionsScreen;addDrawableChild(Lnet/minecraft/client/gui/Element;)Lnet/minecraft/client/gui/Element;")) private void addControllerButton(CallbackInfo ci) { TextIconButtonWidget iconWidget = TextIconButtonWidget.builder(Text.translatable("midnightcontrols.menu.title.controller"), (button -> this.client.setScreen(new MidnightControlsSettingsScreen(this, false))), true) - .dimension(20,20).texture(new Identifier("midnightcontrols", "icon/button"), 20, 20).build(); + .dimension(20,20).texture(new Identifier("midnightcontrols", "icon/controller"), 20, 20).build(); iconWidget.setPosition(this.width / 2 + 158, this.height / 6 - 12); this.addDrawableChild(iconWidget); } diff --git a/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/EntryListWidgetAccessor.java b/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/EntryListWidgetAccessor.java deleted file mode 100644 index 72f8f4c..0000000 --- a/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/EntryListWidgetAccessor.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright © 2021 LambdAurora - * - * This file is part of midnightcontrols. - * - * Licensed under the MIT license. For more information, - * see the LICENSE file. - */ - -package eu.midnightdust.midnightcontrols.client.mixin; - -import net.minecraft.client.gui.navigation.NavigationDirection; -import net.minecraft.client.gui.widget.EntryListWidget; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Invoker; - -@Mixin(EntryListWidget.class) -public interface EntryListWidgetAccessor { - //@Invoker("getNeighbouringEntry") - //void midnightcontrols$getNeighbouringEntry(NavigationDirection direction); -} diff --git a/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/GameOptionsMixin.java b/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/GameOptionsMixin.java deleted file mode 100644 index 84291fc..0000000 --- a/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/GameOptionsMixin.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright © 2021 LambdAurora - * - * This file is part of midnightcontrols. - * - * Licensed under the MIT license. For more information, - * see the LICENSE file. - */ - -package eu.midnightdust.midnightcontrols.client.mixin; - -import net.minecraft.client.option.GameOptions; -import net.minecraft.client.option.SimpleOption; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -/** - * Represents a mixin to GameOptions. - *

- * Sets the default of the Auto-Jump option to false. - */ -@Mixin(GameOptions.class) -public abstract class GameOptionsMixin { - - @Shadow public abstract SimpleOption getAutoJump(); - - @Inject(method = "load", at = @At("HEAD")) - public void onInit(CallbackInfo ci) { - // Set default value of the Auto-Jump option to false. - getAutoJump().setValue(false); - } -} 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 dd5ac1e..6ec8f16 100644 --- a/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/ScreenMixin.java +++ b/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/ScreenMixin.java @@ -31,8 +31,10 @@ 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))) { - 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)); + 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); } } } diff --git a/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/WorldRendererMixin.java b/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/WorldRendererMixin.java index 3e5b265..2e16782 100644 --- a/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/WorldRendererMixin.java +++ b/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/WorldRendererMixin.java @@ -10,8 +10,11 @@ package eu.midnightdust.midnightcontrols.client.mixin; import eu.midnightdust.lib.util.MidnightColorUtil; +import eu.midnightdust.midnightcontrols.ControlsMode; import eu.midnightdust.midnightcontrols.client.MidnightControlsClient; import eu.midnightdust.midnightcontrols.client.MidnightControlsConfig; +import eu.midnightdust.midnightcontrols.client.gui.TouchscreenOverlay; +import eu.midnightdust.midnightcontrols.client.touch.TouchMode; import eu.midnightdust.midnightcontrols.client.util.RainbowColor; import net.minecraft.block.ShapeContext; import net.minecraft.client.MinecraftClient; @@ -22,14 +25,17 @@ import net.minecraft.item.BlockItem; import net.minecraft.item.ItemPlacementContext; import net.minecraft.item.ItemUsageContext; import net.minecraft.util.Hand; +import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.hit.HitResult; import net.minecraft.util.shape.VoxelShape; import org.joml.Matrix4f; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import java.awt.*; @@ -55,6 +61,13 @@ public abstract class WorldRendererMixin { @Shadow private static void drawCuboidShapeOutline(MatrixStack matrices, VertexConsumer vertexConsumer, VoxelShape shape, double offsetX, double offsetY, double offsetZ, float red, float green, float blue, float alpha) { } + @Redirect(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/hit/HitResult;getType()Lnet/minecraft/util/hit/HitResult$Type;")) + private HitResult.Type dontRenderOutline(HitResult instance) { + if (MidnightControlsConfig.controlsMode == ControlsMode.TOUCHSCREEN && MidnightControlsConfig.touchMode == TouchMode.FINGER_POS) { + return HitResult.Type.MISS; + } + return instance.getType(); + } @Inject( method = "render", @@ -67,6 +80,31 @@ public abstract class WorldRendererMixin { ) private void onOutlineRender(MatrixStack matrices, float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightmapTextureManager lightmapTextureManager, Matrix4f matrix4f, CallbackInfo ci) { + if (MidnightControlsConfig.controlsMode == ControlsMode.TOUCHSCREEN && MidnightControlsConfig.touchMode == TouchMode.FINGER_POS && TouchscreenOverlay.instance != null) { + this.renderFingerOutline(matrices, camera); + } + this.renderReacharoundOutline(matrices, camera); + } + @Unique + private void renderFingerOutline(MatrixStack matrices, Camera camera) { + if (TouchscreenOverlay.instance.firstHitResult == null || TouchscreenOverlay.instance.firstHitResult.getType() != HitResult.Type.BLOCK) + return; + BlockHitResult result = (BlockHitResult) TouchscreenOverlay.instance.firstHitResult; + var blockPos = result.getBlockPos(); + if (this.world.getWorldBorder().contains(blockPos) && this.client.player != null) { + var outlineShape = this.world.getBlockState(blockPos).getOutlineShape(this.client.world, blockPos, ShapeContext.of(camera.getFocusedEntity())); + Color rgb = MidnightColorUtil.hex2Rgb(MidnightControlsConfig.touchOutlineColorHex); + if (MidnightControlsConfig.touchOutlineColorHex.isEmpty()) rgb = RainbowColor.radialRainbow(1,1); + var pos = camera.getPos(); + matrices.push(); + var vertexConsumer = this.bufferBuilders.getEntityVertexConsumers().getBuffer(RenderLayer.getLines()); + drawCuboidShapeOutline(matrices, vertexConsumer, outlineShape, blockPos.getX() - pos.getX(), blockPos.getY() - pos.getY(), blockPos.getZ() - pos.getZ(), + rgb.getRed() / 255.f, rgb.getGreen() / 255.f, rgb.getBlue() / 255.f, MidnightControlsConfig.touchOutlineColorAlpha / 255.f); + matrices.pop(); + } + } + @Unique + private void renderReacharoundOutline(MatrixStack matrices, Camera camera) { if (this.client.crosshairTarget == null || this.client.crosshairTarget.getType() != HitResult.Type.MISS || !MidnightControlsConfig.shouldRenderReacharoundOutline) return; var result = MidnightControlsClient.get().reacharound.getLastReacharoundResult(); diff --git a/src/main/resources/assets/midnightcontrols/textures/gui/sprites/icon/button.png b/src/main/resources/assets/midnightcontrols/textures/gui/sprites/icon/controller.png similarity index 100% rename from src/main/resources/assets/midnightcontrols/textures/gui/sprites/icon/button.png rename to src/main/resources/assets/midnightcontrols/textures/gui/sprites/icon/controller.png diff --git a/src/main/resources/assets/midnightcontrols/textures/gui/sprites/touch/chat.png b/src/main/resources/assets/midnightcontrols/textures/gui/sprites/touch/chat.png new file mode 100644 index 0000000000000000000000000000000000000000..d1e7aa52d1a7b69aad00185ae02579976130515b GIT binary patch literal 168 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE;AzNd?0h{fr*6Ak$eC~&x%KD4ta z{6CY^FJ=2O!-lJuR@P2F_~D0_ru}+FC0i$#s#!UnRpHM(6GfCBRjMhK8yL?n?YLCs zE4a?UOPsgmOvz>S_kR+9P4k_1B0()Y^!vK4VaKDkUW#=MyL>6A%vJswgIed$Y4t6Z RbAeVfc)I$ztaD0e0sz)GKAHdk literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/midnightcontrols/textures/gui/sprites/touch/emote.png b/src/main/resources/assets/midnightcontrols/textures/gui/sprites/touch/emote.png new file mode 100644 index 0000000000000000000000000000000000000000..b18fd1750335e4c8be2a93fffc764815376bd850 GIT binary patch literal 197 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE;AkEe@ch{frr!3TMdDDV`on%$p?}EJky)R&3SfQ2NvuEmgAA=T$@?4J~mlV(3kgL=Cw@#U3T=l*v{q(b?JrA!( wv93O4t^Mi0|N9vW&ChH0&E5U#e(?t8e~VKEm#o}X3v?HQr>mdKI;Vst0K|h(+yDRo literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/midnightcontrols/textures/gui/sprites/touch/empty.png b/src/main/resources/assets/midnightcontrols/textures/gui/sprites/touch/empty.png new file mode 100644 index 0000000000000000000000000000000000000000..af367b99a00dc1613aaba25466ded4b74e58d0ed GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx1|;Q0k8}blZci7-5RU7~2@FgO46F={kJMOa Q1BDqpUHx3vIVCg!09!{3-~a#s literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/midnightcontrols/textures/gui/sprites/touch/pause.png b/src/main/resources/assets/midnightcontrols/textures/gui/sprites/touch/pause.png new file mode 100644 index 0000000000000000000000000000000000000000..8dea51d7d2d5479ac6ce4d0319fd2fc1aa06da89 GIT binary patch literal 126 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE;=tEY=&h{fsT1PN9X#{UZ+9BSqM z|MtzBf5O_w4*-En?(rTei>wC;1`}9kKRDVgUYK=2z5Vim6)Q9>W>23!J!5B}gDeAs YV7=n%j>oEBfCe&ny85}Sb4q9e0Dl@Rpa1{> literal 0 HcmV?d00001 diff --git a/src/main/resources/midnightcontrols.mixins.json b/src/main/resources/midnightcontrols.mixins.json index fd098ca..13310fa 100644 --- a/src/main/resources/midnightcontrols.mixins.json +++ b/src/main/resources/midnightcontrols.mixins.json @@ -8,8 +8,6 @@ "ClientPlayerEntityMixin", "ControlsOptionsScreenMixin", "CreativeInventoryScreenAccessor", - "EntryListWidgetAccessor", - "GameOptionsMixin", "GameRendererMixin", "HandledScreenMixin", "KeyBindingMixin",