From 62df244db7638883f8ba9a32e5f1148c4629b2ee Mon Sep 17 00:00:00 2001 From: Brady Date: Wed, 9 Oct 2019 21:19:58 -0500 Subject: [PATCH] Initial Brigadier overriden tab completion --- .../api/event/events/TabCompleteEvent.java | 30 ++---- .../listener/AbstractGameEventListener.java | 5 +- .../event/listener/IGameEventListener.java | 10 +- .../baritone/launch/mixins/MixinGuiChat.java | 97 +++++++++++++++++++ src/launch/resources/mixins.baritone.json | 1 + .../baritone/command/BaritoneChatControl.java | 6 +- .../java/baritone/event/GameEventHandler.java | 7 +- .../utils/accessor/ITabCompleter.java | 10 -- 8 files changed, 110 insertions(+), 56 deletions(-) create mode 100644 src/launch/java/baritone/launch/mixins/MixinGuiChat.java delete mode 100644 src/main/java/baritone/utils/accessor/ITabCompleter.java diff --git a/src/api/java/baritone/api/event/events/TabCompleteEvent.java b/src/api/java/baritone/api/event/events/TabCompleteEvent.java index fea1da292..2a0ef87ba 100644 --- a/src/api/java/baritone/api/event/events/TabCompleteEvent.java +++ b/src/api/java/baritone/api/event/events/TabCompleteEvent.java @@ -23,31 +23,13 @@ import baritone.api.event.events.type.Overrideable; /** * @author LoganDark */ -public abstract class TabCompleteEvent extends Cancellable { +public final class TabCompleteEvent extends Cancellable { - public final Overrideable prefix; - public final Overrideable completions; + public final String prefix; + public String[] completions; - TabCompleteEvent(String prefix, String[] completions) { - this.prefix = new Overrideable<>(prefix); - this.completions = new Overrideable<>(completions); - } - - public boolean wasModified() { - return prefix.wasModified() || completions.wasModified(); - } - - public static final class Pre extends TabCompleteEvent { - - public Pre(String prefix) { - super(prefix, null); - } - } - - public static final class Post extends TabCompleteEvent { - - public Post(String prefix, String[] completions) { - super(prefix, completions); - } + public TabCompleteEvent(String prefix) { + this.prefix = prefix; + this.completions = null; } } diff --git a/src/api/java/baritone/api/event/listener/AbstractGameEventListener.java b/src/api/java/baritone/api/event/listener/AbstractGameEventListener.java index e7d4dc292..9eac8de46 100644 --- a/src/api/java/baritone/api/event/listener/AbstractGameEventListener.java +++ b/src/api/java/baritone/api/event/listener/AbstractGameEventListener.java @@ -40,10 +40,7 @@ public interface AbstractGameEventListener extends IGameEventListener { default void onSendChatMessage(ChatEvent event) {} @Override - default void onPreTabComplete(TabCompleteEvent.Pre event) {} - - @Override - default void onPostTabComplete(TabCompleteEvent.Post event) {} + default void onPreTabComplete(TabCompleteEvent event) {} @Override default void onChunkEvent(ChunkEvent event) {} diff --git a/src/api/java/baritone/api/event/listener/IGameEventListener.java b/src/api/java/baritone/api/event/listener/IGameEventListener.java index 44db8f62f..c374c8913 100644 --- a/src/api/java/baritone/api/event/listener/IGameEventListener.java +++ b/src/api/java/baritone/api/event/listener/IGameEventListener.java @@ -61,15 +61,7 @@ public interface IGameEventListener { * * @param event The event */ - void onPreTabComplete(TabCompleteEvent.Pre event); - - /** - * Runs whenever the client player tries to tab complete in chat once completions have been recieved from the - * server. This will only be called if the {@link TabCompleteEvent#cancel()} method was not called. - * - * @param event The event - */ - void onPostTabComplete(TabCompleteEvent.Post event); + void onPreTabComplete(TabCompleteEvent event); /** * Runs before and after whenever a chunk is either loaded, unloaded, or populated. diff --git a/src/launch/java/baritone/launch/mixins/MixinGuiChat.java b/src/launch/java/baritone/launch/mixins/MixinGuiChat.java new file mode 100644 index 000000000..570847e9c --- /dev/null +++ b/src/launch/java/baritone/launch/mixins/MixinGuiChat.java @@ -0,0 +1,97 @@ +/* + * This file is part of Baritone. + * + * Baritone is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Baritone is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Baritone. If not, see . + */ + +package baritone.launch.mixins; + +import baritone.api.BaritoneAPI; +import baritone.api.event.events.TabCompleteEvent; +import com.mojang.brigadier.context.StringRange; +import com.mojang.brigadier.suggestion.Suggestion; +import com.mojang.brigadier.suggestion.Suggestions; +import net.minecraft.client.gui.GuiChat; +import net.minecraft.client.gui.GuiTextField; +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; + +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * @author Brady + * @since 10/9/2019 + */ +@Mixin(GuiChat.class) +public class MixinGuiChat { + + @Shadow + protected GuiTextField inputField; + + @Shadow + @Final + protected List commandUsage; + + @Shadow + private CompletableFuture pendingSuggestions; + + @Inject( + method = "updateSuggestion", + at = @At("HEAD"), + cancellable = true + ) + private void preUpdateSuggestion(CallbackInfo ci) { + // Anything that is present in the input text before the cursor position + String prefix = this.inputField.getText().substring(0, Math.min(this.inputField.getText().length(), this.inputField.getCursorPosition())); + + TabCompleteEvent event = new TabCompleteEvent(prefix); + BaritoneAPI.getProvider().getPrimaryBaritone().getGameEventHandler().onPreTabComplete(event); + + if (event.isCancelled()) { + ci.cancel(); + return; + } + + if (event.completions != null) { + ci.cancel(); + + // TODO: Support populating the command usage + this.commandUsage.clear(); + + if (event.completions.length == 0) { + this.pendingSuggestions = Suggestions.empty(); + } else { + int offset = this.inputField.getCursorPosition(); + + List suggestionList = Stream.of(event.completions) + .map(s -> new Suggestion(StringRange.between(offset, offset + s.length()), s)) + .collect(Collectors.toList()); + + Suggestions suggestions = new Suggestions( + StringRange.between(offset, offset + suggestionList.stream().mapToInt(s -> s.getText().length()).max().orElse(0)), + suggestionList); + + this.pendingSuggestions = new CompletableFuture<>(); + this.pendingSuggestions.complete(suggestions); + } + } + } +} diff --git a/src/launch/resources/mixins.baritone.json b/src/launch/resources/mixins.baritone.json index ceaba84de..84a77d22a 100644 --- a/src/launch/resources/mixins.baritone.json +++ b/src/launch/resources/mixins.baritone.json @@ -18,6 +18,7 @@ "MixinEntityLivingBase", "MixinEntityPlayerSP", "MixinGameRenderer", + "MixinGuiChat", "MixinGuiScreen", "MixinItemStack", "MixinMinecraft", diff --git a/src/main/java/baritone/command/BaritoneChatControl.java b/src/main/java/baritone/command/BaritoneChatControl.java index 79b8ee255..d5fba9645 100644 --- a/src/main/java/baritone/command/BaritoneChatControl.java +++ b/src/main/java/baritone/command/BaritoneChatControl.java @@ -146,11 +146,11 @@ public class BaritoneChatControl implements Helper, AbstractGameEventListener { } @Override - public void onPreTabComplete(TabCompleteEvent.Pre event) { + public void onPreTabComplete(TabCompleteEvent event) { if (!settings.prefixControl.value) { return; } - String prefix = event.prefix.get(); + String prefix = event.prefix; String commandPrefix = settings.prefix.value; if (!prefix.startsWith(commandPrefix)) { return; @@ -161,7 +161,7 @@ public class BaritoneChatControl implements Helper, AbstractGameEventListener { if (args.size() == 1) { stream = stream.map(x -> commandPrefix + x); } - event.completions.set(stream.toArray(String[]::new)); + event.completions = stream.toArray(String[]::new); } public Stream tabComplete(String msg) { diff --git a/src/main/java/baritone/event/GameEventHandler.java b/src/main/java/baritone/event/GameEventHandler.java index f03378562..c2da8548e 100644 --- a/src/main/java/baritone/event/GameEventHandler.java +++ b/src/main/java/baritone/event/GameEventHandler.java @@ -70,15 +70,10 @@ public final class GameEventHandler implements IEventBus, Helper { } @Override - public void onPreTabComplete(TabCompleteEvent.Pre event) { + public void onPreTabComplete(TabCompleteEvent event) { listeners.forEach(l -> l.onPreTabComplete(event)); } - @Override - public void onPostTabComplete(TabCompleteEvent.Post event) { - listeners.forEach(l -> l.onPostTabComplete(event)); - } - @Override public final void onChunkEvent(ChunkEvent event) { EventState state = event.getState(); diff --git a/src/main/java/baritone/utils/accessor/ITabCompleter.java b/src/main/java/baritone/utils/accessor/ITabCompleter.java deleted file mode 100644 index e187c3e6c..000000000 --- a/src/main/java/baritone/utils/accessor/ITabCompleter.java +++ /dev/null @@ -1,10 +0,0 @@ -package baritone.utils.accessor; - -public interface ITabCompleter { - - String getPrefix(); - - void setPrefix(String prefix); - - boolean onGuiChatSetCompletions(String[] newCompl); -}