From 1f7870c62d1e00abcd8c882a47ef6781e0a420d6 Mon Sep 17 00:00:00 2001 From: Beomjun Kim Date: Tue, 19 Mar 2024 09:46:09 +0900 Subject: [PATCH 1/4] Use mixin for command suggestor --- .../client/ChatInputSuggestorFields.java | 28 ++++++++++++++++++ .../mixin/client/SuggestionWindowFields.java | 21 ++++++++++++++ .../calcite/screen/CalciteCommandScreen.java | 29 +++++++++++++++---- .../calcite/screen/CalciteInputSuggestor.java | 2 +- .../widget/CalciteTextFieldWidget.java | 19 ++++++------ .../resources/calcite.client.mixins.json | 9 ++++-- 6 files changed, 90 insertions(+), 18 deletions(-) create mode 100644 src/client/java/works/nuty/calcite/mixin/client/ChatInputSuggestorFields.java create mode 100644 src/client/java/works/nuty/calcite/mixin/client/SuggestionWindowFields.java diff --git a/src/client/java/works/nuty/calcite/mixin/client/ChatInputSuggestorFields.java b/src/client/java/works/nuty/calcite/mixin/client/ChatInputSuggestorFields.java new file mode 100644 index 0000000..5dfd8a7 --- /dev/null +++ b/src/client/java/works/nuty/calcite/mixin/client/ChatInputSuggestorFields.java @@ -0,0 +1,28 @@ +package works.nuty.calcite.mixin.client; + +import com.mojang.brigadier.ParseResults; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.gui.screen.ChatInputSuggestor; +import net.minecraft.command.CommandSource; +import net.minecraft.text.OrderedText; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.List; + +@Environment(EnvType.CLIENT) +@Mixin(ChatInputSuggestor.class) +public interface ChatInputSuggestorFields { + @Accessor + ChatInputSuggestor.SuggestionWindow getWindow(); + + @Accessor + int getMaxSuggestionSize(); + + @Accessor + ParseResults getParse(); + + @Accessor + List getMessages(); +} diff --git a/src/client/java/works/nuty/calcite/mixin/client/SuggestionWindowFields.java b/src/client/java/works/nuty/calcite/mixin/client/SuggestionWindowFields.java new file mode 100644 index 0000000..6a5097d --- /dev/null +++ b/src/client/java/works/nuty/calcite/mixin/client/SuggestionWindowFields.java @@ -0,0 +1,21 @@ +package works.nuty.calcite.mixin.client; + +import com.mojang.brigadier.suggestion.Suggestion; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.gui.screen.ChatInputSuggestor; +import net.minecraft.client.util.math.Rect2i; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.List; + +@Environment(EnvType.CLIENT) +@Mixin(ChatInputSuggestor.SuggestionWindow.class) +public interface SuggestionWindowFields { + @Accessor + Rect2i getArea(); + + @Accessor + List getSuggestions(); +} diff --git a/src/client/java/works/nuty/calcite/screen/CalciteCommandScreen.java b/src/client/java/works/nuty/calcite/screen/CalciteCommandScreen.java index 93f3ea1..93ab0ec 100644 --- a/src/client/java/works/nuty/calcite/screen/CalciteCommandScreen.java +++ b/src/client/java/works/nuty/calcite/screen/CalciteCommandScreen.java @@ -11,6 +11,7 @@ import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.Element; import net.minecraft.client.gui.Selectable; +import net.minecraft.client.gui.screen.ChatInputSuggestor; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.gui.widget.ClickableWidget; @@ -25,6 +26,8 @@ import net.minecraft.world.World; import org.jetbrains.annotations.Nullable; import org.lwjgl.glfw.GLFW; +import works.nuty.calcite.mixin.client.ChatInputSuggestorFields; +import works.nuty.calcite.mixin.client.SuggestionWindowFields; import works.nuty.calcite.widget.AutoActivateButtonWidget; import works.nuty.calcite.widget.CalciteTextFieldWidget; import works.nuty.calcite.widget.ModeButtonWidget; @@ -347,7 +350,7 @@ public void scrollToFocused() { @Environment(EnvType.CLIENT) public class CommandWidget extends AbstractCommandWidget { - protected final CalciteInputSuggestor commandSuggestor; + protected final ChatInputSuggestor commandSuggestor; protected final List children; private final CommandBlockBlockEntity blockEntity; private final CalciteTextFieldWidget commandEdit; @@ -368,10 +371,11 @@ public CommandWidget(CommandBlockBlockEntity blockEntity) { this.commandEdit.setMaxLength(32500); this.commandEdit.setChangedListener(this::onCommandChanged); - this.commandSuggestor = new CalciteInputSuggestor(CalciteCommandScreen.this.client, CalciteCommandScreen.this, this.commandEdit, CalciteCommandScreen.this.textRenderer, true, true, 0, 7, Integer.MIN_VALUE); + this.commandSuggestor = new ChatInputSuggestor(CalciteCommandScreen.this.client, CalciteCommandScreen.this, this.commandEdit, CalciteCommandScreen.this.textRenderer, true, true, 0, 7, false, Integer.MIN_VALUE); this.commandSuggestor.setWindowActive(true); this.commandSuggestor.refresh(); + this.commandEdit.suggestor = this.commandSuggestor; this.commandEdit.setSuggestion(null); this.children = List.of(this.commandEdit); @@ -503,11 +507,14 @@ public void render(DrawContext context, int index, int y, int x, int entryWidth, CalciteCommandScreen.this.commandSuggestorRenderer = () -> { context.getMatrices().push(); context.getMatrices().translate(0, 0, 1); - CalciteInputSuggestor.SuggestionWindow window = this.commandSuggestor.window; + ChatInputSuggestor.SuggestionWindow window = ((ChatInputSuggestorFields) this.commandSuggestor).getWindow(); if (window != null) { - window.area.setY(window.calculateY(y)); + ((SuggestionWindowFields) window).getArea().setY(calculateSuggestionY(y)); + } + if (!this.commandSuggestor.tryRenderWindow(context, mouseX, mouseY)) { + context.getMatrices().translate(0, calculateMessageY(y), 0); + this.commandSuggestor.renderMessages(context); } - this.commandSuggestor.render(context, mouseX, mouseY, y); context.getMatrices().pop(); }; } @@ -531,5 +538,17 @@ protected void syncSettingsToServer() { CommandBlockExecutor commandExecutor = blockEntity.getCommandExecutor(); CalciteCommandScreen.this.client.getNetworkHandler().sendPacket(new UpdateCommandBlockC2SPacket(BlockPos.ofFloored(commandExecutor.getPos()), this.commandEdit.getText(), this.mode, commandExecutor.isTrackingOutput(), this.conditional, this.autoActivate)); } + + private int calculateSuggestionY(int y) { + return height / 2 - 6 < y + ? y - 3 - Math.min(((SuggestionWindowFields) ((ChatInputSuggestorFields) this.commandSuggestor).getWindow()).getSuggestions().size(), ((ChatInputSuggestorFields) this.commandSuggestor).getMaxSuggestionSize()) * 12 + : (y + 24) - (this.commandEdit.drawsBackground() ? 1 : 0); + } + + private int calculateMessageY(int y) { + return (height / 2 - 6 < y + ? y - 3 - ((ChatInputSuggestorFields) this.commandSuggestor).getMessages().size() * 12 + : (y + 24) - (this.commandEdit.drawsBackground() ? 1 : 0)) - 72; + } } } \ No newline at end of file diff --git a/src/client/java/works/nuty/calcite/screen/CalciteInputSuggestor.java b/src/client/java/works/nuty/calcite/screen/CalciteInputSuggestor.java index 93488d2..d1ac4e0 100644 --- a/src/client/java/works/nuty/calcite/screen/CalciteInputSuggestor.java +++ b/src/client/java/works/nuty/calcite/screen/CalciteInputSuggestor.java @@ -78,7 +78,7 @@ public CalciteInputSuggestor(MinecraftClient client, Screen owner, CalciteTextFi this.client = client; this.owner = owner; this.textField = textField; - this.textField.suggestor = this; +// this.textField.suggestor = this; this.textRenderer = textRenderer; this.slashOptional = slashOptional; this.suggestingWhenEmpty = suggestingWhenEmpty; diff --git a/src/client/java/works/nuty/calcite/widget/CalciteTextFieldWidget.java b/src/client/java/works/nuty/calcite/widget/CalciteTextFieldWidget.java index f16f9cc..c3d88e5 100644 --- a/src/client/java/works/nuty/calcite/widget/CalciteTextFieldWidget.java +++ b/src/client/java/works/nuty/calcite/widget/CalciteTextFieldWidget.java @@ -8,12 +8,12 @@ import net.minecraft.client.MinecraftClient; import net.minecraft.client.font.TextRenderer; import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.Drawable; import net.minecraft.client.gui.screen.ButtonTextures; +import net.minecraft.client.gui.screen.ChatInputSuggestor; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder; import net.minecraft.client.gui.screen.narration.NarrationPart; -import net.minecraft.client.gui.widget.ClickableWidget; +import net.minecraft.client.gui.widget.TextFieldWidget; import net.minecraft.client.render.RenderLayer; import net.minecraft.client.sound.SoundManager; import net.minecraft.command.CommandSource; @@ -28,7 +28,7 @@ import org.jetbrains.annotations.Nullable; import works.nuty.calcite.CalciteModClient; import works.nuty.calcite.VerticalNbtTextFormatter; -import works.nuty.calcite.screen.CalciteInputSuggestor; +import works.nuty.calcite.mixin.client.ChatInputSuggestorFields; import java.util.List; import java.util.Objects; @@ -38,8 +38,7 @@ @Environment(value = EnvType.CLIENT) public class CalciteTextFieldWidget - extends ClickableWidget - implements Drawable { + extends TextFieldWidget { public static final int DEFAULT_EDITABLE_COLOR = 0xE0E0E0; private static final ButtonTextures TEXTURES = new ButtonTextures(new Identifier("widget/text_field"), new Identifier("widget/text_field_highlighted")); private static final int VERTICAL_CURSOR_COLOR = -3092272; @@ -58,7 +57,7 @@ public class CalciteTextFieldWidget private int selectionEnd; private int editableColor = 0xE0E0E0; private int uneditableColor = 0x707070; - public CalciteInputSuggestor suggestor; + public ChatInputSuggestor suggestor; @Nullable private String suggestion; @Nullable @@ -75,8 +74,8 @@ public CalciteTextFieldWidget(TextRenderer textRenderer, int x, int y, int width this(textRenderer, x, y, width, height, null, text); } - public CalciteTextFieldWidget(TextRenderer textRenderer, int x, int y, int width, int height, @Nullable net.minecraft.client.gui.widget.TextFieldWidget copyFrom, Text text) { - super(x, y, width, height, text); + public CalciteTextFieldWidget(TextRenderer textRenderer, int x, int y, int width, int height, @Nullable TextFieldWidget copyFrom, Text text) { + super(textRenderer, x, y, width, height, copyFrom, text); this.textRenderer = textRenderer; if (copyFrom != null) { this.setText(copyFrom.getText()); @@ -411,8 +410,8 @@ public void renderWidget(DrawContext context, int mouseX, int mouseY, float delt int displayedSelectionRight = left + this.textRenderer.getWidth(displayedString.substring(0, displayedSelectionEnd)); this.drawSelectionHighlight(context, cursor2, top - 1, displayedSelectionRight - 1, top + 1 + this.textRenderer.fontHeight); } - if (isHovered() && suggestor.parse != null) { - var args = suggestor.parse.getContext().getLastChild().getArguments(); + if (isHovered() && ((ChatInputSuggestorFields) suggestor).getParse() != null) { + var args = ((ChatInputSuggestorFields) suggestor).getParse().getContext().getLastChild().getArguments(); for (String key : args.keySet()) { ParsedArgument arg = args.get(key); diff --git a/src/client/resources/calcite.client.mixins.json b/src/client/resources/calcite.client.mixins.json index e104c9c..95cea30 100644 --- a/src/client/resources/calcite.client.mixins.json +++ b/src/client/resources/calcite.client.mixins.json @@ -3,10 +3,15 @@ "package": "works.nuty.calcite.mixin.client", "compatibilityLevel": "JAVA_17", "client": [ + "ChatInputSuggestorFields", "ClientPlayerEntityMixin", - "DataQueryHandlerMixin" + "DataQueryHandlerMixin", + "SuggestionWindowFields" ], "injectors": { "defaultRequire": 1 - } + }, + "mixins": [ + "SuggestionWindowMixin" + ] } \ No newline at end of file From 2863aad2fa45aae783708e780074edd2eaa7c051 Mon Sep 17 00:00:00 2001 From: Beomjun Kim Date: Tue, 19 Mar 2024 09:47:25 +0900 Subject: [PATCH 2/4] Support ^N and ^P for navigating suggestions --- .../mixin/client/SuggestionWindowMixin.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 src/client/java/works/nuty/calcite/mixin/client/SuggestionWindowMixin.java diff --git a/src/client/java/works/nuty/calcite/mixin/client/SuggestionWindowMixin.java b/src/client/java/works/nuty/calcite/mixin/client/SuggestionWindowMixin.java new file mode 100644 index 0000000..cb9a780 --- /dev/null +++ b/src/client/java/works/nuty/calcite/mixin/client/SuggestionWindowMixin.java @@ -0,0 +1,37 @@ +package works.nuty.calcite.mixin.client; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.gui.screen.ChatInputSuggestor; +import org.lwjgl.glfw.GLFW; +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.CallbackInfoReturnable; + +@Environment(EnvType.CLIENT) +@Mixin(ChatInputSuggestor.SuggestionWindow.class) +public abstract class SuggestionWindowMixin { + @Shadow + boolean completed; + + @Shadow + public abstract void scroll(int offset); + + @Inject(at = @At("HEAD"), method = "keyPressed", cancellable = true) + public void keyPressed(int keyCode, int scanCode, int modifiers, CallbackInfoReturnable cir) { + if ((modifiers & GLFW.GLFW_MOD_CONTROL) > 0 && keyCode == GLFW.GLFW_KEY_N) { + this.scroll(1); + this.completed = false; + cir.setReturnValue(true); + cir.cancel(); + } + if ((modifiers & GLFW.GLFW_MOD_CONTROL) > 0 && keyCode == GLFW.GLFW_KEY_P) { + this.scroll(-1); + this.completed = false; + cir.setReturnValue(true); + cir.cancel(); + } + } +} From a6d0945929b54edcb78afdd75cf9f5b7514a6973 Mon Sep 17 00:00:00 2001 From: Beomjun Kim Date: Tue, 19 Mar 2024 10:03:47 +0900 Subject: [PATCH 3/4] Allow enter key for auto completing --- .../nuty/calcite/mixin/client/SuggestionWindowMixin.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/client/java/works/nuty/calcite/mixin/client/SuggestionWindowMixin.java b/src/client/java/works/nuty/calcite/mixin/client/SuggestionWindowMixin.java index cb9a780..3441b12 100644 --- a/src/client/java/works/nuty/calcite/mixin/client/SuggestionWindowMixin.java +++ b/src/client/java/works/nuty/calcite/mixin/client/SuggestionWindowMixin.java @@ -19,6 +19,9 @@ public abstract class SuggestionWindowMixin { @Shadow public abstract void scroll(int offset); + @Shadow + public abstract void complete(); + @Inject(at = @At("HEAD"), method = "keyPressed", cancellable = true) public void keyPressed(int keyCode, int scanCode, int modifiers, CallbackInfoReturnable cir) { if ((modifiers & GLFW.GLFW_MOD_CONTROL) > 0 && keyCode == GLFW.GLFW_KEY_N) { @@ -33,5 +36,10 @@ public void keyPressed(int keyCode, int scanCode, int modifiers, CallbackInfoRet cir.setReturnValue(true); cir.cancel(); } + if (keyCode == GLFW.GLFW_KEY_ENTER || keyCode == GLFW.GLFW_KEY_KP_ENTER) { + this.complete(); + cir.setReturnValue(true); + cir.cancel(); + } } } From aea7a6a18d460668a95470d0a506c608d512e80a Mon Sep 17 00:00:00 2001 From: Beomjun Kim Date: Tue, 19 Mar 2024 10:09:08 +0900 Subject: [PATCH 4/4] Remove unused file --- .../calcite/screen/CalciteInputSuggestor.java | 527 ------------------ .../resources/calcite.client.mixins.json | 4 +- 2 files changed, 2 insertions(+), 529 deletions(-) delete mode 100644 src/client/java/works/nuty/calcite/screen/CalciteInputSuggestor.java diff --git a/src/client/java/works/nuty/calcite/screen/CalciteInputSuggestor.java b/src/client/java/works/nuty/calcite/screen/CalciteInputSuggestor.java deleted file mode 100644 index d1ac4e0..0000000 --- a/src/client/java/works/nuty/calcite/screen/CalciteInputSuggestor.java +++ /dev/null @@ -1,527 +0,0 @@ -package works.nuty.calcite.screen; - -import com.google.common.base.Strings; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Lists; -import com.mojang.brigadier.CommandDispatcher; -import com.mojang.brigadier.Message; -import com.mojang.brigadier.ParseResults; -import com.mojang.brigadier.StringReader; -import com.mojang.brigadier.context.CommandContextBuilder; -import com.mojang.brigadier.context.ParsedArgument; -import com.mojang.brigadier.context.SuggestionContext; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import com.mojang.brigadier.suggestion.Suggestion; -import com.mojang.brigadier.suggestion.Suggestions; -import com.mojang.brigadier.suggestion.SuggestionsBuilder; -import com.mojang.brigadier.tree.CommandNode; -import com.mojang.brigadier.tree.LiteralCommandNode; -import net.fabricmc.api.EnvType; -import net.fabricmc.api.Environment; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.font.TextRenderer; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.util.math.Rect2i; -import net.minecraft.command.CommandSource; -import net.minecraft.screen.ScreenTexts; -import net.minecraft.server.command.CommandManager; -import net.minecraft.text.OrderedText; -import net.minecraft.text.Style; -import net.minecraft.text.Text; -import net.minecraft.text.Texts; -import net.minecraft.util.Colors; -import net.minecraft.util.Formatting; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.Vec2f; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.jetbrains.annotations.Nullable; -import works.nuty.calcite.widget.CalciteTextFieldWidget; - -import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Stream; - -@Environment(EnvType.CLIENT) -public class CalciteInputSuggestor { - private static final Pattern WHITESPACE_PATTERN = Pattern.compile("(\\s+)"); - private static final Style ERROR_STYLE = Style.EMPTY.withColor(Formatting.RED); - private static final Style INFO_STYLE = Style.EMPTY.withColor(Formatting.GRAY); - private static final List