Add touchscreen support but still WIP.

This commit is contained in:
LambdAurora
2019-11-27 16:06:16 +01:00
parent e10aaf9f7a
commit eeaf35564a
13 changed files with 468 additions and 7 deletions

View File

@@ -0,0 +1,66 @@
/*
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package me.lambdaurora.lambdacontrols;
import 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 hud side which is the side where the movements buttons are.
*/
public enum HudSide implements Nameable
{
LEFT,
RIGHT;
/**
* Returns the next side available.
*
* @return The next available side.
*/
public HudSide next()
{
HudSide[] v = values();
if (v.length == this.ordinal() + 1)
return v[0];
return v[this.ordinal() + 1];
}
/**
* Gets the translated name of this hud side.
*
* @return The translated name of this hud side.
*/
public String get_translated_name()
{
return I18n.translate("lambdacontrols.hud_side." + this.get_name());
}
@Override
public @NotNull String get_name()
{
return this.name().toLowerCase();
}
/**
* Gets the hud side from its identifier.
*
* @param id The identifier of the hud side.
* @return The hud side if found, else empty.
*/
public static Optional<HudSide> by_id(@NotNull String id)
{
return Arrays.stream(values()).filter(mode -> mode.get_name().equalsIgnoreCase(id)).findFirst();
}
}

View File

@@ -10,7 +10,6 @@
package me.lambdaurora.lambdacontrols;
import com.electronwill.nightconfig.core.file.FileConfig;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.options.GameOptions;
import net.minecraft.client.options.KeyBinding;
import org.jetbrains.annotations.NotNull;
@@ -28,6 +27,7 @@ public class LambdaControlsConfig
private final Map<String, KeyBinding> keybinding_mappings = new HashMap<>();
private final LambdaControls mod;
private ControlsMode controls_mode;
private HudSide hud_side;
public LambdaControlsConfig(@NotNull LambdaControls mod)
{
@@ -40,6 +40,7 @@ public class LambdaControlsConfig
this.config.load();
this.mod.log("Configuration loaded.");
this.controls_mode = ControlsMode.by_id(this.config.getOrElse("controls", "default")).orElse(ControlsMode.DEFAULT);
this.hud_side = HudSide.by_id(this.config.getOrElse("hud.side", "left")).orElse(HudSide.LEFT);
}
public void init_keybindings(GameOptions options)
@@ -106,6 +107,27 @@ public class LambdaControlsConfig
this.config.set("controls", controls_mode.get_name());
}
/**
* Returns the HUD side from the configuration.
*
* @return The HUD side.
*/
public @NotNull HudSide get_hud_side()
{
return this.hud_side;
}
/**
* Sets the HUD side in the configuration.
*
* @param hud_side The HUD side.
*/
public void set_hud_side(@NotNull HudSide hud_side)
{
this.hud_side = hud_side;
this.config.set("hud.side", hud_side.get_name());
}
/**
* Returns the keybindings.
*

View File

@@ -9,9 +9,13 @@
package me.lambdaurora.lambdacontrols.gui;
import me.lambdaurora.lambdacontrols.ControlsMode;
import me.lambdaurora.lambdacontrols.LambdaControls;
import me.lambdaurora.lambdacontrols.util.LambdaKeyBinding;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.widget.ButtonWidget;
import org.jetbrains.annotations.NotNull;
import org.lwjgl.glfw.GLFW;
/**
* Represents the LambdaControls HUD.
@@ -19,15 +23,31 @@ import org.jetbrains.annotations.NotNull;
public class LambdaControlsHud
{
private final MinecraftClient client;
private final LambdaControls mod;
private final LambdaControls mod;
private ButtonWidget jump_button;
public LambdaControlsHud(@NotNull MinecraftClient client, @NotNull LambdaControls mod)
{
this.client = client;
this.mod = mod;
this.jump_button = new ButtonWidget(50, 50, 20, 20, "J", button-> {});
}
public void render() {
public void render(float delta)
{
if (this.mod.config.get_controls_mode() == ControlsMode.TOUCHSCREEN)
this.render_touchscreen(delta);
}
public void render_touchscreen(float delta)
{
//this.jump_button.render((int) this.client.mouse.getX(), (int) this.client.mouse.getY(), delta);
}
public void on_input(double x, double y, int button, int action)
{
if (this.jump_button.mouseClicked(x, y, button)) {
((LambdaKeyBinding) this.client.options.keyJump).handle_press_state(action != GLFW.GLFW_RELEASE);
}
}
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package me.lambdaurora.lambdacontrols.gui;
import net.minecraft.client.gui.widget.TexturedButtonWidget;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
/**
* Represents a touchscreen button widget.
*/
public class TouchscreenButtonWidget extends TexturedButtonWidget
{
private final Consumer<Boolean> on_change_state;
public TouchscreenButtonWidget(int x, int y, int width, int height, int u, int v, int hovered_v_offset, Identifier texture, @NotNull Consumer<Boolean> on_changed_state)
{
super(x, y, width, height, u, v, hovered_v_offset, texture, 256, 256, btn -> on_changed_state.accept(true));
this.on_change_state = on_changed_state;
}
@Override
public void onRelease(double mouseX, double mouseY)
{
super.onRelease(mouseX, mouseY);
this.on_change_state.accept(false);
}
@Override
public boolean mouseClicked(double mouseX, double mouseY, int button)
{
if (this.active && this.visible) {
if (this.isValidClickButton(button)) {
boolean clicked = this.clicked(mouseX, mouseY);
if (clicked) {
this.onClick(mouseX, mouseY);
return true;
}
}
return false;
} else
return false;
}
}

View File

@@ -0,0 +1,163 @@
/*
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package me.lambdaurora.lambdacontrols.gui;
import me.lambdaurora.lambdacontrols.HudSide;
import me.lambdaurora.lambdacontrols.LambdaControls;
import me.lambdaurora.lambdacontrols.util.LambdaKeyBinding;
import net.minecraft.client.gui.screen.ChatScreen;
import net.minecraft.client.gui.screen.GameMenuScreen;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.ingame.InventoryScreen;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.gui.widget.TexturedButtonWidget;
import net.minecraft.server.network.packet.PlayerActionC2SPacket;
import net.minecraft.text.LiteralText;
import net.minecraft.util.Arm;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import org.jetbrains.annotations.NotNull;
/**
* Represents the touchscreen overlay
*/
public class TouchscreenOverlay extends Screen
{
public static final Identifier WIDGETS_LOCATION = new Identifier("lambdacontrols", "textures/gui/widgets.png");
private LambdaControls mod;
private TouchscreenButtonWidget start_sneak_button;
private TouchscreenButtonWidget end_sneak_button;
public TouchscreenOverlay(@NotNull LambdaControls mod)
{
super(new LiteralText("Touchscreen overlay"));
this.mod = mod;
this.passEvents = true;
}
@Override
public boolean shouldCloseOnEsc()
{
return false;
}
@Override
public boolean isPauseScreen()
{
return false;
}
@Override
public void onClose()
{
super.onClose();
}
private void pause_game(boolean bl)
{
if (this.minecraft == null)
return;
boolean bl2 = this.minecraft.isIntegratedServerRunning() && !this.minecraft.getServer().isRemote();
if (bl2) {
this.minecraft.openScreen(new GameMenuScreen(!bl));
this.minecraft.getSoundManager().pauseAll();
} else {
this.minecraft.openScreen(new GameMenuScreen(true));
}
}
@Override
protected void init()
{
super.init();
int scaled_width = this.minecraft.window.getScaledWidth();
int scaled_height = this.minecraft.window.getScaledHeight();
this.addButton(new TexturedButtonWidget(scaled_width / 2 - 20, 0, 20, 20, 0, 106, 20, ButtonWidget.WIDGETS_LOCATION, 256, 256,
btn -> this.minecraft.openScreen(new ChatScreen("")), ""));
this.addButton(new TexturedButtonWidget(scaled_width / 2, 0, 20, 20, 0, 0, 20, WIDGETS_LOCATION, 256, 256,
btn -> this.pause_game(false)));
// Inventory buttons.
int inventory_button_x = scaled_width / 2;
int inventory_button_y = scaled_height - 16 - 5;
if (this.minecraft.options.mainArm == Arm.LEFT) {
inventory_button_x = inventory_button_x - 91 - 24;
} else {
inventory_button_x = inventory_button_x + 91 + 4;
}
this.addButton(new TexturedButtonWidget(inventory_button_x, inventory_button_y, 20, 20, 20, 0, 20, WIDGETS_LOCATION, 256, 256,
btn -> {
if (this.minecraft.interactionManager.hasRidingInventory()) {
this.minecraft.player.openRidingInventory();
} else {
this.minecraft.getTutorialManager().onInventoryOpened();
this.minecraft.openScreen(new InventoryScreen(this.minecraft.player));
}
}));
int jump_button_x, swap_hands_x, sneak_button_x;
int sneak_button_y = scaled_height - 10 - 40 - 5;
if (this.mod.config.get_hud_side() == HudSide.LEFT) {
jump_button_x = scaled_width - 20 - 20;
swap_hands_x = jump_button_x - 5 - 20;
sneak_button_x = 10 + 20 + 5;
} else {
jump_button_x = 20;
swap_hands_x = jump_button_x + 5 + 20;
sneak_button_x = scaled_width - 10 - 40 - 5;
}
// Swap items hand.
this.addButton(new TouchscreenButtonWidget(swap_hands_x, scaled_height - 5 - 20 - 40, 20, 20, 0, 0, 20, WIDGETS_LOCATION,
state -> {
if (state) {
if (!this.minecraft.player.isSpectator()) {
this.minecraft.getNetworkHandler().sendPacket(new PlayerActionC2SPacket(PlayerActionC2SPacket.Action.SWAP_HELD_ITEMS, BlockPos.ORIGIN, Direction.DOWN));
}
}
}));
// Drop
this.addButton(new TouchscreenButtonWidget(swap_hands_x, scaled_height - 40, 20, 20, 0, 0, 20, WIDGETS_LOCATION,
state -> ((LambdaKeyBinding) this.minecraft.options.keyDrop).handle_press_state(state)));
// Jump keys
this.addButton(new TouchscreenButtonWidget(jump_button_x, scaled_height - 40, 20, 20, 0, 40, 20, WIDGETS_LOCATION,
state -> ((LambdaKeyBinding) this.minecraft.options.keyJump).handle_press_state(state)));
// Movements keys
this.addButton((this.start_sneak_button = new TouchscreenButtonWidget(sneak_button_x, sneak_button_y, 20, 20, 0, 120, 20, WIDGETS_LOCATION,
state -> {
if (state) {
((LambdaKeyBinding) this.minecraft.options.keySneak).handle_press_state(true);
this.start_sneak_button.visible = false;
this.end_sneak_button.visible = true;
}
})));
this.addButton((this.end_sneak_button = new TouchscreenButtonWidget(sneak_button_x, sneak_button_y, 20, 20, 20, 120, 20, WIDGETS_LOCATION,
state -> {
if (state) {
((LambdaKeyBinding) this.minecraft.options.keySneak).handle_press_state(false);
this.end_sneak_button.visible = false;
this.start_sneak_button.visible = true;
}
})));
this.end_sneak_button.visible = false;
this.addButton(new TouchscreenButtonWidget(sneak_button_x, sneak_button_y - 5 - 20, 20, 20, 0, 80, 20, WIDGETS_LOCATION,
state -> ((LambdaKeyBinding) this.minecraft.options.keyForward).handle_press_state(state)));
this.addButton(new TouchscreenButtonWidget(sneak_button_x + 20 + 5, sneak_button_y, 20, 20, 20, 80, 20, WIDGETS_LOCATION,
state -> ((LambdaKeyBinding) this.minecraft.options.keyRight).handle_press_state(state)));
this.addButton(new TouchscreenButtonWidget(sneak_button_x, sneak_button_y + 20 + 5, 20, 20, 40, 80, 20, WIDGETS_LOCATION,
state -> ((LambdaKeyBinding) this.minecraft.options.keyBack).handle_press_state(state)));
this.addButton(new TouchscreenButtonWidget(sneak_button_x - 20 - 5, sneak_button_y, 20, 20, 60, 80, 20, WIDGETS_LOCATION,
state -> ((LambdaKeyBinding) this.minecraft.options.keyLeft).handle_press_state(state)));
}
@Override
public void render(int mouseX, int mouseY, float delta)
{
super.render(mouseX, mouseY, delta);
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package me.lambdaurora.lambdacontrols.mixin;
import me.lambdaurora.lambdacontrols.LambdaControls;
import me.lambdaurora.lambdacontrols.gui.LambdaControlsHud;
import me.lambdaurora.lambdacontrols.util.CustomInGameHud;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.hud.InGameHud;
import org.jetbrains.annotations.NotNull;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(InGameHud.class)
public class InGameHudMixin implements CustomInGameHud
{
private LambdaControlsHud lambdacontrols_hud;
@Inject(method = "<init>", at = @At("RETURN"))
public void on_new(MinecraftClient client, CallbackInfo ci)
{
this.lambdacontrols_hud = new LambdaControlsHud(client, LambdaControls.get());
}
@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/hud/InGameHud;renderMountHealth()V"))
public void on_render(float tick_delta, CallbackInfo ci)
{
lambdacontrols_hud.render(tick_delta);
}
@Override
public @NotNull LambdaControlsHud get_lambdacontrols_hud()
{
return this.lambdacontrols_hud;
}
}

View File

@@ -11,8 +11,13 @@ package me.lambdaurora.lambdacontrols.mixin;
import me.lambdaurora.lambdacontrols.ControlsMode;
import me.lambdaurora.lambdacontrols.LambdaControls;
import me.lambdaurora.lambdacontrols.gui.TouchscreenOverlay;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.util.Window;
import org.jetbrains.annotations.Nullable;
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;
@@ -20,6 +25,14 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(MinecraftClient.class)
public abstract class MinecraftClientMixin
{
@Shadow
public Window window;
@Shadow
public boolean skipGameRender;
@Shadow public Screen currentScreen;
@Inject(method = "init", at = @At("RETURN"))
private void on_init(CallbackInfo ci)
{
@@ -32,4 +45,16 @@ public abstract class MinecraftClientMixin
if (LambdaControls.get().config.get_controls_mode() == ControlsMode.CONTROLLER)
LambdaControls.get().on_tick((MinecraftClient) (Object) this);
}
@Inject(method = "openScreen", at = @At("RETURN"))
private void on_open_screen(@Nullable Screen screen, CallbackInfo ci)
{
LambdaControls mod = LambdaControls.get();
if (screen == null && mod.config.get_controls_mode() == ControlsMode.TOUCHSCREEN) {
screen = new TouchscreenOverlay(mod);
screen.init(((MinecraftClient) (Object) this), this.window.getScaledWidth(), this.window.getScaledHeight());
this.skipGameRender = false;
this.currentScreen = screen;
}
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package me.lambdaurora.lambdacontrols.mixin;
import me.lambdaurora.lambdacontrols.ControlsMode;
import me.lambdaurora.lambdacontrols.LambdaControls;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.Mouse;
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;
@Mixin(Mouse.class)
public class MouseMixin
{
@Shadow
@Final
private MinecraftClient client;
@Shadow
private double x;
@Shadow
private double y;
@Inject(method = "lockCursor", at = @At("HEAD"), cancellable = true)
private void on_mouse_locked(CallbackInfo ci)
{
if (LambdaControls.get().config.get_controls_mode() == ControlsMode.TOUCHSCREEN)
ci.cancel();
}
}

View File

@@ -0,0 +1,21 @@
/*
* Copyright © 2019 LambdAurora <aurora42lambda@gmail.com>
*
* This file is part of LambdaControls.
*
* Licensed under the MIT license. For more information,
* see the LICENSE file.
*/
package me.lambdaurora.lambdacontrols.util;
import me.lambdaurora.lambdacontrols.gui.LambdaControlsHud;
import org.jetbrains.annotations.NotNull;
/**
* Represents a custom ingame hud with an accessor to an added hud.
*/
public interface CustomInGameHud
{
@NotNull LambdaControlsHud get_lambdacontrols_hud();
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

View File

@@ -4,8 +4,8 @@
controls = "default"
[hud]
# Dertermines which side is used depending of the main hand.
side = "right_handed"
# Dertermines where the movements buttons are.
side = "left"
# Controller settings
[controller]

View File

@@ -26,7 +26,8 @@
"depends": {
"fabricloader": ">=0.4.0",
"fabric": "*",
"minecraft": "1.14.x"
"minecraft": "1.14.x",
"cotton-client-commands": ">=0.4.2+1.14.3-SNAPSHOT"
},
"suggests": {
"flamingo": "*"

View File

@@ -3,8 +3,10 @@
"package": "me.lambdaurora.lambdacontrols.mixin",
"compatibilityLevel": "JAVA_8",
"client": [
"InGameHudMixin",
"KeyBindingMixin",
"MinecraftClientMixin",
"KeyBindingMixin"
"MouseMixin"
],
"injectors": {
"defaultRequire": 1