WIP chomens bot command suggestion

This commit is contained in:
Chayapak 2023-07-02 17:21:26 +07:00
parent e55b9e51b4
commit 0af580f804
10 changed files with 171 additions and 20 deletions

View file

@ -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,11 +20,12 @@ 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();
@ -24,6 +33,7 @@ public class ChatHudMixin {
}
}
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<Component> 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) {}
}
}

View file

@ -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<Suggestions> pendingSuggestions ();
@Accessor("pendingSuggestions")
void setPendingSuggestions (CompletableFuture<Suggestions> pendingSuggestions);
}

View file

@ -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);

View file

@ -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 ();
}

View file

@ -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();
}

View file

@ -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 = "";
}

View file

@ -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<Integer, CompletableFuture<CommandSuggestionsS2CPacket>> 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<CommandSuggestionsS2CPacket> future = new CompletableFuture<>();

View file

@ -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++; }
}

View file

@ -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) + "}]"; }
}

View file

@ -6,12 +6,13 @@
"client": [
"ChatHudMixin",
"ChatInputSuggestorMixin",
"ChatInputSuggestorAccessor",
"ChatScreenMixin",
"ChatScreenAccessor",
"ClientConnectionMixin",
"ClientPlayerEntityMixin",
"ClientPlayNetworkHandlerAccessor",
"ClientPlayNetworkHandlerMixin",
"ClientPlayNetworkHandlerInvoker",
"MinecraftClientAccessor",
"LightmapTextureManagerMixin",
"DecoderHandlerMixin",