Compare commits

...

9 Commits

Author SHA1 Message Date
Martin Prokoph
f2372cf406 release: 1.11.3-alpha.2 2025-10-01 17:07:27 +02:00
Martin Prokoph
ffa1bb5a33 fix: get debug hud toggle working correctly 2025-10-01 17:06:20 +02:00
Martin Prokoph
1d9a4287d7 fix: touchscreen interaction finger outline 2025-10-01 16:55:55 +02:00
Martin Prokoph
b3a170f862 fix: server list moving entries instead of cycling 2025-10-01 16:55:09 +02:00
Martin Prokoph
15e1b08e8f fix: attack key not working properly for mobs 2025-10-01 16:54:24 +02:00
Martin Prokoph
7660f6b0ee release: 1.11.3-alpha.1 2025-10-01 14:14:20 +02:00
Martin Prokoph
5c1657aef2 feat: more mouse cursors 🐁 2025-10-01 14:13:47 +02:00
Martin Prokoph
830ac38b02 fix: button category names 2025-10-01 14:12:12 +02:00
Martin Prokoph
4d85879c87 feat: add more functionality to MidnightLib-based config
- The plan is to slowly phase out ObsidianUI, as it is not updated fast enough
2025-10-01 14:11:47 +02:00
19 changed files with 388 additions and 83 deletions

View File

@@ -21,6 +21,7 @@ import eu.midnightdust.midnightcontrols.MidnightControls;
import eu.midnightdust.midnightcontrols.MidnightControlsConstants;
import eu.midnightdust.midnightcontrols.MidnightControlsFeature;
import eu.midnightdust.midnightcontrols.client.controller.ButtonBinding;
import eu.midnightdust.midnightcontrols.client.controller.ButtonCategory;
import eu.midnightdust.midnightcontrols.client.controller.Controller;
import eu.midnightdust.midnightcontrols.client.controller.InputManager;
import eu.midnightdust.midnightcontrols.client.enums.ButtonState;
@@ -30,17 +31,29 @@ import eu.midnightdust.midnightcontrols.client.enums.HudSide;
import eu.midnightdust.midnightcontrols.client.enums.VirtualMouseSkin;
import eu.midnightdust.midnightcontrols.client.gui.RingScreen;
import eu.midnightdust.midnightcontrols.client.enums.TouchMode;
import eu.midnightdust.midnightcontrols.client.gui.config.ControllerBindingButton;
import eu.midnightdust.midnightcontrols.client.gui.config.ControllerSelectionButton;
import eu.midnightdust.midnightcontrols.client.virtualkeyboard.KeyboardLayoutManager;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.ChatScreen;
import net.minecraft.client.gui.screen.advancement.AdvancementsScreen;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.gui.widget.PressableTextWidget;
import net.minecraft.client.gui.widget.PressableWidget;
import net.minecraft.client.gui.widget.TextIconButtonWidget;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.glfw.GLFW;
import java.lang.annotation.Annotation;
import java.util.*;
import java.util.regex.Pattern;
import static eu.midnightdust.midnightcontrols.client.MidnightControlsClient.client;
import static eu.midnightdust.midnightcontrols.client.gui.MidnightControlsSettingsScreen.searchNextAvailableController;
import static org.lwjgl.glfw.GLFW.*;
/**
@@ -53,6 +66,7 @@ public class MidnightControlsConfig extends MidnightConfig {
public static final String SCREENS = "screens";
public static final String VISUAL = "visual";
public static final String MISC = "misc";
public static final String BUTTONS = "buttons";
public static boolean isEditing = false;
@Hidden @Entry public static int configVersion = 2;
// General
@@ -152,7 +166,7 @@ public class MidnightControlsConfig extends MidnightConfig {
@Comment(category = SCREENS, centered = true, name="\uD83D\uDD27 UI Modifications") public static Comment _uiMods;
@Entry(category = SCREENS, name = "midnightcontrols.menu.move_chat") public static boolean moveChat = false;
@Entry(category = SCREENS, name = "Enable Shortcut in Controls Options") public static boolean shortcutInControls = true;
@Entry(category = MISC, name = "midnightcontrols.menu.virtual_keyboard_layout") public static String keyboardLayout = "en_US:qwerty";
@Entry(category = MISC) @Hidden public static String keyboardLayout = "en_US:qwerty";
@Entry(category = MISC, name = "Debug") public static boolean debug = false;
@Entry(category = MISC, name = "Excluded Keybindings") public static List<String> excludedKeybindings = Lists.newArrayList("key.forward", "key.left", "key.back", "key.right", "key.jump", "key.sneak", "key.sprint", "key.inventory",
"key.swapOffhand", "key.drop", "key.use", "key.attack", "key.chat", "key.playerlist", "key.screenshot", "key.togglePerspective", "key.smoothCamera", "key.fullscreen", "key.saveToolbarActivator", "key.loadToolbarActivator",
@@ -163,6 +177,55 @@ public class MidnightControlsConfig extends MidnightConfig {
private static Map<String, String> currentBindingProfile = new HashMap<>();
private static Controller prevController;
@Comment(category = BUTTONS) @Condition(requiredModId = "thisModDoesNotExist") public static Comment this_spacer_will_never_be_visible;
public void onTabInit(String tabName, MidnightConfigListWidget list, MidnightConfigScreen screen) {
EntryInfo centeredComment = new EntryInfo(null, "midnightcontrols");
centeredComment.comment = new Comment() {
public Class<? extends Annotation> annotationType() {return null;}
public String category() {return "";}
public String name() {return "";}
public String url() {return "";}
public String requiredMod() {return "";}
@Override
public boolean centered() {
return true;
}
};
if (BUTTONS.equals(tabName)) {
InputManager.streamCategories()
.sorted(Comparator.comparingInt(ButtonCategory::getPriority))
.forEach(category -> {
list.addButton(Lists.newArrayList(), Text.literal(category.getTranslatedName()), centeredComment);
category.getBindings().forEach(binding -> {
ControllerBindingButton.add(binding, list, screen);
});
});
}
if (MISC.equals(tabName)) {
TextIconButtonWidget resetButton = TextIconButtonWidget.builder(Text.translatable("controls.reset"), (button -> {
MidnightControlsConfig.keyboardLayout = "en_US:qwerty";
screen.updateList();
}), true).texture(Identifier.of("midnightlib","icon/reset"), 12, 12).dimension(20, 20).build();
resetButton.setPosition(screen.width - 205 + 150 + 25, 0);
ButtonWidget editButton = ButtonWidget.builder(Text.translatable(KeyboardLayoutManager.getById(MidnightControlsConfig.keyboardLayout).getTranslationKey()),
button -> {
MidnightControlsConfig.keyboardLayout = KeyboardLayoutManager.getNext(KeyboardLayoutManager.getById(MidnightControlsConfig.keyboardLayout)).getId();
resetButton.active = !MidnightControlsConfig.keyboardLayout.equals("en_US:qwerty");
button.setMessage(Text.translatable(KeyboardLayoutManager.getById(MidnightControlsConfig.keyboardLayout).getTranslationKey()));
}).dimensions(screen.width - 185, 0, 150, 20).build();
resetButton.active = !MidnightControlsConfig.keyboardLayout.equals("en_US:qwerty");
list.addButton(List.of(editButton, resetButton), Text.translatable("midnightcontrols.menu.virtual_keyboard_layout"), new EntryInfo(null, screen.modid));
}
if (CONTROLLER.equals(tabName)) {
ControllerSelectionButton.add(list, screen, false);
ControllerSelectionButton.add(list, screen, true);
}
}
/**
* Loads the configuration
*/

View File

@@ -15,6 +15,7 @@ import eu.midnightdust.midnightcontrols.client.compat.EmotecraftCompat;
import eu.midnightdust.midnightcontrols.client.compat.LibGuiCompat;
import eu.midnightdust.midnightcontrols.client.compat.MidnightControlsCompat;
import eu.midnightdust.midnightcontrols.client.compat.YACLCompat;
import eu.midnightdust.midnightcontrols.client.gui.config.ControlsInput;
import eu.midnightdust.midnightcontrols.client.mixin.AdvancementsScreenAccessor;
import eu.midnightdust.midnightcontrols.client.mixin.CreativeInventoryScreenAccessor;
import eu.midnightdust.midnightcontrols.client.mixin.KeyboardAccessor;
@@ -39,7 +40,6 @@ import eu.midnightdust.midnightcontrols.client.controller.InputManager;
import eu.midnightdust.midnightcontrols.client.enums.CameraMode;
import eu.midnightdust.midnightcontrols.client.gui.RingScreen;
import eu.midnightdust.midnightcontrols.client.touch.gui.TouchscreenOverlay;
import eu.midnightdust.midnightcontrols.client.gui.widget.ControllerControlsWidget;
import eu.midnightdust.midnightcontrols.client.ring.RingPage;
import eu.midnightdust.midnightcontrols.client.util.HandledScreenAccessor;
import eu.midnightdust.midnightcontrols.client.util.MathUtil;
@@ -98,7 +98,7 @@ public class MidnightInput {
public int inventoryInteractionCooldown = 0;
public int screenCloseCooldown = 0;
private ControllerControlsWidget controlsInput = null;
private ControlsInput controlsInput = null;
public MidnightInput() {}
@@ -156,7 +156,7 @@ public class MidnightInput {
this.fetchJoystickInput(state, true, false);
});
boolean allowInput = this.controlsInput == null || this.controlsInput.focusedBinding == null;
boolean allowInput = this.controlsInput == null || this.controlsInput.getFocusedBinding() == null;
if (allowInput)
InputManager.updateBindings();
@@ -167,11 +167,11 @@ public class MidnightInput {
});
}
if (this.controlsInput != null && InputManager.STATES.int2ObjectEntrySet().parallelStream().map(Map.Entry::getValue).allMatch(ButtonState::isUnpressed)) {
if (MidnightControlsConfig.debug) MidnightControls.log("Starting MidnightInput Button Edit");
if (this.controlsInput.focusedBinding != null && !this.controlsInput.waiting) {
int[] buttons = new int[this.controlsInput.currentButtons.size()];
for (int i = 0; i < this.controlsInput.currentButtons.size(); i++)
buttons[i] = this.controlsInput.currentButtons.get(i);
//if (MidnightControlsConfig.debug) MidnightControls.log("Starting MidnightInput Button Edit");
if (this.controlsInput.getFocusedBinding() != null && !this.controlsInput.isWaiting()) {
int[] buttons = new int[this.controlsInput.getCurrentButtons().size()];
for (int i = 0; i < this.controlsInput.getCurrentButtons().size(); i++)
buttons[i] = this.controlsInput.getCurrentButtons().get(i);
this.controlsInput.finishBindingEdit(buttons);
this.controlsInput = null;
}
@@ -246,11 +246,11 @@ public class MidnightInput {
this.inventoryInteractionCooldown = 5;
}
public void beginControlsInput(ControllerControlsWidget widget) {
public void beginControlsInput(ControlsInput widget) {
this.controlsInput = widget;
if (widget != null) {
this.controlsInput.currentButtons.clear();
this.controlsInput.waiting = true;
this.controlsInput.getCurrentButtons().clear();
this.controlsInput.setWaiting(true);
}
}
@@ -332,16 +332,17 @@ public class MidnightInput {
}
public void handleButton(ButtonStorage storage) {
if (this.controlsInput != null && this.controlsInput.focusedBinding != null) {
if (storage.state == ButtonState.PRESS && !this.controlsInput.currentButtons.contains(storage.button)) {
this.controlsInput.currentButtons.add(storage.button);
if (this.controlsInput != null && this.controlsInput.getFocusedBinding() != null) {
if (storage.state == ButtonState.PRESS && !this.controlsInput.getCurrentButtons().contains(storage.button)) {
this.controlsInput.getCurrentButtons().add(storage.button);
var buttons = new int[this.controlsInput.currentButtons.size()];
for (int i = 0; i < this.controlsInput.currentButtons.size(); i++)
buttons[i] = this.controlsInput.currentButtons.get(i);
this.controlsInput.focusedBinding.setButton(buttons);
var buttons = new int[this.controlsInput.getCurrentButtons().size()];
for (int i = 0; i < this.controlsInput.getCurrentButtons().size(); i++)
buttons[i] = this.controlsInput.getCurrentButtons().get(i);
this.controlsInput.getFocusedBinding().setButton(buttons);
this.controlsInput.update();
this.controlsInput.waiting = false;
this.controlsInput.setWaiting(false);
}
return;
}
@@ -517,17 +518,18 @@ public class MidnightInput {
// @TODO allow rebinding to left stick
int preferredAxis = true ? GLFW_GAMEPAD_AXIS_RIGHT_Y : GLFW_GAMEPAD_AXIS_LEFT_Y;
if (this.controlsInput != null && this.controlsInput.focusedBinding != null) {
if (storage.buttonState != ButtonState.NONE && !this.controlsInput.currentButtons.contains(storage.getButtonId(storage.buttonState == ButtonState.PRESS))) {
if (this.controlsInput != null && this.controlsInput.getFocusedBinding() != null) {
if (storage.buttonState != ButtonState.NONE && !this.controlsInput.getCurrentButtons().contains(storage.getButtonId(storage.buttonState == ButtonState.PRESS))) {
this.controlsInput.currentButtons.add(storage.getButtonId(storage.buttonState == ButtonState.PRESS));
this.controlsInput.getCurrentButtons().add(storage.getButtonId(storage.buttonState == ButtonState.PRESS));
int[] buttons = new int[this.controlsInput.currentButtons.size()];
for (int i = 0; i < this.controlsInput.currentButtons.size(); i++)
buttons[i] = this.controlsInput.currentButtons.get(i);
this.controlsInput.focusedBinding.setButton(buttons);
int[] buttons = new int[this.controlsInput.getCurrentButtons().size()];
for (int i = 0; i < this.controlsInput.getCurrentButtons().size(); i++)
buttons[i] = this.controlsInput.getCurrentButtons().get(i);
this.controlsInput.getFocusedBinding().setButton(buttons);
this.controlsInput.update();
this.controlsInput.waiting = false;
this.controlsInput.setWaiting(false);
}
return true;
} else if (storage.absValue >= storage.deadZone) {
@@ -816,6 +818,6 @@ public class MidnightInput {
((KeyboardAccessor) client.keyboard).midnightcontrols$onKey(client.getWindow().getHandle(), 1, new KeyInput(key, 0, 0));
}
public void pressKeyboardKey(Screen screen, int key) {
screen.keyPressed(new KeyInput(key, 0, 1));
screen.keyPressed(new KeyInput(key, 0, 0));
}
}

View File

@@ -77,7 +77,7 @@ public class ButtonBinding {
public static final ButtonBinding SCREENSHOT = new Builder("screenshot").buttons(GLFW_GAMEPAD_BUTTON_DPAD_UP, GLFW_GAMEPAD_BUTTON_A)
.action(InputHandlers::handleScreenshot).cooldown().register();
public static final ButtonBinding DEBUG_SCREEN = new Builder("debug_screen").buttons(GLFW_GAMEPAD_BUTTON_DPAD_UP, GLFW_GAMEPAD_BUTTON_B)
.action((client,binding,value,action) -> {if (action == ButtonState.PRESS) client.inGameHud.getDebugHud().toggleRenderingChart(); return true;}).cooldown().register();
.action((client,binding,value,action) -> {if (action == ButtonState.PRESS) client.debugHudEntryList.setF3Enabled(!client.debugHudEntryList.isF3Enabled()); return true;}).cooldown().register();
public static final ButtonBinding SLOT_DOWN = new Builder("slot_down").buttons(GLFW_GAMEPAD_BUTTON_DPAD_DOWN)
.action(InputHandlers.handleInventorySlotPad(1)).onlyInInventory().cooldown().register();
public static final ButtonBinding SLOT_LEFT = new Builder("slot_left").buttons(GLFW_GAMEPAD_BUTTON_DPAD_LEFT)
@@ -413,7 +413,7 @@ public class ButtonBinding {
}
static {
MOVEMENT_CATEGORY = InputManager.registerDefaultCategory("key.categories.movement", category -> category.registerAllBindings(
MOVEMENT_CATEGORY = InputManager.registerDefaultCategory("movement", category -> category.registerAllBindings(
ButtonBinding.FORWARD,
ButtonBinding.BACK,
ButtonBinding.LEFT,
@@ -421,12 +421,12 @@ public class ButtonBinding {
ButtonBinding.JUMP,
ButtonBinding.SNEAK,
ButtonBinding.SPRINT));
GAMEPLAY_CATEGORY = InputManager.registerDefaultCategory("key.categories.gameplay", category -> category.registerAllBindings(
GAMEPLAY_CATEGORY = InputManager.registerDefaultCategory("gameplay", category -> category.registerAllBindings(
ButtonBinding.ATTACK,
ButtonBinding.PICK_BLOCK,
ButtonBinding.USE
));
INVENTORY_CATEGORY = InputManager.registerDefaultCategory("key.categories.inventory", category -> category.registerAllBindings(
INVENTORY_CATEGORY = InputManager.registerDefaultCategory("inventory", category -> category.registerAllBindings(
ButtonBinding.EXIT,
ButtonBinding.DROP_ITEM,
ButtonBinding.HOTBAR_LEFT,
@@ -445,9 +445,9 @@ public class ButtonBinding {
ButtonBinding.SLOT_LEFT,
ButtonBinding.SLOT_RIGHT
));
MULTIPLAYER_CATEGORY = InputManager.registerDefaultCategory("key.categories.multiplayer",
MULTIPLAYER_CATEGORY = InputManager.registerDefaultCategory("multiplayer",
category -> category.registerAllBindings(ButtonBinding.CHAT, ButtonBinding.PLAYER_LIST));
MISC_CATEGORY = InputManager.registerDefaultCategory("key.categories.misc", category -> category.registerAllBindings(
MISC_CATEGORY = InputManager.registerDefaultCategory("misc", category -> category.registerAllBindings(
ButtonBinding.SCREENSHOT,
ButtonBinding.TOGGLE_PERSPECTIVE,
ButtonBinding.PAUSE_GAME,

View File

@@ -38,15 +38,6 @@ public class ButtonCategory {
public ButtonCategory(@NotNull Identifier id) {
this(id, 100);
}
@Deprecated
public ButtonCategory(@NotNull org.aperlambda.lambdacommon.Identifier id, int priority) {
this(Identifier.of(id.getNamespace(), id.getName()), priority);
}
@Deprecated
public ButtonCategory(@NotNull org.aperlambda.lambdacommon.Identifier id) {
this(id, 100);
}
public void registerBinding(@NotNull ButtonBinding binding) {
if (this.bindings.contains(binding))
@@ -74,15 +65,12 @@ public class ButtonCategory {
/**
* Gets the translated name of this category.
* <p>
* The translation key should be `modid.identifier_name`.
* The translation key should be `key.category.modid.identifier_name`.
*
* @return the translated name
*/
public @NotNull String getTranslatedName() {
if (this.id.getNamespace().equals("minecraft"))
return I18n.translate(this.id.getPath());
else
return I18n.translate(this.id.getNamespace() + "." + this.id.getPath());
return I18n.translate("key.category.%s.%s".formatted(id.getNamespace(), id.getPath()));
}
/**

View File

@@ -28,7 +28,7 @@ public interface PressAction {
if (action == ButtonState.REPEAT || client.currentScreen != null)
return false;
button.asKeyBinding().ifPresent(binding -> {
if (binding instanceof StickyKeyBinding)
if (binding instanceof StickyKeyBinding && binding != client.options.attackKey) // TODO: Properly fix sticky keys so the attack key doesn't need to be a hardcoded exception
binding.setPressed(button.isPressed());
else
((KeyBindingAccessor) binding).midnightcontrols$handlePressState(button.isPressed());

View File

@@ -163,7 +163,7 @@ public class MidnightControlsSettingsScreen extends SpruceScreen {
.append(Text.literal(GAMEPAD_TOOL_URL).formatted(Formatting.GOLD))
.append("),");
private static int searchNextAvailableController(int newId, boolean allowNone) {
public static int searchNextAvailableController(int newId, boolean allowNone) {
if ((allowNone && newId == -1) || newId == 0) return newId;
Controller candidate = Controller.byId(newId);

View File

@@ -0,0 +1,154 @@
package eu.midnightdust.midnightcontrols.client.gui.config;
import com.google.common.collect.Lists;
import eu.midnightdust.lib.config.EntryInfo;
import eu.midnightdust.lib.config.MidnightConfigListWidget;
import eu.midnightdust.lib.config.MidnightConfigScreen;
import eu.midnightdust.midnightcontrols.client.MidnightControlsClient;
import eu.midnightdust.midnightcontrols.client.MidnightControlsConfig;
import eu.midnightdust.midnightcontrols.client.controller.ButtonBinding;
import eu.midnightdust.midnightcontrols.client.controller.InputManager;
import eu.midnightdust.midnightcontrols.client.gui.MidnightControlsRenderer;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.tooltip.Tooltip;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.gui.widget.ClickableWidget;
import net.minecraft.client.gui.widget.TextIconButtonWidget;
import net.minecraft.client.input.AbstractInput;
import net.minecraft.text.MutableText;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.Nullable;
import org.thinkingstudio.obsidianui.SpruceTexts;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
public class ControllerBindingButton extends ButtonWidget implements ControlsInput {
private static final int[] UNBOUND = new int[]{-1};
static boolean waiting = false;
static List<Integer> currentButtons = new ArrayList<>();
private int iconWidth;
public static void add(ButtonBinding binding, MidnightConfigListWidget list, MidnightConfigScreen screen) {
ControllerBindingButton editButton = new ControllerBindingButton(screen.width - 185 + 22, 0, 128, 20, binding);
TextIconButtonWidget resetButton = TextIconButtonWidget.builder(Text.translatable("controls.reset"), (button -> {
MidnightControlsConfig.setButtonBinding(binding, binding.getDefaultButton());
screen.updateList();
}), true).texture(Identifier.of("midnightlib","icon/reset"), 12, 12).dimension(20, 20).build();
resetButton.setPosition(screen.width - 205 + 150 + 25, 0);
editButton.resetButton = resetButton;
editButton.updateMessage(false);
EntryInfo info = new EntryInfo(null, screen.modid);
TextIconButtonWidget unbindButton = TextIconButtonWidget.builder(Text.translatable("midnightcontrols.narrator.unbound", binding.getText()), (button -> {
MidnightControlsConfig.setButtonBinding(binding, UNBOUND);
screen.updateList();
}), true).texture(Identifier.of("midnightcontrols","icon/unbind"), 12, 12).dimension(20, 20).build();
unbindButton.setPosition(screen.width - 205 + 20, 0);
unbindButton.setTooltip(Tooltip.of(SpruceTexts.GUI_UNBIND));
list.addButton(Lists.newArrayList(editButton, resetButton, unbindButton), Text.translatable(binding.getTranslationKey()), info);
}
private final ButtonBinding binding;
private @Nullable ClickableWidget resetButton;
public ControllerBindingButton(int x, int y, int width, int height, ButtonBinding binding) {
super(x, y, width, height, binding.getText(), (button) -> {},
(textSupplier) -> binding.isNotBound() ? Text.translatable("narrator.controls.unbound", binding.getTranslationKey()) : Text.translatable("narrator.controls.bound", binding.getTranslationKey(), textSupplier.get()));
this.binding = binding;
updateMessage(false);
}
@Override
public void onPress(AbstractInput input) {
MidnightControlsClient.input.beginControlsInput(this);
this.updateMessage(true);
}
public void updateMessage(boolean focused) {
AtomicBoolean hasConflicts = new AtomicBoolean(false);
MutableText conflictingBindings = Text.empty();
if (focused) this.setMessage(Text.literal("> ").append(getTranslatedButtons().copy().formatted(Formatting.WHITE, Formatting.UNDERLINE)).append(" <").formatted(Formatting.YELLOW));
else {
this.setMessage(getTranslatedButtons());
if (!this.binding.isNotBound()) {
InputManager.streamBindings().forEach(keyBinding -> {
if (keyBinding != this.binding && this.binding.equals(keyBinding)) {
if (hasConflicts.get()) conflictingBindings.append(", ");
hasConflicts.set(true);
conflictingBindings.append(Text.translatable(keyBinding.getTranslationKey()));
}
});
}
}
if (this.resetButton != null) this.resetButton.active = !this.binding.isDefault();
if (hasConflicts.get()) {
this.setMessage(Text.literal("[ ").append(this.getMessage().copy().formatted(Formatting.WHITE)).append(" ]").formatted(Formatting.RED));
this.setTooltip(Tooltip.of(Text.translatable("controls.keybinds.duplicateKeybinds", conflictingBindings)));
} else {
this.setTooltip(null);
}
}
private Text getTranslatedButtons() {
return this.binding.isNotBound() ? SpruceTexts.NOT_BOUND.copy() :
(binding.getButton().length > 0 ? ButtonBinding.getLocalizedButtonName(binding.getButton()[0]) : Text.literal("..."));
}
@Override
public void drawMessage(DrawContext context, TextRenderer textRenderer, int color) {
if (this.binding.getButton().length < 2) super.drawMessage(context, textRenderer, color);
}
@Override
protected void renderWidget(DrawContext context, int mouseX, int mouseY, float deltaTicks) {
super.renderWidget(context, mouseX, mouseY, deltaTicks);
int x = this.getX();
if (this.binding.getButton().length > 1) {
x += (this.width / 2 - iconWidth / 2) - 4;
}
var size = MidnightControlsRenderer.drawButton(context, x, this.getY(), this.binding, MinecraftClient.getInstance());
iconWidth = size.length();
}
@Override
public void finishBindingEdit(int... buttons) {
MidnightControlsConfig.setButtonBinding(binding, buttons);
updateMessage(false);
}
@Override
public void update() {
this.updateMessage(true);
}
@Override
public void setWaiting(boolean value) {
waiting = value;
}
@Override
public boolean isWaiting() {
return waiting;
}
@Override
public List<Integer> getCurrentButtons() {
return currentButtons;
}
@Override
public ButtonBinding getFocusedBinding() {
return this.binding;
}
}

View File

@@ -0,0 +1,62 @@
package eu.midnightdust.midnightcontrols.client.gui.config;
import eu.midnightdust.lib.config.EntryInfo;
import eu.midnightdust.lib.config.MidnightConfigListWidget;
import eu.midnightdust.lib.config.MidnightConfigScreen;
import eu.midnightdust.midnightcontrols.client.MidnightControlsConfig;
import eu.midnightdust.midnightcontrols.client.controller.Controller;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.gui.widget.TextIconButtonWidget;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
import net.minecraft.util.Identifier;
import org.lwjgl.glfw.GLFW;
import org.thinkingstudio.obsidianui.SpruceTexts;
import java.util.List;
import static eu.midnightdust.midnightcontrols.client.gui.MidnightControlsSettingsScreen.searchNextAvailableController;
public class ControllerSelectionButton {
public static void add(MidnightConfigListWidget list, MidnightConfigScreen screen, boolean second) {
TextIconButtonWidget resetButton = TextIconButtonWidget.builder(Text.translatable("controls.reset"), (button -> {
if (second) MidnightControlsConfig.secondControllerID = -1;
else MidnightControlsConfig.controllerID = 0;
screen.updateList();
}), true).texture(Identifier.of("midnightlib","icon/reset"), 12, 12).dimension(20, 20).build();
resetButton.setPosition(screen.width - 205 + 150 + 25, 0);
ButtonWidget editButton = ButtonWidget.builder(getControllerName(second),
button -> {
int id = second ? MidnightControlsConfig.getSecondController().map(Controller::id).orElse(-1) : MidnightControlsConfig.getController().id();
id += 1;
if (id > GLFW.GLFW_JOYSTICK_LAST)
id = GLFW.GLFW_JOYSTICK_1;
id = searchNextAvailableController(id, second);
if (second) {
MidnightControlsConfig.setSecondController(Controller.byId(id));
} else {
MidnightControlsConfig.setController(Controller.byId(id));
}
if (MidnightControlsConfig.debug && id != -1) System.out.println(Controller.byId(id).getName() + "'s Controller GUID: " + Controller.byId(id).getGuid());
resetButton.active = second ? MidnightControlsConfig.getSecondController().isPresent() : false;
button.setMessage(getControllerName(second));
}).dimensions(screen.width - 185, 0, 150, 20).build();
resetButton.active = second ? MidnightControlsConfig.getSecondController().isPresent() : false;
list.addButton(List.of(editButton, resetButton), Text.translatable(second ? "midnightcontrols.menu.controller2" : "midnightcontrols.menu.controller"), new EntryInfo(null, screen.modid));
}
private static Text getControllerName(boolean second) {
if (second && MidnightControlsConfig.getSecondController().isEmpty()) return SpruceTexts.OPTIONS_OFF.copyContentOnly().formatted(Formatting.RED);
var controller = second ? MidnightControlsConfig.getSecondController().get() : MidnightControlsConfig.getController();
var controllerName = controller.getName();
if (!controller.isConnected())
return Text.literal(controllerName).formatted(Formatting.RED);
else if (!controller.isGamepad())
return Text.literal(controllerName).formatted(Formatting.GOLD);
else
return Text.literal(controllerName);
}
}

View File

@@ -0,0 +1,18 @@
package eu.midnightdust.midnightcontrols.client.gui.config;
import eu.midnightdust.midnightcontrols.client.controller.ButtonBinding;
import java.util.List;
public interface ControlsInput {
void setWaiting(boolean value);
boolean isWaiting();
List<Integer> getCurrentButtons();
ButtonBinding getFocusedBinding();
void finishBindingEdit(int[] buttons);
default void update() {};
}

View File

@@ -23,6 +23,12 @@ public class WaylandCursorRenderer extends CursorRenderer {
public static final Identifier WAYLAND_CURSOR_POINTING_DARK = id("cursor/dark/mouse_pointing_hand");
public static final Identifier WAYLAND_CURSOR_IBEAM_LIGHT = id("cursor/light/mouse_ibeam");
public static final Identifier WAYLAND_CURSOR_IBEAM_DARK = id("cursor/dark/mouse_ibeam");
public static final Identifier WAYLAND_CURSOR_RESIZE_VERTICAL_LIGHT = id("cursor/light/mouse_resize_vertical");
public static final Identifier WAYLAND_CURSOR_REZIZE_VERTICAL_DARK = id("cursor/dark/mouse_resize_vertical");
public static final Identifier WAYLAND_CURSOR_RESIZE_HORIZONTAL_LIGHT = id("cursor/light/mouse_resize_horizontal");
public static final Identifier WAYLAND_CURSOR_REZIZE_HORIZONTAL_DARK = id("cursor/dark/mouse_resize_horizontal");
public static final Identifier WAYLAND_CURSOR_NOT_ALLOWED_LIGHT = id("cursor/light/mouse_not_allowed");
public static final Identifier WAYLAND_CURSOR_NOT_ALLOWED_DARK = id("cursor/dark/mouse_not_allowed");
public static WaylandCursorRenderer getInstance() {
return INSTANCE;
@@ -45,6 +51,9 @@ public class WaylandCursorRenderer extends CursorRenderer {
Identifier spritePath;
if (CursorRenderer.currentCursorStyle == StandardCursors.POINTING_HAND) spritePath = isDark ? WAYLAND_CURSOR_POINTING_DARK : WAYLAND_CURSOR_POINTING_LIGHT;
else if (CursorRenderer.currentCursorStyle == StandardCursors.IBEAM) spritePath = isDark ? WAYLAND_CURSOR_IBEAM_DARK : WAYLAND_CURSOR_IBEAM_LIGHT;
else if (CursorRenderer.currentCursorStyle == StandardCursors.RESIZE_NS) spritePath = isDark ? WAYLAND_CURSOR_REZIZE_VERTICAL_DARK : WAYLAND_CURSOR_RESIZE_VERTICAL_LIGHT;
else if (CursorRenderer.currentCursorStyle == StandardCursors.RESIZE_EW) spritePath = isDark ? WAYLAND_CURSOR_REZIZE_HORIZONTAL_DARK : WAYLAND_CURSOR_RESIZE_HORIZONTAL_LIGHT;
else if (CursorRenderer.currentCursorStyle == StandardCursors.NOT_ALLOWED) spritePath = isDark ? WAYLAND_CURSOR_NOT_ALLOWED_DARK : WAYLAND_CURSOR_NOT_ALLOWED_LIGHT;
else spritePath = isDark ? WAYLAND_CURSOR_ARROW_DARK : WAYLAND_CURSOR_ARROW_LIGHT;
return client.getAtlasManager().getAtlasTexture(Atlases.GUI).getSprite(spritePath);

View File

@@ -12,6 +12,7 @@ package eu.midnightdust.midnightcontrols.client.gui.widget;
import eu.midnightdust.midnightcontrols.client.MidnightControlsConfig;
import eu.midnightdust.midnightcontrols.client.controller.ButtonBinding;
import eu.midnightdust.midnightcontrols.client.controller.InputManager;
import eu.midnightdust.midnightcontrols.client.gui.config.ControlsInput;
import org.thinkingstudio.obsidianui.Position;
import org.thinkingstudio.obsidianui.SpruceTexts;
import org.thinkingstudio.obsidianui.widget.SpruceButtonWidget;
@@ -29,11 +30,11 @@ import java.util.stream.Collectors;
/**
* Represents the controls screen.
*/
public class ControllerControlsWidget extends SpruceContainerWidget {
public class ControllerControlsWidget extends SpruceContainerWidget implements ControlsInput {
private SpruceButtonWidget resetButton;
public ButtonBinding focusedBinding;
public boolean waiting = false;
public List<Integer> currentButtons = new ArrayList<>();
ButtonBinding focusedBinding = null;
boolean waiting = false;
List<Integer> currentButtons = new ArrayList<>();
public ControllerControlsWidget(Position position, int width, int height) {
super(position, width, height);
@@ -66,4 +67,24 @@ public class ControllerControlsWidget extends SpruceContainerWidget {
MidnightControlsConfig.setButtonBinding(this.focusedBinding, buttons);
this.focusedBinding = null;
}
@Override
public void setWaiting(boolean value) {
this.waiting = value;
}
@Override
public boolean isWaiting() {
return this.waiting;
}
@Override
public List<Integer> getCurrentButtons() {
return currentButtons;
}
@Override
public ButtonBinding getFocusedBinding() {
return focusedBinding;
}
}

View File

@@ -14,7 +14,6 @@ import com.mojang.blaze3d.systems.RenderSystem;
import eu.midnightdust.midnightcontrols.ControlsMode;
import eu.midnightdust.midnightcontrols.client.MidnightControlsClient;
import eu.midnightdust.midnightcontrols.client.MidnightControlsConfig;
import eu.midnightdust.midnightcontrols.client.gui.MidnightControlsRenderer;
import eu.midnightdust.midnightcontrols.client.gui.cursor.VirtualCursorRenderer;
import eu.midnightdust.midnightcontrols.client.gui.cursor.WaylandCursorRenderer;
import eu.midnightdust.midnightcontrols.client.touch.TouchUtils;
@@ -43,10 +42,9 @@ public abstract class GameRendererMixin {
private void midnightcontrols$renderVirtualCursor(RenderTickCounter tickCounter, boolean tick, CallbackInfo ci, @Local DrawContext drawContext) {
VirtualCursorRenderer.getInstance().renderCursor(drawContext, client);
if (MidnightControlsClient.isWayland) WaylandCursorRenderer.getInstance().renderCursor(drawContext, client);
//drawContext.draw();
}
@Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/GameRenderer;renderHand(FZLorg/joml/Matrix4f;)V"), method = "renderWorld")
private void midnigtcontrols$captureMatrices(RenderTickCounter tickCounter, CallbackInfo ci, @Local(ordinal = 1) Matrix4f projectionMatrix, @Local(ordinal = 1) Matrix4f worldSpaceMatrix) {
private void midnigtcontrols$captureMatrices(RenderTickCounter tickCounter, CallbackInfo ci, @Local(ordinal = 0) Matrix4f projectionMatrix, @Local(ordinal = 1) Matrix4f worldSpaceMatrix) {
TouchUtils.lastProjMat.set(projectionMatrix);
TouchUtils.lastModMat.set(RenderSystem.getModelViewMatrix());
TouchUtils.lastWorldSpaceMatrix.set(worldSpaceMatrix);

View File

@@ -56,7 +56,7 @@ public abstract class MinecraftClientMixin {
@Shadow public abstract void setScreen(Screen screen);
@Shadow public int attackCooldown;
@Shadow protected int attackCooldown;
@Shadow protected abstract void handleInputEvents();

View File

@@ -34,7 +34,6 @@ 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,30 +54,21 @@ public abstract class WorldRendererMixin {
@Shadow
private ClientWorld world;
@Shadow
@Final
private BufferBuilderStorage bufferBuilders;
@Inject(method = "renderTargetBlockOutline", at = @At("HEAD"), cancellable = true)
private void dontRenderOutline(VertexConsumerProvider.Immediate immediate, MatrixStack matrices, boolean renderBlockOutline, WorldRenderState renderStates, CallbackInfo ci) {
if (MidnightControlsConfig.controlsMode == ControlsMode.TOUCHSCREEN && MidnightControlsConfig.touchMode == TouchMode.FINGER_POS) {
ci.cancel();
}
}
@Inject(
method = "renderTargetBlockOutline",
at = @At("HEAD")
at = @At("HEAD"),
cancellable = true
)
private void onOutlineRender(VertexConsumerProvider.Immediate immediate, MatrixStack matrices, boolean renderBlockOutline, WorldRenderState renderStates, CallbackInfo ci) {
if (((MidnightControlsConfig.controlsMode == ControlsMode.CONTROLLER && MidnightControlsConfig.touchInControllerMode) || MidnightControlsConfig.controlsMode == ControlsMode.TOUCHSCREEN)
&& MidnightControlsConfig.touchMode == TouchMode.FINGER_POS) {
this.midnightcontrols$renderFingerOutline(matrices, client.gameRenderer.getCamera());
this.midnightcontrols$renderFingerOutline(immediate, matrices, client.gameRenderer.getCamera());
ci.cancel();
}
this.midnightcontrols$renderReacharoundOutline(matrices, client.gameRenderer.getCamera());
this.midnightcontrols$renderReacharoundOutline(immediate, matrices, client.gameRenderer.getCamera());
}
@Unique
private void midnightcontrols$renderFingerOutline(MatrixStack matrices, Camera camera) {
private void midnightcontrols$renderFingerOutline(VertexConsumerProvider.Immediate immediate, MatrixStack matrices, Camera camera) {
if (TouchInput.firstHitResult == null || TouchInput.firstHitResult.getType() != HitResult.Type.BLOCK)
return;
BlockHitResult result = (BlockHitResult) TouchInput.firstHitResult;
@@ -89,14 +79,14 @@ public abstract class WorldRendererMixin {
if (MidnightControlsConfig.touchOutlineColorHex.isEmpty()) rgb = RainbowColor.radialRainbow(1,1);
var pos = camera.getPos();
matrices.push();
var vertexConsumer = this.bufferBuilders.getEntityVertexConsumers().getBuffer(RenderLayer.getLines());
var vertexConsumer = immediate.getBuffer(RenderLayer.getLines());
VertexRendering.drawOutline(matrices, vertexConsumer, outlineShape, blockPos.getX() - pos.getX(), blockPos.getY() - pos.getY(), blockPos.getZ() - pos.getZ(),
ColorHelper.withAlpha(MidnightControlsConfig.touchOutlineColorAlpha, rgb.getRGB()));
matrices.pop();
}
}
@Unique
private void midnightcontrols$renderReacharoundOutline(MatrixStack matrices, Camera camera) {
private void midnightcontrols$renderReacharoundOutline(VertexConsumerProvider.Immediate immediate, MatrixStack matrices, Camera camera) {
if (this.client.crosshairTarget == null || this.client.crosshairTarget.getType() != HitResult.Type.MISS || !MidnightControlsConfig.shouldRenderReacharoundOutline)
return;
var result = reacharound.getLastReacharoundResult();
@@ -121,7 +111,7 @@ public abstract class WorldRendererMixin {
Color rgb = MidnightColorUtil.hex2Rgb(MidnightControlsConfig.reacharoundOutlineColorHex);
if (MidnightControlsConfig.reacharoundOutlineColorHex.isEmpty()) rgb = RainbowColor.radialRainbow(1,1);
matrices.push();
var vertexConsumer = this.bufferBuilders.getEntityVertexConsumers().getBuffer(RenderLayer.getLines());
var vertexConsumer = immediate.getBuffer(RenderLayer.getLines());
VertexRendering.drawOutline(matrices, vertexConsumer, outlineShape, blockPos.getX() - pos.getX(), blockPos.getY() - pos.getY(), blockPos.getZ() - pos.getZ(),
ColorHelper.withAlpha(MidnightControlsConfig.touchOutlineColorAlpha, rgb.getRGB()));
matrices.pop();

Binary file not shown.

After

Width:  |  Height:  |  Size: 335 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 B

View File

@@ -52,7 +52,7 @@
"depends": {
"fabricloader": ">=0.11.3",
"fabric": ">=0.71.0",
"minecraft": ">=1.20.5",
"minecraft": ">=1.21.9",
"obsidianui": ">=0.2.5",
"java": ">=21"
},

View File

@@ -2,15 +2,15 @@
org.gradle.parallel=true
org.gradle.jvmargs=-Xmx2048M
minecraft_version=1.21.9-rc1
minecraft_version=1.21.9
supported_versions=
yarn_mappings=1.21.9-rc1+build.2
yarn_mappings=1.21.9+build.1
enabled_platforms=fabric,neoforge
archives_base_name=midnightcontrols
mod_version=1.11.2
mod_version=1.11.3-alpha.2
maven_group=eu.midnightdust
release_type=release
release_type=alpha
modrinth_id = bXX9h73M
curseforge_id = 621768
# Configure the IDs here after creating the projects on the websites