diff --git a/src/main/java/land/chipmunk/chipmunkmod/mixin/ChatHudMixin.java b/src/main/java/land/chipmunk/chipmunkmod/mixin/ChatHudMixin.java index 831a236..77d8f38 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/mixin/ChatHudMixin.java +++ b/src/main/java/land/chipmunk/chipmunkmod/mixin/ChatHudMixin.java @@ -1,9 +1,17 @@ package land.chipmunk.chipmunkmod.mixin; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import land.chipmunk.chipmunkmod.ChipmunkMod; import land.chipmunk.chipmunkmod.listeners.Listener; import land.chipmunk.chipmunkmod.listeners.ListenerManager; +import land.chipmunk.chipmunkmod.modules.ChatInputGlobals; import land.chipmunk.chipmunkmod.modules.RainbowName; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TextComponent; +import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.hud.MessageIndicator; +import net.minecraft.client.gui.screen.ChatScreen; +import net.minecraft.command.CommandSource; import net.minecraft.network.message.MessageSignatureData; import net.minecraft.text.Text; import net.minecraft.text.TranslatableTextContent; @@ -12,18 +20,20 @@ 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; + @Mixin(net.minecraft.client.gui.hud.ChatHud.class) public class ChatHudMixin { @Inject(at = @At("HEAD"), method = "addMessage(Lnet/minecraft/text/Text;Lnet/minecraft/network/message/MessageSignatureData;ILnet/minecraft/client/gui/hud/MessageIndicator;Z)V", cancellable = true) public void addMessage(Text message, MessageSignatureData signature, int ticks, MessageIndicator indicator, boolean refresh, CallbackInfo ci) { - try { - if (RainbowName.INSTANCE.enabled) { - if (message.getString().contains("Your nickname is now ") || message.getString().contains("Nickname changed.")) { - ci.cancel(); - return; - } + if (RainbowName.INSTANCE.enabled) { + if (message.getString().contains("Your nickname is now ") || message.getString().contains("Nickname changed.")) { + ci.cancel(); + return; } + } + try { if (((TranslatableTextContent) message.getContent()).getKey().equals("advMode.setCommand.success")) { ci.cancel(); return; @@ -33,5 +43,44 @@ public class ChatHudMixin { for (Listener listener : ListenerManager.listeners) { listener.chatMessageReceived(message); } + + try { + final Component component = message.asComponent(); + + final List children = component.children(); + + if (children.size() == 0) return; + + if (!((TextComponent) children.get(0)).content().equals("chomens_bot_command_suggestion")) return; + + ci.cancel(); + + final String[] matches = children.subList(2, children.size()) + .stream() + .map((each) -> ((TextComponent) each).content()) + .toArray(String[]::new); + + if (!(MinecraftClient.getInstance().currentScreen instanceof ChatScreen chatScreen)) return; + + final ChatScreenAccessor chatScreenAccessor = (ChatScreenAccessor) chatScreen; + + final ChatInputSuggestorAccessor chatInputSuggestorAccessor = (ChatInputSuggestorAccessor) chatScreenAccessor.chatInputSuggestor(); + + chatInputSuggestorAccessor.setPendingSuggestions( + CommandSource.suggestMatching( + matches, + new SuggestionsBuilder( + ChatInputGlobals.textUpToCursor, + ChipmunkMod.CONFIG.bots.chomens.prefix.length() + ) + ) + ); + + chatInputSuggestorAccessor.pendingSuggestions().thenRun(() -> { + if (!chatInputSuggestorAccessor.pendingSuggestions().isDone()) return; + + ((ChatScreenAccessor) chatScreen).chatInputSuggestor().show(true); + }); + } catch (ClassCastException | NumberFormatException ignored) {} } } diff --git a/src/main/java/land/chipmunk/chipmunkmod/mixin/ChatInputSuggestorAccessor.java b/src/main/java/land/chipmunk/chipmunkmod/mixin/ChatInputSuggestorAccessor.java new file mode 100644 index 0000000..dd9e9c5 --- /dev/null +++ b/src/main/java/land/chipmunk/chipmunkmod/mixin/ChatInputSuggestorAccessor.java @@ -0,0 +1,17 @@ +package land.chipmunk.chipmunkmod.mixin; + +import com.mojang.brigadier.suggestion.Suggestions; +import net.minecraft.client.gui.screen.ChatInputSuggestor; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.concurrent.CompletableFuture; + +@Mixin(ChatInputSuggestor.class) +public interface ChatInputSuggestorAccessor { + @Accessor("pendingSuggestions") + CompletableFuture pendingSuggestions (); + + @Accessor("pendingSuggestions") + void setPendingSuggestions (CompletableFuture pendingSuggestions); +} diff --git a/src/main/java/land/chipmunk/chipmunkmod/mixin/ChatInputSuggestorMixin.java b/src/main/java/land/chipmunk/chipmunkmod/mixin/ChatInputSuggestorMixin.java index 634c8c6..49ce058 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/mixin/ChatInputSuggestorMixin.java +++ b/src/main/java/land/chipmunk/chipmunkmod/mixin/ChatInputSuggestorMixin.java @@ -3,10 +3,18 @@ package land.chipmunk.chipmunkmod.mixin; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.StringReader; import com.mojang.brigadier.suggestion.Suggestions; +import land.chipmunk.chipmunkmod.ChipmunkMod; import land.chipmunk.chipmunkmod.command.CommandManager; +import land.chipmunk.chipmunkmod.modules.ChatInputGlobals; +import land.chipmunk.chipmunkmod.modules.CommandCore; +import land.chipmunk.chipmunkmod.modules.TransactionManager; +import land.chipmunk.chipmunkmod.util.UUIDUtilities; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.widget.TextFieldWidget; +import net.minecraft.client.network.ClientPlayerEntity; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mutable; @@ -15,6 +23,7 @@ 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; @Mixin(net.minecraft.client.gui.screen.ChatInputSuggestor.class) @@ -38,6 +47,8 @@ public class ChatInputSuggestorMixin { textField = null; } + public int transactionId = 0; + @Inject(at = @At("TAIL"), method = "refresh()V") public void refresh (CallbackInfo ci) { if (slashOptional) return; @@ -47,6 +58,36 @@ public class ChatInputSuggestorMixin { final String text = this.textField.getText(); final int cursor = this.textField.getCursor(); + final ClientPlayerEntity player = MinecraftClient.getInstance().player; + + final String chomeNSPrefix = ChipmunkMod.CONFIG.bots.chomens.prefix; + + if (text.startsWith(chomeNSPrefix) && player != null) { + final String textUpToCursor = text.substring(chomeNSPrefix.length(), Math.max(chomeNSPrefix.length(), cursor)); + + ChatInputGlobals.text = text; + ChatInputGlobals.cursor = cursor; + ChatInputGlobals.textUpToCursor = textUpToCursor; + + final String selfSelector = UUIDUtilities.selector(player.getUuid()); + + TransactionManager.INSTANCE.nextTransactionId(); + + final Component component = Component + .text("chomens_bot_command_suggestion") + .append(Component.text(transactionId)) + .append(Component.text(selfSelector)) + .append(Component.text(textUpToCursor)); + + CommandCore.INSTANCE.run( + "minecraft:tellraw @a[tag=chomens_bot] " + GsonComponentSerializer.gson().serialize(component) + ); + + transactionId++; + + return; + } + if (cursor < commandManager.prefix.length() || !text.startsWith(commandManager.prefix)) return; final StringReader reader = new StringReader(text); diff --git a/src/main/java/land/chipmunk/chipmunkmod/mixin/ChatScreenAccessor.java b/src/main/java/land/chipmunk/chipmunkmod/mixin/ChatScreenAccessor.java new file mode 100644 index 0000000..e2e9ae2 --- /dev/null +++ b/src/main/java/land/chipmunk/chipmunkmod/mixin/ChatScreenAccessor.java @@ -0,0 +1,12 @@ +package land.chipmunk.chipmunkmod.mixin; + +import net.minecraft.client.gui.screen.ChatInputSuggestor; +import net.minecraft.client.gui.screen.ChatScreen; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(ChatScreen.class) +public interface ChatScreenAccessor { + @Accessor("chatInputSuggestor") + ChatInputSuggestor chatInputSuggestor (); +} diff --git a/src/main/java/land/chipmunk/chipmunkmod/mixin/ClientPlayNetworkHandlerInvoker.java b/src/main/java/land/chipmunk/chipmunkmod/mixin/ClientPlayNetworkHandlerInvoker.java deleted file mode 100644 index 9cac251..0000000 --- a/src/main/java/land/chipmunk/chipmunkmod/mixin/ClientPlayNetworkHandlerInvoker.java +++ /dev/null @@ -1,11 +0,0 @@ -package land.chipmunk.chipmunkmod.mixin; - -import net.minecraft.client.network.ClientPlayNetworkHandler; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Invoker; - -@Mixin(ClientPlayNetworkHandler.class) -public interface ClientPlayNetworkHandlerInvoker { - @Invoker("isSecureChatEnforced") - public boolean isSecureChatEnforced(); -} diff --git a/src/main/java/land/chipmunk/chipmunkmod/modules/ChatInputGlobals.java b/src/main/java/land/chipmunk/chipmunkmod/modules/ChatInputGlobals.java new file mode 100644 index 0000000..e30d5dc --- /dev/null +++ b/src/main/java/land/chipmunk/chipmunkmod/modules/ChatInputGlobals.java @@ -0,0 +1,8 @@ +package land.chipmunk.chipmunkmod.modules; + +// bad +public class ChatInputGlobals { + public static String text = ""; + public static int cursor; + public static String textUpToCursor = ""; +} diff --git a/src/main/java/land/chipmunk/chipmunkmod/modules/TabComplete.java b/src/main/java/land/chipmunk/chipmunkmod/modules/TabComplete.java index de799d6..c493e8d 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/modules/TabComplete.java +++ b/src/main/java/land/chipmunk/chipmunkmod/modules/TabComplete.java @@ -16,7 +16,6 @@ import java.util.concurrent.CompletableFuture; public class TabComplete extends Listener { private final MinecraftClient client; - private int nextTransactionId = 0; private final Map> transactions = new HashMap<>(); public static TabComplete INSTANCE = new TabComplete(MinecraftClient.getInstance()); @@ -37,7 +36,7 @@ public class TabComplete extends Listener { if (connection == null) return null; - final int transactionId = nextTransactionId++; + final int transactionId = TransactionManager.INSTANCE.nextTransactionId(); connection.send(new RequestCommandCompletionsC2SPacket(transactionId, command)); final CompletableFuture future = new CompletableFuture<>(); diff --git a/src/main/java/land/chipmunk/chipmunkmod/modules/TransactionManager.java b/src/main/java/land/chipmunk/chipmunkmod/modules/TransactionManager.java new file mode 100644 index 0000000..03f7bd0 --- /dev/null +++ b/src/main/java/land/chipmunk/chipmunkmod/modules/TransactionManager.java @@ -0,0 +1,11 @@ +package land.chipmunk.chipmunkmod.modules; + +public class TransactionManager { + public static final TransactionManager INSTANCE = new TransactionManager(); + + private int transactionId = 0; + + public int transactionId () { return transactionId; } + + public int nextTransactionId () { return transactionId++; } +} diff --git a/src/main/java/land/chipmunk/chipmunkmod/util/UUIDUtilities.java b/src/main/java/land/chipmunk/chipmunkmod/util/UUIDUtilities.java new file mode 100644 index 0000000..277c709 --- /dev/null +++ b/src/main/java/land/chipmunk/chipmunkmod/util/UUIDUtilities.java @@ -0,0 +1,24 @@ +package land.chipmunk.chipmunkmod.util; + +import java.nio.ByteBuffer; +import java.util.UUID; + +public class UUIDUtilities { + public static int[] intArray (UUID uuid) { + final ByteBuffer buffer = ByteBuffer.wrap(new byte[16]); + buffer.putLong(0, uuid.getMostSignificantBits()); + buffer.putLong(8, uuid.getLeastSignificantBits()); + + final int[] intArray = new int[4]; + for (int i = 0; i < intArray.length; i++) intArray[i] = buffer.getInt(); + + return intArray; + } + + public static String snbt (UUID uuid) { + int[] array = intArray(uuid); + return "[I;" + array[0] + "," + array[1] + "," + array[2] + "," + array[3] + "]"; // TODO: improve lol + } + + public static String selector (UUID uuid) { return "@a[limit=1,nbt={UUID:" + snbt(uuid) + "}]"; } +} diff --git a/src/main/resources/chipmunkmod.mixins.json b/src/main/resources/chipmunkmod.mixins.json index 16cfcb5..d73c2c6 100644 --- a/src/main/resources/chipmunkmod.mixins.json +++ b/src/main/resources/chipmunkmod.mixins.json @@ -6,12 +6,13 @@ "client": [ "ChatHudMixin", "ChatInputSuggestorMixin", + "ChatInputSuggestorAccessor", "ChatScreenMixin", + "ChatScreenAccessor", "ClientConnectionMixin", "ClientPlayerEntityMixin", "ClientPlayNetworkHandlerAccessor", "ClientPlayNetworkHandlerMixin", - "ClientPlayNetworkHandlerInvoker", "MinecraftClientAccessor", "LightmapTextureManagerMixin", "DecoderHandlerMixin",