From dd173836ff010c7de2f24a7c44dfe75324d4436c Mon Sep 17 00:00:00 2001 From: Motschen Date: Wed, 21 Sep 2022 20:58:27 +0200 Subject: [PATCH] MidnightControls 1.6.0 - Stability, QoL, Cleanup & Compat - Fixed camera choppiness (especially noticeable on low framerates, closes #38) - Asset improvements kindly contributed by @spudpiggy - Button tips now adjust properly to the scaled width of the window (closes #95) - Make 'Back' binding configurable (closes #93) - Add config option to disable the button in the controls screen (closes #97) - Add compatibility with the Inventory Tabs mod (closes #100) - Improve Emotecraft compatibility - Add radial menu listing unbound keys (closes #101) - Fix disabling the HUD not hiding the tips in container screens (closes #104) - Fix 'Back' button not working correctly - Fix recipe book not switching tab via shoulder buttons in Crafting Table and Furnace screens - Support scrolling in Stonecutter --- build.gradle | 2 +- gradle.properties | 2 +- .../client/MidnightControlsConfig.java | 8 ++-- .../client/MidnightInput.java | 33 +++++++++---- .../client/compat/CompatHandler.java | 7 +++ .../client/compat/EMICompat.java | 3 ++ .../client/gui/MidnightControlsHud.java | 45 ++++++++++-------- .../client/mixin/HandledScreenMixin.java | 28 +++++------ .../assets/midnightcontrols/lang/de_de.json | 20 +++----- .../assets/midnightcontrols/lang/en_us.json | 42 ++++++++-------- .../textures/gui/controller_buttons.png | Bin 4402 -> 4398 bytes .../resourcepacks/bedrock/pack.mcmeta | 2 +- .../textures/gui/controller_buttons.png | Bin 7943 -> 4207 bytes .../resourcepacks/legacy/pack.mcmeta | 2 +- 14 files changed, 106 insertions(+), 88 deletions(-) diff --git a/build.gradle b/build.gradle index 264e344..7c95d58 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'fabric-loom' version '0.11-SNAPSHOT' + id 'fabric-loom' version '0.12-SNAPSHOT' id 'java-library' id 'maven-publish' id 'com.github.johnrengelman.shadow' version '7.0.0' diff --git a/gradle.properties b/gradle.properties index 41202f6..59a6b42 100644 --- a/gradle.properties +++ b/gradle.properties @@ -18,7 +18,7 @@ modrinth_id=bXX9h73M fabric_version=0.60.0+1.19.2 sodium_version=mc1.19.2-0.4.4 spruceui_version=4.0.0+1.19 -midnightlib_version=0.6.0 +midnightlib_version=0.6.1 modmenu_version=4.0.6 emotecraft_version=2.1.3-SNAPSHOT-build.29-MC1.19-fabric bendylib_version=2.0.+ diff --git a/src/main/java/eu/midnightdust/midnightcontrols/client/MidnightControlsConfig.java b/src/main/java/eu/midnightdust/midnightcontrols/client/MidnightControlsConfig.java index 0b21567..7e0058f 100644 --- a/src/main/java/eu/midnightdust/midnightcontrols/client/MidnightControlsConfig.java +++ b/src/main/java/eu/midnightdust/midnightcontrols/client/MidnightControlsConfig.java @@ -54,7 +54,7 @@ public class MidnightControlsConfig extends MidnightConfig { @Entry(name = "midnightcontrols.menu.left_dead_zone") public static double leftDeadZone = 0.25; @Entry(name = "midnightcontrols.menu.invert_right_y_axis") public static boolean invertRightYAxis = false; @Entry(name = "midnightcontrols.menu.invert_right_x_axis") public static boolean invertRightXAxis = false; - @Entry(name = "midnightcontrols.menu.rotation_speed") public static double rotationSpeed = 30.0; //used for x axis, name kept for compatability + @Entry(name = "midnightcontrols.menu.rotation_speed") public static double rotationSpeed = 40.0; //used for x-axis, name kept for compatability @Entry(name = "midnightcontrols.menu.y_axis_rotation_speed") public static double yAxisRotationSpeed = rotationSpeed; @Entry(name = "midnightcontrols.menu.mouse_speed") public static double mouseSpeed = 25.0; @Entry(name = "midnightcontrols.menu.unfocused_input") public static boolean unfocusedInput = false; @@ -294,7 +294,7 @@ public class MidnightControlsConfig extends MidnightConfig { leftDeadZone = 0.25; invertRightYAxis = false; invertRightXAxis = false; - rotationSpeed = 30.0; + rotationSpeed = 40.0; yAxisRotationSpeed = rotationSpeed; mouseSpeed = 25.0; unfocusedInput = false; @@ -325,8 +325,8 @@ public class MidnightControlsConfig extends MidnightConfig { else if (controller.contains("steam deck")) return ControllerType.STEAM_DECK; else if (controller.contains("steam")) return ControllerType.STEAM_CONTROLLER; else if (controller.contains("dualsense")) return ControllerType.DUALSENSE; - else if (controller.contains("dualshock") || controller.contains("ps4")) return ControllerType.DUALSHOCK; - else if (controller.contains("switch") || controller.contains("joy-con")) return ControllerType.SWITCH; + else if (controller.contains("dualshock") || controller.contains("ps4") || controller.contains("sony")) return ControllerType.DUALSHOCK; + else if (controller.contains("switch") || controller.contains("joy-con") || controller.contains("wii") || controller.contains("nintendo")) return ControllerType.SWITCH; else if (controller.contains("ouya")) return ControllerType.OUYA; else return ControllerType.DEFAULT; } diff --git a/src/main/java/eu/midnightdust/midnightcontrols/client/MidnightInput.java b/src/main/java/eu/midnightdust/midnightcontrols/client/MidnightInput.java index 458cbf8..32bdb74 100644 --- a/src/main/java/eu/midnightdust/midnightcontrols/client/MidnightInput.java +++ b/src/main/java/eu/midnightdust/midnightcontrols/client/MidnightInput.java @@ -189,8 +189,8 @@ public class MidnightInput { return; if (this.targetYaw != 0.f || this.targetPitch != 0.f) { - float rotationYaw = (float) (client.player.prevYaw + (this.targetYaw * 0.2)); - float rotationPitch = (float) (client.player.prevPitch + (this.targetPitch * 0.2)); + float rotationYaw = (float) (client.player.prevYaw + (this.targetYaw * 0.175)); + float rotationPitch = (float) (client.player.prevPitch + (this.targetPitch * 0.175)); client.player.prevYaw = rotationYaw; client.player.prevPitch = MathHelper.clamp(rotationPitch, -90.f, 90.f); client.player.setYaw(rotationYaw); @@ -199,8 +199,19 @@ public class MidnightInput { client.player.getVehicle().onPassengerLookAround(client.player); } client.getTutorialManager().onUpdateMouse(this.targetPitch, this.targetYaw); + MidnightControlsCompat.HANDLERS.forEach(handler -> handler.handleCamera(client, targetYaw, targetPitch)); + this.onRender(client); } } + /** + * This method is deprecated and will be removed in future versions + * It is just kept, because the current version of 'Do a Barrel Roll' mixins into this method + * + * @param client the client instance + */ + @Deprecated + public void onRender(@NotNull MinecraftClient client) { + } /** * This method is called when a Screen is opened. @@ -504,21 +515,25 @@ public class MidnightInput { } else if (client.currentScreen != null) { if (axis == GLFW_GAMEPAD_AXIS_RIGHT_Y && absValue >= deadZone) { float finalValue = value; - client.currentScreen.children().stream().filter(element -> element instanceof SpruceEntryListWidget) + if (client.currentScreen.children().stream().filter(element -> element instanceof SpruceEntryListWidget) .map(element -> (SpruceEntryListWidget) element) .filter(AbstractSpruceWidget::isFocusedOrHovered) - .anyMatch(element -> { - MidnightControls.get().log(String.valueOf(finalValue)); + .noneMatch(element -> { element.mouseScrolled(0.0, 0.0, -finalValue); return true; - }); - client.currentScreen.children().stream().filter(element -> element instanceof EntryListWidget) + }) + && + client.currentScreen.children().stream().filter(element -> element instanceof EntryListWidget) .map(element -> (EntryListWidget) element) .filter(element -> element.getType().isFocused()) - .anyMatch(element -> { + .noneMatch(element -> { element.mouseScrolled(0.0, 0.0, -finalValue); return true; - }); + })) + { + client.currentScreen.mouseScrolled(0.0, 0.0, -(value * 1.5f)); + } + return; } } diff --git a/src/main/java/eu/midnightdust/midnightcontrols/client/compat/CompatHandler.java b/src/main/java/eu/midnightdust/midnightcontrols/client/compat/CompatHandler.java index 04beb0e..ffb367d 100644 --- a/src/main/java/eu/midnightdust/midnightcontrols/client/compat/CompatHandler.java +++ b/src/main/java/eu/midnightdust/midnightcontrols/client/compat/CompatHandler.java @@ -33,6 +33,13 @@ public interface CompatHandler { */ void handle(@NotNull MidnightControlsClient mod); + /** + * Handles custom camera updates + * + * @param client the Minecraft client instance + */ + default void handleCamera(@NotNull MinecraftClient client, double targetYaw, double targetPitch) {}; + /** * Returns whether the mouse is required on the specified screen. * diff --git a/src/main/java/eu/midnightdust/midnightcontrols/client/compat/EMICompat.java b/src/main/java/eu/midnightdust/midnightcontrols/client/compat/EMICompat.java index aadcd29..7e02be8 100644 --- a/src/main/java/eu/midnightdust/midnightcontrols/client/compat/EMICompat.java +++ b/src/main/java/eu/midnightdust/midnightcontrols/client/compat/EMICompat.java @@ -42,4 +42,7 @@ public class EMICompat implements CompatHandler { public static boolean isEMIEnabled() { return EmiConfig.enabled; } + public static boolean isSearchBarCentered() { + return EmiConfig.centerSearchBar; + } } diff --git a/src/main/java/eu/midnightdust/midnightcontrols/client/gui/MidnightControlsHud.java b/src/main/java/eu/midnightdust/midnightcontrols/client/gui/MidnightControlsHud.java index e4945bd..6c38257 100644 --- a/src/main/java/eu/midnightdust/midnightcontrols/client/gui/MidnightControlsHud.java +++ b/src/main/java/eu/midnightdust/midnightcontrols/client/gui/MidnightControlsHud.java @@ -52,7 +52,7 @@ public class MidnightControlsHud extends Hud { private String attackAction = ""; private String placeAction = ""; private int ticksDisplayedCrosshair = 0; - private static float scale = 1f; + private static boolean isCrammed = false; public MidnightControlsHud(@NotNull MidnightControlsClient mod) { super(new Identifier(MidnightControlsConstants.NAMESPACE, "hud/button_indicator")); @@ -71,26 +71,23 @@ public class MidnightControlsHud extends Hud { this.dropItemButtonWidth = MidnightControlsRenderer.getBindingIconWidth(ButtonBinding.DROP_ITEM); this.attackButtonWidth = MidnightControlsRenderer.getBindingIconWidth(ButtonBinding.ATTACK); this.useButtonWidth = MidnightControlsRenderer.getBindingIconWidth(ButtonBinding.USE); - if (client.getWindow().getScaleFactor() >= 4) { - scale = 0.75f; - } else scale = 1f; } /** - * Renders the midnightcontrols' HUD. + * Renders the MidnightControls HUD. */ @Override public void render(MatrixStack matrices, float tickDelta) { if (this.client == null) return; if (MidnightControlsConfig.controlsMode == ControlsMode.CONTROLLER && this.client.currentScreen == null) { + isCrammed = client.getWindow().getScaledWidth() < 560; int y = bottom(2); matrices.push(); - if (scale != 1f) matrices.scale(scale,scale,scale); - this.renderFirstIcons(matrices, MidnightControlsConfig.hudSide == HudSide.LEFT ? 2 : (int) ((client.getWindow().getScaledWidth() - 2) * (1 / scale)), y); - this.renderSecondIcons(matrices, MidnightControlsConfig.hudSide == HudSide.RIGHT ? 2 : (int) ((client.getWindow().getScaledWidth() - 2) * (1 / scale)), y); - this.renderFirstSection(matrices, MidnightControlsConfig.hudSide == HudSide.LEFT ? 2 : (int) ((client.getWindow().getScaledWidth() - 2) * (1 / scale)), y); - this.renderSecondSection(matrices, MidnightControlsConfig.hudSide == HudSide.RIGHT ? 2 : (int) ((client.getWindow().getScaledWidth() - 2) * (1 / scale)), y); + this.renderFirstIcons(matrices, MidnightControlsConfig.hudSide == HudSide.LEFT ? 2 : client.getWindow().getScaledWidth() - 2, y); + this.renderSecondIcons(matrices, MidnightControlsConfig.hudSide == HudSide.RIGHT ? 2 : client.getWindow().getScaledWidth() - 2, y); + this.renderFirstSection(matrices, MidnightControlsConfig.hudSide == HudSide.LEFT ? 2 : client.getWindow().getScaledWidth() - 2, y); + this.renderSecondSection(matrices, MidnightControlsConfig.hudSide == HudSide.RIGHT ? 2 : client.getWindow().getScaledWidth() - 2, y); matrices.pop(); } @@ -111,8 +108,12 @@ public class MidnightControlsHud extends Hud { public void renderFirstIcons(MatrixStack matrices, int x, int y) { int offset = 2 + this.inventoryWidth + this.inventoryButtonWidth + 4; int currentX = MidnightControlsConfig.hudSide == HudSide.LEFT ? x : x - this.inventoryButtonWidth; - this.drawButton(matrices, currentX, y, ButtonBinding.INVENTORY, true); - this.drawButton(matrices, currentX += (MidnightControlsConfig.hudSide == HudSide.LEFT ? offset : -offset), y, ButtonBinding.SWAP_HANDS, true); + if (!ButtonBinding.INVENTORY.isNotBound()) this.drawButton(matrices, currentX, y, ButtonBinding.INVENTORY, true); + if (isCrammed) { + offset = 0; + y -= 20; + } + if (!ButtonBinding.SWAP_HANDS.isNotBound()) this.drawButton(matrices, currentX += (MidnightControlsConfig.hudSide == HudSide.LEFT ? offset : -offset), y, ButtonBinding.SWAP_HANDS, true); offset = 2 + this.swapHandsWidth + this.dropItemButtonWidth + 4; if (this.client.options.getShowSubtitles().getValue() && MidnightControlsConfig.hudSide == HudSide.RIGHT) { currentX += -offset; @@ -120,13 +121,13 @@ public class MidnightControlsHud extends Hud { currentX = MidnightControlsConfig.hudSide == HudSide.LEFT ? x : x - this.dropItemButtonWidth; y -= 20; } - this.drawButton(matrices, currentX, y, ButtonBinding.DROP_ITEM, !this.client.player.getMainHandStack().isEmpty()); + if (!ButtonBinding.DROP_ITEM.isNotBound()) this.drawButton(matrices, currentX, y, ButtonBinding.DROP_ITEM, !this.client.player.getMainHandStack().isEmpty()); } public void renderSecondIcons(MatrixStack matrices, int x, int y) { int offset; int currentX = x; - if (!this.placeAction.isEmpty()) { + if (!this.placeAction.isEmpty() && (!ButtonBinding.USE.isNotBound()) ) { if (MidnightControlsConfig.hudSide == HudSide.LEFT) currentX -= this.useButtonWidth; this.drawButton(matrices, currentX, y, ButtonBinding.USE, true); @@ -142,22 +143,26 @@ public class MidnightControlsHud extends Hud { if (MidnightControlsConfig.hudSide == HudSide.LEFT) currentX -= this.attackButtonWidth; - this.drawButton(matrices, currentX, y, ButtonBinding.ATTACK, this.attackWidth != 0); + if (!ButtonBinding.ATTACK.isNotBound()) this.drawButton(matrices, currentX, y, ButtonBinding.ATTACK, this.attackWidth != 0); } public void renderFirstSection(MatrixStack matrices, int x, int y) { int currentX = MidnightControlsConfig.hudSide == HudSide.LEFT ? x + this.inventoryButtonWidth + 2 : x - this.inventoryButtonWidth - 2 - this.inventoryWidth; - this.drawTip(matrices, currentX, y, ButtonBinding.INVENTORY, true); + if (!ButtonBinding.INVENTORY.isNotBound()) this.drawTip(matrices, currentX, y, ButtonBinding.INVENTORY, true); currentX += MidnightControlsConfig.hudSide == HudSide.LEFT ? this.inventoryWidth + 4 + this.swapHandsButtonWidth + 2 : -this.swapHandsWidth - 2 - this.swapHandsButtonWidth - 4; - this.drawTip(matrices, currentX, y, ButtonBinding.SWAP_HANDS, true); + if (isCrammed) { + currentX = MidnightControlsConfig.hudSide == HudSide.LEFT ? x + this.inventoryButtonWidth + 2 : x - this.inventoryButtonWidth - 2 - this.inventoryWidth; + y -= 20; + } + if (!ButtonBinding.SWAP_HANDS.isNotBound()) this.drawTip(matrices, currentX, y, ButtonBinding.SWAP_HANDS, true); if (this.client.options.getShowSubtitles().getValue() && MidnightControlsConfig.hudSide == HudSide.RIGHT) { currentX += -this.dropItemWidth - 2 - this.dropItemButtonWidth - 4; } else { y -= 20; currentX = MidnightControlsConfig.hudSide == HudSide.LEFT ? x + this.dropItemButtonWidth + 2 : x - this.dropItemButtonWidth - 2 - this.dropItemWidth; } - this.drawTip(matrices, currentX, y, ButtonBinding.DROP_ITEM, !this.client.player.getMainHandStack().isEmpty()); + if (!ButtonBinding.DROP_ITEM.isNotBound()) this.drawTip(matrices, currentX, y, ButtonBinding.DROP_ITEM, !this.client.player.getMainHandStack().isEmpty()); } public void renderSecondSection(MatrixStack matrices, int x, int y) { @@ -178,7 +183,7 @@ public class MidnightControlsHud extends Hud { currentX += MidnightControlsConfig.hudSide == HudSide.RIGHT ? this.attackButtonWidth + 2 : -this.attackButtonWidth - 2 - this.attackWidth; - this.drawTip(matrices, currentX, y, this.attackAction, this.attackWidth != 0); + if (!ButtonBinding.ATTACK.isNotBound()) this.drawTip(matrices, currentX, y, this.attackAction, this.attackWidth != 0); } @Override @@ -254,7 +259,7 @@ public class MidnightControlsHud extends Hud { } private int bottom(int y) { - return (int) ((this.client.getWindow().getScaledHeight() * (1/scale)) - y - MidnightControlsRenderer.ICON_SIZE); + return (this.client.getWindow().getScaledHeight() - y - MidnightControlsRenderer.ICON_SIZE); } private int width(@NotNull ButtonBinding binding) { diff --git a/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/HandledScreenMixin.java b/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/HandledScreenMixin.java index 29d1337..825c90c 100644 --- a/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/HandledScreenMixin.java +++ b/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/HandledScreenMixin.java @@ -38,8 +38,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; */ @Mixin(HandledScreen.class) public abstract class HandledScreenMixin implements HandledScreenAccessor { - @Unique private static float scale = 1f; - @Accessor("x") public abstract int getX(); @@ -58,30 +56,26 @@ public abstract class HandledScreenMixin implements HandledScreenAccessor { @Inject(method = "render", at = @At("RETURN")) public void onRender(MatrixStack matrices, int mouseX, int mouseY, float delta, CallbackInfo ci) { - if (MidnightControlsConfig.controlsMode == ControlsMode.CONTROLLER) { + if (MidnightControlsConfig.controlsMode == ControlsMode.CONTROLLER && MidnightControlsConfig.hudEnable) { var client = MinecraftClient.getInstance(); - if (client.getWindow().getScaleFactor() >= 4) { - scale = 0.75f; - } else scale = 1f; matrices.push(); - if (scale != 1f) matrices.scale(scale,scale,scale); - int x = 2, y = (int) (client.getWindow().getScaledHeight() * (1 / scale) - 2 - MidnightControlsRenderer.ICON_SIZE); + int x = 2, y = client.getWindow().getScaledHeight() - 2 - MidnightControlsRenderer.ICON_SIZE; if (MidnightControlsCompat.isEMIPresent() && EMICompat.isEMIEnabled()) { - x += 40 * (1 / scale); + x += 42; } - x = MidnightControlsRenderer.drawButtonTip(matrices, x, y, new int[]{GLFW.GLFW_GAMEPAD_BUTTON_A}, "midnightcontrols.action.pickup_all", true, client) + 2; - x = MidnightControlsRenderer.drawButtonTip(matrices, x, y, new int[]{GLFW.GLFW_GAMEPAD_BUTTON_B}, "midnightcontrols.action.exit", true, client) + 2; + if (!ButtonBinding.TAKE_ALL.isNotBound()) x = MidnightControlsRenderer.drawButtonTip(matrices, x, y, ButtonBinding.TAKE_ALL,true, client) + 2; + if (!ButtonBinding.EXIT.isNotBound()) x = MidnightControlsRenderer.drawButtonTip(matrices, x, y, ButtonBinding.EXIT, true, client) + 2; if (MidnightControlsCompat.isReiPresent()) { x = 2; y -= 24; } - if (MidnightControlsCompat.isEMIPresent() && EMICompat.isEMIEnabled()) { - x = (int) (client.getWindow().getScaledWidth() * (1 / scale) - 55 - client.textRenderer.getWidth(Text.translatable("midnightcontrols.action.pickup")) - * (1 / scale) - client.textRenderer.getWidth(Text.translatable("midnightcontrols.action.quick_move")) - - MidnightControlsRenderer.getBindingIconWidth(ButtonBinding.TAKE) - MidnightControlsRenderer.getBindingIconWidth(ButtonBinding.QUICK_MOVE)); + if (MidnightControlsCompat.isEMIPresent() && EMICompat.isEMIEnabled() && EMICompat.isSearchBarCentered()) { + x = client.getWindow().getScaledWidth() - 55 - client.textRenderer.getWidth(Text.translatable("midnightcontrols.action.pickup")) + - client.textRenderer.getWidth(Text.translatable("midnightcontrols.action.quick_move")) + - MidnightControlsRenderer.getBindingIconWidth(ButtonBinding.TAKE) - MidnightControlsRenderer.getBindingIconWidth(ButtonBinding.QUICK_MOVE); } - x = MidnightControlsRenderer.drawButtonTip(matrices, x, y, new int[]{GLFW.GLFW_GAMEPAD_BUTTON_X}, "midnightcontrols.action.pickup", true, client); - MidnightControlsRenderer.drawButtonTip(matrices, x, y, new int[]{GLFW.GLFW_GAMEPAD_BUTTON_Y}, "midnightcontrols.action.quick_move", true, client); + if (!ButtonBinding.TAKE.isNotBound()) x = MidnightControlsRenderer.drawButtonTip(matrices, x, y, ButtonBinding.TAKE, true, client); + if (!ButtonBinding.QUICK_MOVE.isNotBound()) MidnightControlsRenderer.drawButtonTip(matrices, x, y, ButtonBinding.QUICK_MOVE, true, client); matrices.pop(); } } diff --git a/src/main/resources/assets/midnightcontrols/lang/de_de.json b/src/main/resources/assets/midnightcontrols/lang/de_de.json index 07aaffc..5d32f07 100644 --- a/src/main/resources/assets/midnightcontrols/lang/de_de.json +++ b/src/main/resources/assets/midnightcontrols/lang/de_de.json @@ -4,10 +4,11 @@ "key.midnightcontrols.look_left": "Nach links schauen", "key.midnightcontrols.look_right": "Nach rechts schauen", "key.midnightcontrols.look_up": "Nach oben schauen", - "key.midnightcontrols.ring": "Zeige Steuerungsring", + "key.midnightcontrols.ring": "Öffne Ring mit ungebundenen Aktionen", "midnightcontrols.action.attack": "Angreifen", "midnightcontrols.action.back": "Zurück", "midnightcontrols.action.chat": "Chat öffnen", + "midnightcontrols.action.controls_ring": "Öffne Ring mit ungebundenen Aktionen", "midnightcontrols.action.drop_item": "Item droppen", "midnightcontrols.action.exit": "Schließen", "midnightcontrols.action.forward": "Vorwärts", @@ -40,8 +41,6 @@ "midnightcontrols.action.zoom_in": "Zoom erhöhen", "midnightcontrols.action.zoom_out": "Zoom verringern", "midnightcontrols.action.zoom_reset": "Zoom zurücksetzen", - "midnightcontrols.action.key.emotecraft.fastchoose": "Emote Schnellauswahl", - "midnightcontrols.action.key.emotecraft.stop": "Emote stoppen", "midnightcontrols.button.left_bumper": "Linke Schultertaste", "midnightcontrols.button.right_bumper": "Rechte Schultertaste", "midnightcontrols.button.back": "Zurück", @@ -78,16 +77,11 @@ "midnightcontrols.controller.mappings.error.write": "Fehler beim Schreiben der Controller Mappings.", "midnightcontrols.controller.mappings.updated": "Mappings aktualisiert!", "midnightcontrols.controller_type.default": "Standard", - "midnightcontrols.controller_type.dualshock": "DualShock", - "midnightcontrols.controller_type.switch": "Switch", - "midnightcontrols.controller_type.xbox": "Xbox", - "midnightcontrols.controller_type.steam": "Steam", - "midnightcontrols.controller_type.ouya": "OUYA", "midnightcontrols.controls_mode.default": "Tastatur/Maus", "midnightcontrols.controls_mode.controller": "Controller", "midnightcontrols.controls_mode.touchscreen": "Touchscreen (In Arbeit)", - "midnightcontrols.hud_side.left": "links", - "midnightcontrols.hud_side.right": "rechts", + "midnightcontrols.hud_side.left": "Links", + "midnightcontrols.hud_side.right": "Rechts", "midnightcontrols.menu.analog_movement": "Analoge Bewegung", "midnightcontrols.menu.auto_switch_mode": "Automatischer Wechsel", "midnightcontrols.menu.controller": "Controller", @@ -103,7 +97,7 @@ "midnightcontrols.menu.invert_right_x_axis": "X rechts umkehren", "midnightcontrols.menu.invert_right_y_axis": "Y rechts umkehren", "midnightcontrols.menu.keyboard_controls": "Tastatureinstellungen...", - "midnightcontrols.menu.left_dead_zone": "Linke tote Zone", + "midnightcontrols.menu.left_dead_zone": "Tote Zone des linken Sticks", "midnightcontrols.menu.mappings.open_input_str": "Öffne den Controller-Mapping Editor", "midnightcontrols.menu.max_left_x_value": "Maximalwert Linke X-Achse", "midnightcontrols.menu.max_left_y_value": "Maximalwert Linke Y-Achse", @@ -113,14 +107,14 @@ "midnightcontrols.menu.reacharound.horizontal": "Vorderes Blockplatzieren", "midnightcontrols.menu.reacharound.vertical": "Vertikales Umgreifen", "midnightcontrols.menu.reload_controller_mappings": "Controller-Mappings neuladen", - "midnightcontrols.menu.right_dead_zone": "Rechte tote Zone", + "midnightcontrols.menu.right_dead_zone": "Tote Zone des rechten Sticks", "midnightcontrols.menu.rotation_speed": "Rotationsgeschwindigkeit (X-Achse)", "midnightcontrols.menu.y_axis_rotation_speed": "Rotationsgeschwindigkeit (Y-Achse)", "midnightcontrols.menu.separator.controller": "Controller", "midnightcontrols.menu.separator.general": "Generell", "midnightcontrols.menu.title": "MidnightControls - Einstellungen", "midnightcontrols.menu.title.controller": "Controlleroptionen", - "midnightcontrols.menu.title.controller_controls": "Controller Steuerung", + "midnightcontrols.menu.title.controller_controls": "Controller Aktionen", "midnightcontrols.menu.title.gameplay": "Gameplay Optionen", "midnightcontrols.menu.title.general": "Generelle Optionen", "midnightcontrols.menu.title.hud": "HUD Optionen", diff --git a/src/main/resources/assets/midnightcontrols/lang/en_us.json b/src/main/resources/assets/midnightcontrols/lang/en_us.json index 845f27f..b94d302 100644 --- a/src/main/resources/assets/midnightcontrols/lang/en_us.json +++ b/src/main/resources/assets/midnightcontrols/lang/en_us.json @@ -4,7 +4,7 @@ "key.midnightcontrols.look_left": "Look left", "key.midnightcontrols.look_right": "Look right", "key.midnightcontrols.look_up": "Look up", - "key.midnightcontrols.ring": "Show controls ring", + "key.midnightcontrols.ring": "Open Unbound Keybind Ring", "midnightcontrols.action.attack": "Attack", "midnightcontrols.action.back": "Back", "midnightcontrols.action.chat": "Open Chat", @@ -93,17 +93,17 @@ "midnightcontrols.controller_type.default": "Default", "midnightcontrols.controller_type.dualshock": "DualShock", "midnightcontrols.controller_type.dualsense": "DualSense", - "midnightcontrols.controller_type.switch": "Switch", - "midnightcontrols.controller_type.xbox": "Xbox", - "midnightcontrols.controller_type.xbox_360": "Xbox 360", + "midnightcontrols.controller_type.switch": "Switch/Wii Controller", + "midnightcontrols.controller_type.xbox": "Xbox One/Series Controller", + "midnightcontrols.controller_type.xbox_360": "Xbox 360 Controller", "midnightcontrols.controller_type.steam_controller": "Steam Controller", "midnightcontrols.controller_type.steam_deck": "Steam Deck", - "midnightcontrols.controller_type.ouya": "OUYA", + "midnightcontrols.controller_type.ouya": "OUYA Controller", "midnightcontrols.controls_mode.default": "Keyboard/Mouse", "midnightcontrols.controls_mode.controller": "Controller", "midnightcontrols.controls_mode.touchscreen": "Touchscreen (WIP)", - "midnightcontrols.hud_side.left": "left", - "midnightcontrols.hud_side.right": "right", + "midnightcontrols.hud_side.left": "Left", + "midnightcontrols.hud_side.right": "Right", "midnightcontrols.menu.analog_movement": "Analog Movement", "midnightcontrols.menu.auto_switch_mode": "Auto Switch Mode", "midnightcontrols.menu.controller": "Controller", @@ -119,7 +119,7 @@ "midnightcontrols.menu.invert_right_x_axis": "Invert Right X", "midnightcontrols.menu.invert_right_y_axis": "Invert Right Y", "midnightcontrols.menu.keyboard_controls": "Keyboard Controls...", - "midnightcontrols.menu.left_dead_zone": "Left Dead Zone", + "midnightcontrols.menu.left_dead_zone": "Left Stick Dead Zone", "midnightcontrols.menu.mappings.open_input_str": "Open Mappings File Editor", "midnightcontrols.menu.max_left_x_value": "Left X Axis Max Value", "midnightcontrols.menu.max_left_y_value": "Left Y Axis Max Value", @@ -129,14 +129,14 @@ "midnightcontrols.menu.reacharound.horizontal": "Front Block Placing", "midnightcontrols.menu.reacharound.vertical": "Vertical Reacharound", "midnightcontrols.menu.reload_controller_mappings": "Reload Controller Mappings", - "midnightcontrols.menu.right_dead_zone": "Right Dead Zone", + "midnightcontrols.menu.right_dead_zone": "Right Stick Dead Zone", "midnightcontrols.menu.rotation_speed": "X Axis Rotation Speed", "midnightcontrols.menu.y_axis_rotation_speed": "Y Axis Rotation Speed", "midnightcontrols.menu.separator.controller": "Controller", "midnightcontrols.menu.separator.general": "General", "midnightcontrols.menu.title": "MidnightControls - Settings", "midnightcontrols.menu.title.controller": "Controller Options", - "midnightcontrols.menu.title.controller_controls": "Controller Controls", + "midnightcontrols.menu.title.controller_controls": "Controller Bindings", "midnightcontrols.menu.title.gameplay": "Gameplay Options", "midnightcontrols.menu.title.general": "General Options", "midnightcontrols.menu.title.hud": "HUD Options", @@ -147,18 +147,18 @@ "midnightcontrols.menu.virtual_mouse.skin": "Virtual Mouse Skin", "midnightcontrols.narrator.unbound": "Unbound %s", "midnightcontrols.not_bound": "Not bound", - "midnightcontrols.tooltip.analog_movement": "Enables analog movement when possible.", - "midnightcontrols.tooltip.auto_switch_mode": "If the controls mode should be switched to Controller automatically if one is connected.", - "midnightcontrols.tooltip.controller2": "Second controller to use, which allows Joy-Cons support for example.", - "midnightcontrols.tooltip.controller_type": "The controller type to display the correct buttons.", + "midnightcontrols.tooltip.analog_movement": "When possible, enables analog movement.", + "midnightcontrols.tooltip.auto_switch_mode": "Whether the controls mode should be switched to Controller automatically if one is connected.", + "midnightcontrols.tooltip.controller2": "Second controller to use, which allows (for example) Joy-Cons support.", + "midnightcontrols.tooltip.controller_type": "The controller type you're using (needed to display the correct buttons)", "midnightcontrols.tooltip.controls_mode": "The controls mode.", - "midnightcontrols.tooltip.double_tap_to_sprint": "Toggles whether the Walk Forwards key makes the player sprint when quickly double-tapped", + "midnightcontrols.tooltip.double_tap_to_sprint": "Toggles whether the Walk Forwards key makes the player sprint when double-tapped quickly", "midnightcontrols.tooltip.fast_block_placing": "While flying in creative mode, enables fast block placing depending on your speed. §cOn some servers this might be considered as cheating.", "midnightcontrols.tooltip.fly_drifting": "While flying, enables Vanilla drifting/inertia.", "midnightcontrols.tooltip.fly_drifting_vertical": "While flying, enables Vanilla vertical drifting/intertia.", "midnightcontrols.tooltip.hud_enable": "Toggles the on-screen controller button indicator.", "midnightcontrols.tooltip.hud_side": "The position of the HUD.", - "midnightcontrols.tooltip.left_dead_zone": "The dead zone for the controller's left analogue stick.", + "midnightcontrols.tooltip.left_dead_zone": "The dead zone for the controller's left analog stick.", "midnightcontrols.tooltip.max_left_x_value": "Changes what the mod considers the highest value for the left X axis. Useful if your axis does not use the full range and seems slow.", "midnightcontrols.tooltip.max_left_y_value": "Changes what the mod considers the highest value for the left Y axis. Useful if your axis does not use the full range and seems slow.", "midnightcontrols.tooltip.max_right_x_value": "Changes what the mod considers the highest value for the right X axis. Useful if your axis does not use the full range and seems slow.", @@ -167,11 +167,11 @@ "midnightcontrols.tooltip.reacharound.horizontal": "Enables front block placing, §cmight be considered cheating on some servers§r.", "midnightcontrols.tooltip.reacharound.vertical": "Enables vertical reacharound, §cmight be considered cheating on some servers§r.", "midnightcontrols.tooltip.reload_controller_mappings": "Reloads the controller mappings file.", - "midnightcontrols.tooltip.right_dead_zone": "The dead zone for the controller's right analogue stick.", - "midnightcontrols.tooltip.rotation_speed": "The camera X Axis rotation speed in controller mode.", - "midnightcontrols.tooltip.y_axis_rotation_speed": "The camera Y Axis rotation speed in controller mode.", - "midnightcontrols.tooltip.unfocused_input": "Allow controller input when the window is not focused.", - "midnightcontrols.tooltip.virtual_mouse": "Enable the virtual mouse which is handful in the case of a splitscreen.", + "midnightcontrols.tooltip.right_dead_zone": "The dead zone for the controller's right analog stick.", + "midnightcontrols.tooltip.rotation_speed": "The camera's X Axis rotation speed in controller mode.", + "midnightcontrols.tooltip.y_axis_rotation_speed": "The camera's Y Axis rotation speed in controller mode.", + "midnightcontrols.tooltip.unfocused_input": "Allows controller input when the window is not focused.", + "midnightcontrols.tooltip.virtual_mouse": "Enables the virtual mouse, which is useful during splitscreen.", "midnightcontrols.virtual_mouse.skin.default_light": "Default Light", "midnightcontrols.virtual_mouse.skin.default_dark": "Default Dark", "midnightcontrols.virtual_mouse.skin.second_light": "Second Light", diff --git a/src/main/resources/resourcepacks/bedrock/assets/midnightcontrols/textures/gui/controller_buttons.png b/src/main/resources/resourcepacks/bedrock/assets/midnightcontrols/textures/gui/controller_buttons.png index 1f9ebd2011a21966dd23592e8ed47a38f5f5606d..086df70e759fb825e141e203f2f5d6474639544d 100644 GIT binary patch literal 4398 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 CDV`kw literal 7943 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