From c0526d5e1e7c48a29e48d3dd380a5389e2d06cc0 Mon Sep 17 00:00:00 2001 From: Aaron <51387595+AzureAaron@users.noreply.github.com> Date: Fri, 6 Dec 2024 18:49:19 -0500 Subject: Sack Item Autocomplete (#1062) * Sack Item Autocomplete * Add amount argument --------- Co-authored-by: Rime <81419447+Emirlol@users.noreply.github.com> --- .../mixins/CommandTreeS2CPacketMixin.java | 23 ++++-- .../skyblocker/skyblock/SackItemAutocomplete.java | 82 ++++++++++++++++++++++ 2 files changed, 98 insertions(+), 7 deletions(-) create mode 100644 src/main/java/de/hysky/skyblocker/skyblock/SackItemAutocomplete.java (limited to 'src/main/java') diff --git a/src/main/java/de/hysky/skyblocker/mixins/CommandTreeS2CPacketMixin.java b/src/main/java/de/hysky/skyblocker/mixins/CommandTreeS2CPacketMixin.java index 289923c8..4d49e5f5 100644 --- a/src/main/java/de/hysky/skyblocker/mixins/CommandTreeS2CPacketMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/CommandTreeS2CPacketMixin.java @@ -3,6 +3,8 @@ package de.hysky.skyblocker.mixins; import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import com.mojang.brigadier.tree.CommandNode; import com.mojang.brigadier.tree.LiteralCommandNode; + +import de.hysky.skyblocker.skyblock.SackItemAutocomplete; import de.hysky.skyblocker.skyblock.WarpAutocomplete; import de.hysky.skyblocker.utils.Utils; import net.minecraft.command.CommandSource; @@ -11,11 +13,18 @@ import org.spongepowered.asm.mixin.injection.At; @Mixin(targets = "net.minecraft.network.packet.s2c.play.CommandTreeS2CPacket$CommandTree") public class CommandTreeS2CPacketMixin { - @ModifyExpressionValue(method = "getNode", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/packet/s2c/play/CommandTreeS2CPacket$CommandTree;getNode(I)Lcom/mojang/brigadier/tree/CommandNode;", ordinal = 1)) - public CommandNode modifyCommandSuggestions(CommandNode original) { - if (Utils.isOnHypixel() && WarpAutocomplete.commandNode != null && original instanceof LiteralCommandNode literalCommandNode && literalCommandNode.getLiteral().equals("warp")) { - return WarpAutocomplete.commandNode; - } - return original; - } + @ModifyExpressionValue(method = "getNode", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/packet/s2c/play/CommandTreeS2CPacket$CommandTree;getNode(I)Lcom/mojang/brigadier/tree/CommandNode;", ordinal = 1)) + public CommandNode modifyCommandSuggestions(CommandNode original) { + if (Utils.isOnHypixel() && original instanceof LiteralCommandNode literalCommandNode) { + return switch (literalCommandNode.getLiteral()) { + case String s when s.equals("warp") && WarpAutocomplete.commandNode != null -> WarpAutocomplete.commandNode; + case String s when s.equals("getfromsacks") && SackItemAutocomplete.longCommandNode != null -> SackItemAutocomplete.longCommandNode; + case String s when s.equals("gfs") && SackItemAutocomplete.shortCommandNode != null -> SackItemAutocomplete.shortCommandNode; + + default -> original; + }; + } + + return original; + } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/SackItemAutocomplete.java b/src/main/java/de/hysky/skyblocker/skyblock/SackItemAutocomplete.java new file mode 100644 index 00000000..8646300c --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/SackItemAutocomplete.java @@ -0,0 +1,82 @@ +package de.hysky.skyblocker.skyblock; + +import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.argument; +import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal; + +import java.io.InputStream; +import java.util.List; +import java.util.Set; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import org.jetbrains.annotations.Nullable; +import org.slf4j.Logger; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.mojang.brigadier.arguments.IntegerArgumentType; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.tree.LiteralCommandNode; +import com.mojang.logging.LogUtils; + +import de.hysky.skyblocker.annotations.Init; +import de.hysky.skyblocker.utils.NEURepoManager; +import de.hysky.skyblocker.utils.Utils; +import io.github.moulberry.repo.data.NEUItem; +import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; +import net.minecraft.command.CommandSource; +import net.minecraft.util.Formatting; + +public class SackItemAutocomplete { + private static final Logger LOGGER = LogUtils.getLogger(); + private static final Pattern BAD_CHARACTERS = Pattern.compile("[α☘☠✎✧❁❂❈❤⸕]"); + + @Nullable + public static LiteralCommandNode longCommandNode; + @Nullable + public static LiteralCommandNode shortCommandNode; + + @Init + public static void init() { + NEURepoManager.runAsyncAfterLoad(SackItemAutocomplete::loadSackItems); + } + + private static void loadSackItems() { + try (InputStream stream = NEURepoManager.NEU_REPO.file("constants/sacks.json").stream()) { + JsonObject sacks = JsonParser.parseString(new String(stream.readAllBytes())).getAsJsonObject().getAsJsonObject("sacks"); + + Set sackItemIds = sacks.entrySet().stream() + .map(entry -> entry.getValue().getAsJsonObject()) + .map(sack -> sack.getAsJsonArray("contents")) + .map(JsonArray::asList) + .flatMap(List::stream) + .map(JsonElement::getAsString) + .collect(Collectors.toUnmodifiableSet()); + Set sackItems = sackItemIds.stream() + .map(neuId -> { + NEUItem stack = NEURepoManager.NEU_REPO.getItems().getItemBySkyblockId(neuId); + + return stack != null ? Formatting.strip(stack.getDisplayName()) : neuId; + }) + .map(name -> BAD_CHARACTERS.matcher(name).replaceAll("").trim()) + .collect(Collectors.toUnmodifiableSet()); + + longCommandNode = createCommandNode("getfromsacks", sackItems); + shortCommandNode = createCommandNode("gfs", sackItems); + } catch (Exception e) { + LOGGER.error("[Skyblocker Sack Item Autocomplete] Failed to load sacks data from the NEU Repo.", e); + } + } + + private static LiteralCommandNode createCommandNode(String command, Set sackItems) { + return literal(command) + .requires(fccs -> Utils.isOnSkyblock()) + .then(argument("item", StringArgumentType.greedyString()) + .suggests((context, builder) -> CommandSource.suggestMatching(sackItems, builder)) + .then(argument("amount", IntegerArgumentType.integer(0))) // Adds a nice text to the suggestion when any number is entered after the item string + ) + .build(); + } +} -- cgit