aboutsummaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/de/hysky/skyblocker/SkyblockerMod.java3
-rw-r--r--src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java4
-rw-r--r--src/main/java/de/hysky/skyblocker/mixin/CommandTreeS2CPacketMixin.java21
-rw-r--r--src/main/java/de/hysky/skyblocker/mixin/DyeableItemMixin.java5
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/Tips.java1
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/WarpAutocomplete.java46
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/CustomArmorAnimatedDyes.java181
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java3
-rw-r--r--src/main/resources/assets/skyblocker/lang/en_us.json9
-rw-r--r--src/main/resources/skyblocker.mixins.json1
10 files changed, 273 insertions, 1 deletions
diff --git a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java
index 75918fa9..485a2103 100644
--- a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java
+++ b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java
@@ -148,6 +148,7 @@ public class SkyblockerMod implements ClientModInitializer {
TeleportOverlay.init();
CustomItemNames.init();
CustomArmorDyeColors.init();
+ CustomArmorAnimatedDyes.init();
CustomArmorTrims.init();
TicTacToe.init();
QuiverWarning.init();
@@ -166,6 +167,8 @@ public class SkyblockerMod implements ClientModInitializer {
containerSolverManager.init();
statusBarTracker.init();
BeaconHighlighter.init();
+ WarpAutocomplete.init();
+
Scheduler.INSTANCE.scheduleCyclic(Utils::update, 20);
Scheduler.INSTANCE.scheduleCyclic(DiscordRPCManager::updateDataAndPresence, 200);
Scheduler.INSTANCE.scheduleCyclic(LividColor::update, 10);
diff --git a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java
index 06ac748a..418cc4d1 100644
--- a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java
+++ b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java
@@ -1,6 +1,7 @@
package de.hysky.skyblocker.config;
import de.hysky.skyblocker.SkyblockerMod;
+import de.hysky.skyblocker.skyblock.item.CustomArmorAnimatedDyes;
import de.hysky.skyblocker.skyblock.item.CustomArmorTrims;
import de.hysky.skyblocker.utils.chat.ChatFilterResult;
import de.hysky.skyblocker.utils.waypoint.Waypoint;
@@ -263,6 +264,9 @@ public class SkyblockerConfig {
@SerialEntry
public Object2ObjectOpenHashMap<String, CustomArmorTrims.ArmorTrimId> customArmorTrims = new Object2ObjectOpenHashMap<>();
+
+ @SerialEntry
+ public Object2ObjectOpenHashMap<String, CustomArmorAnimatedDyes.AnimatedDye> customAnimatedDyes = new Object2ObjectOpenHashMap<>();
}
public static class TabHudConf {
diff --git a/src/main/java/de/hysky/skyblocker/mixin/CommandTreeS2CPacketMixin.java b/src/main/java/de/hysky/skyblocker/mixin/CommandTreeS2CPacketMixin.java
new file mode 100644
index 00000000..1cc1b8de
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/mixin/CommandTreeS2CPacketMixin.java
@@ -0,0 +1,21 @@
+package de.hysky.skyblocker.mixin;
+
+import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
+import com.mojang.brigadier.tree.CommandNode;
+import com.mojang.brigadier.tree.LiteralCommandNode;
+import de.hysky.skyblocker.skyblock.WarpAutocomplete;
+import de.hysky.skyblocker.utils.Utils;
+import net.minecraft.command.CommandSource;
+import org.spongepowered.asm.mixin.Mixin;
+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<? extends CommandSource> modifyCommandSuggestions(CommandNode<CommandSource> original) {
+ if (Utils.isOnHypixel() && WarpAutocomplete.commandNode != null && original instanceof LiteralCommandNode<?> literalCommandNode && literalCommandNode.getLiteral().equals("warp")) {
+ return WarpAutocomplete.commandNode;
+ }
+ return original;
+ }
+}
diff --git a/src/main/java/de/hysky/skyblocker/mixin/DyeableItemMixin.java b/src/main/java/de/hysky/skyblocker/mixin/DyeableItemMixin.java
index e5697085..64f6a452 100644
--- a/src/main/java/de/hysky/skyblocker/mixin/DyeableItemMixin.java
+++ b/src/main/java/de/hysky/skyblocker/mixin/DyeableItemMixin.java
@@ -2,6 +2,7 @@ package de.hysky.skyblocker.mixin;
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
import de.hysky.skyblocker.config.SkyblockerConfigManager;
+import de.hysky.skyblocker.skyblock.item.CustomArmorAnimatedDyes;
import de.hysky.skyblocker.utils.ItemUtils;
import de.hysky.skyblocker.utils.Utils;
import net.minecraft.item.DyeableItem;
@@ -16,6 +17,10 @@ public interface DyeableItemMixin {
if (Utils.isOnSkyblock()) {
String itemUuid = ItemUtils.getItemUuid(stack);
+ if (SkyblockerConfigManager.get().general.customAnimatedDyes.containsKey(itemUuid)) {
+ return CustomArmorAnimatedDyes.animateColorTransition(SkyblockerConfigManager.get().general.customAnimatedDyes.get(itemUuid));
+ }
+
return SkyblockerConfigManager.get().general.customDyeColors.getOrDefault(itemUuid, originalColor);
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/Tips.java b/src/main/java/de/hysky/skyblocker/skyblock/Tips.java
index ad345527..c483555e 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/Tips.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/Tips.java
@@ -27,6 +27,7 @@ public class Tips {
getTipFactory("skyblocker.tips.customItemNames", ClickEvent.Action.SUGGEST_COMMAND, "/skyblocker custom renameItem"),
getTipFactory("skyblocker.tips.customArmorDyeColors", ClickEvent.Action.SUGGEST_COMMAND, "/skyblocker custom dyeColor"),
getTipFactory("skyblocker.tips.customArmorTrims", ClickEvent.Action.SUGGEST_COMMAND, "/skyblocker custom armorTrim"),
+ getTipFactory("skyblocker.tips.customAnimatedDyes", ClickEvent.Action.SUGGEST_COMMAND, "/skyblocker custom animatedDye"),
getTipFactory("skyblocker.tips.fancyTabExtraInfo"),
getTipFactory("skyblocker.tips.helpCommand", ClickEvent.Action.SUGGEST_COMMAND, "/skyblocker help"),
getTipFactory("skyblocker.tips.discordRichPresence", ClickEvent.Action.SUGGEST_COMMAND, "/skyblocker config"),
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/WarpAutocomplete.java b/src/main/java/de/hysky/skyblocker/skyblock/WarpAutocomplete.java
new file mode 100644
index 00000000..8862185f
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/skyblock/WarpAutocomplete.java
@@ -0,0 +1,46 @@
+package de.hysky.skyblocker.skyblock;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.mojang.brigadier.arguments.StringArgumentType;
+import com.mojang.brigadier.tree.LiteralCommandNode;
+import de.hysky.skyblocker.SkyblockerMod;
+import de.hysky.skyblocker.utils.Http;
+import de.hysky.skyblocker.utils.Utils;
+import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
+import net.minecraft.command.CommandSource;
+import org.jetbrains.annotations.Nullable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+
+import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.argument;
+import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal;
+
+/**
+ * the mixin {@link de.hysky.skyblocker.mixin.CommandTreeS2CPacketMixin}
+ */
+public class WarpAutocomplete {
+ private static final Logger LOGGER = LoggerFactory.getLogger(WarpAutocomplete.class);
+ @Nullable
+ public static LiteralCommandNode<FabricClientCommandSource> commandNode;
+
+ public static void init() {
+ CompletableFuture.supplyAsync(() -> {
+ try {
+ JsonArray jsonElements = SkyblockerMod.GSON.fromJson(Http.sendGetRequest("https://hysky.de/api/locations"), JsonArray.class);
+ return jsonElements.asList().stream().map(JsonElement::getAsString).toList();
+ } catch (Exception e) {
+ LOGGER.error("[Skyblocker] Failed to download warps list", e);
+ }
+ return List.<String>of();
+ }).thenAccept(warps -> commandNode = literal("warp")
+ .requires(fabricClientCommandSource -> Utils.isOnSkyblock())
+ .then(argument("destination", StringArgumentType.string())
+ .suggests((context, builder) -> CommandSource.suggestMatching(warps, builder))
+ ).build()
+ );
+ }
+}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/CustomArmorAnimatedDyes.java b/src/main/java/de/hysky/skyblocker/skyblock/item/CustomArmorAnimatedDyes.java
new file mode 100644
index 00000000..b011b2b0
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/CustomArmorAnimatedDyes.java
@@ -0,0 +1,181 @@
+package de.hysky.skyblocker.skyblock.item;
+
+import static com.mojang.brigadier.arguments.StringArgumentType.getString;
+import static com.mojang.brigadier.arguments.StringArgumentType.word;
+import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.argument;
+import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal;
+
+import com.mojang.brigadier.Command;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.arguments.BoolArgumentType;
+import com.mojang.brigadier.arguments.IntegerArgumentType;
+
+import de.hysky.skyblocker.SkyblockerMod;
+import de.hysky.skyblocker.config.SkyblockerConfigManager;
+import de.hysky.skyblocker.utils.Constants;
+import de.hysky.skyblocker.utils.ItemUtils;
+import de.hysky.skyblocker.utils.Utils;
+import dev.isxander.yacl3.config.v2.api.SerialEntry;
+import it.unimi.dsi.fastutil.objects.Object2ObjectFunction;
+import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
+import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
+import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
+import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
+import net.minecraft.command.CommandRegistryAccess;
+import net.minecraft.item.DyeableItem;
+import net.minecraft.item.ItemStack;
+import net.minecraft.text.Text;
+import net.minecraft.util.math.MathHelper;
+
+public class CustomArmorAnimatedDyes {
+ private static final Object2ObjectOpenHashMap<AnimatedDye, AnimatedDyeStateTracker> STATE_TRACKER_MAP = new Object2ObjectOpenHashMap<>();
+ private static final Object2ObjectFunction<AnimatedDye, AnimatedDyeStateTracker> NEW_STATE_TRACKER = _dye -> AnimatedDyeStateTracker.create();
+ private static final int DEFAULT_TICK_DELAY = 4;
+ private static int ticks;
+
+ public static void init() {
+ ClientCommandRegistrationCallback.EVENT.register(CustomArmorAnimatedDyes::registerCommands);
+ ClientTickEvents.END_CLIENT_TICK.register(_client -> ++ticks);
+ }
+
+ private static void registerCommands(CommandDispatcher<FabricClientCommandSource> dispatcher, CommandRegistryAccess registryAccess) {
+ dispatcher.register(literal(SkyblockerMod.NAMESPACE)
+ .then(literal("custom")
+ .then(literal("animatedDye")
+ .executes(context -> customizeAnimatedDye(context.getSource(), null, null, 0, false, 0))
+ .then(argument("hex1", word())
+ .then(argument("hex2", word())
+ .then(argument("samples", IntegerArgumentType.integer(1))
+ .then(argument("cycleBack", BoolArgumentType.bool())
+ .executes(context -> customizeAnimatedDye(context.getSource(), getString(context, "hex1"), getString(context, "hex2"), IntegerArgumentType.getInteger(context, "samples"), BoolArgumentType.getBool(context, "cycleBack"), DEFAULT_TICK_DELAY))
+ .then(argument("tickDelay", IntegerArgumentType.integer(0, 20))
+ .executes(context ->customizeAnimatedDye(context.getSource(), getString(context, "hex1"), getString(context, "hex2"), IntegerArgumentType.getInteger(context, "samples"), BoolArgumentType.getBool(context, "cycleBack"), IntegerArgumentType.getInteger(context, "tickDelay")))))))))));
+ }
+
+ private static int customizeAnimatedDye(FabricClientCommandSource source, String hex1, String hex2, int samples, boolean cycleBack, int tickDelay) {
+ if (hex1 != null && hex2 != null && (!CustomArmorDyeColors.isHexadecimalColor(hex1) || !CustomArmorDyeColors.isHexadecimalColor(hex2))) {
+ source.sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.customAnimatedDyes.invalidHex")));
+
+ return Command.SINGLE_SUCCESS;
+ }
+
+ ItemStack heldItem = source.getPlayer().getMainHandStack();
+
+ if (Utils.isOnSkyblock() && heldItem != null && !heldItem.isEmpty()) {
+ if (heldItem.getItem() instanceof DyeableItem) {
+ String itemUuid = ItemUtils.getItemUuid(heldItem);
+
+ if (!itemUuid.isEmpty()) {
+ Object2ObjectOpenHashMap<String, AnimatedDye> customAnimatedDyes = SkyblockerConfigManager.get().general.customAnimatedDyes;
+
+ if (hex1 == null && hex2 == null) {
+ if (customAnimatedDyes.containsKey(itemUuid)) {
+ customAnimatedDyes.remove(itemUuid);
+ SkyblockerConfigManager.save();
+ source.sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.customAnimatedDyes.removed")));
+ } else {
+ source.sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.customAnimatedDyes.neverHad")));
+ }
+ } else {
+ AnimatedDye animatedDye = new AnimatedDye(Integer.decode("0x" + hex1.replace("#", "")), Integer.decode("0x" + hex2.replace("#", "")), samples, cycleBack, tickDelay);
+
+ customAnimatedDyes.put(itemUuid, animatedDye);
+ SkyblockerConfigManager.save();
+ source.sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.customAnimatedDyes.added")));
+ }
+ } else {
+ source.sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.customAnimatedDyes.noItemUuid")));
+ }
+ } else {
+ source.sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.customAnimatedDyes.notDyeable")));
+ }
+ } else {
+ source.sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.customAnimatedDyes.unableToSetDye")));
+ }
+
+ return Command.SINGLE_SUCCESS;
+ }
+
+ public static int animateColorTransition(AnimatedDye animatedDye) {
+ AnimatedDyeStateTracker trackedState = STATE_TRACKER_MAP.computeIfAbsent(animatedDye, NEW_STATE_TRACKER);
+
+ if (trackedState.lastRecordedTick + animatedDye.tickDelay() > ticks) {
+ return trackedState.lastColor;
+ }
+
+ trackedState.lastRecordedTick = ticks;
+
+ return animatedDye.interpolate(trackedState);
+ }
+
+ //Credit to https://codepen.io/OliverBalfour/post/programmatically-making-gradients
+ private static int interpolate(int firstColor, int secondColor, double percentage) {
+ int r1 = MathHelper.square((firstColor >> 16) & 0xFF);
+ int g1 = MathHelper.square((firstColor >> 8) & 0xFF);
+ int b1 = MathHelper.square(firstColor & 0xFF);
+
+ int r2 = MathHelper.square((secondColor >> 16) & 0xFF);
+ int g2 = MathHelper.square((secondColor >> 8) & 0xFF);
+ int b2 = MathHelper.square(secondColor & 0xFF);
+
+ double inverse = 1d - percentage;
+
+ int r3 = (int) Math.floor(Math.sqrt(r1 * inverse + r2 * percentage));
+ int g3 = (int) Math.floor(Math.sqrt(g1 * inverse + g2 * percentage));
+ int b3 = (int) Math.floor(Math.sqrt(b1 * inverse + b2 * percentage));
+
+ return (r3 << 16) | (g3 << 8 ) | b3;
+ }
+
+ private static class AnimatedDyeStateTracker {
+ private int sampleCounter;
+ private boolean onBackCycle = false;
+ private int lastColor = 0;
+ private int lastRecordedTick = 0;
+
+ boolean shouldCycleBack(int samples, boolean canCycleBack) {
+ return canCycleBack && sampleCounter == samples;
+ }
+
+ int getAndDecrement() {
+ return sampleCounter--;
+ }
+
+ int getAndIncrement() {
+ return sampleCounter++;
+ }
+
+ static AnimatedDyeStateTracker create() {
+ return new AnimatedDyeStateTracker();
+ }
+ }
+
+ public record AnimatedDye(@SerialEntry int color1, @SerialEntry int color2, @SerialEntry int samples, @SerialEntry boolean cycleBack, @SerialEntry int tickDelay) {
+
+ private int interpolate(AnimatedDyeStateTracker stateTracker) {
+ if (stateTracker.shouldCycleBack(samples, cycleBack)) stateTracker.onBackCycle = true;
+
+ if (stateTracker.onBackCycle) {
+ double percent = (1d / (double) samples) * stateTracker.getAndDecrement();
+
+ //Go back to normal cycle once we've cycled all the way back
+ if (stateTracker.sampleCounter == 0) stateTracker.onBackCycle = false;
+
+ int interpolatedColor = CustomArmorAnimatedDyes.interpolate(color1, color2, percent);
+ stateTracker.lastColor = interpolatedColor;
+
+ return interpolatedColor;
+ }
+
+ //This will only happen if cycleBack is false
+ if (stateTracker.sampleCounter == samples) stateTracker.sampleCounter = 0;
+
+ double percent = (1d / (double) samples) * stateTracker.getAndIncrement();
+ int interpolatedColor = CustomArmorAnimatedDyes.interpolate(color1, color2, percent);
+
+ stateTracker.lastColor = interpolatedColor;
+
+ return interpolatedColor;
+ }
+ }
+}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java
index 637aea22..62c50735 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java
@@ -218,7 +218,8 @@ public class ItemTooltip {
}
if (TooltipInfoType.COLOR.isTooltipEnabledAndHasOrNullWarning(internalID) && stack.getNbt() != null) {
- boolean hasCustomDye = SkyblockerConfigManager.get().general.customDyeColors.containsKey(ItemUtils.getItemUuid(stack));
+ String uuid = ItemUtils.getItemUuid(stack);
+ boolean hasCustomDye = SkyblockerConfigManager.get().general.customDyeColors.containsKey(uuid) || SkyblockerConfigManager.get().general.customAnimatedDyes.containsKey(uuid);
if (!hasCustomDye && stack.getItem() instanceof DyeableItem item && item.hasColor(stack)) {
String colorHex = String.format("%06X", item.getColor(stack));
diff --git a/src/main/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json
index cb3c265b..aee38317 100644
--- a/src/main/resources/assets/skyblocker/lang/en_us.json
+++ b/src/main/resources/assets/skyblocker/lang/en_us.json
@@ -554,6 +554,14 @@
"skyblocker.customArmorTrims.added": "§fSet a custom armor trim for your currently held item!",
"skyblocker.customArmorTrims.noItemUuid": "§cYou must be holding an item that has a uuid in order to set a custom armor trim!",
"skyblocker.customArmorTrims.unableToSetTrim": "§cUnable to set a custom armor trim :( (Are you in skyblock?, are you holding an item?)",
+
+ "skyblocker.customAnimatedDyes.invalidHex": "§cAn invalid HEX color code was supplied!",
+ "skyblocker.customAnimatedDyes.notDyeable": "§cThis item isn't a dyeable armor piece!",
+ "skyblocker.customAnimatedDyes.removed": "Removed this item's custom animated dye.",
+ "skyblocker.customAnimatedDyes.neverHad": "This item doesn't have a custom animated dye set, but why not add one? ;)",
+ "skyblocker.customAnimatedDyes.added": "Set a custom animated dye for your currently held item!",
+ "skyblocker.customAnimatedDyes.noItemUuid": "§cYou must be holding an item that has a uuid in order to set a custom animated dye.",
+ "skyblocker.customAnimatedDyes.unableToSetDye": "§cUnable to set a custom animated dye :( (Are you in skyblock?, are you holding an item?)",
"skyblocker.quiverWarning.50Left": "You only have 50 Arrows left in your Quiver!",
"skyblocker.quiverWarning.10Left": "You only have 10 Arrows left in your Quiver!",
@@ -573,6 +581,7 @@
"skyblocker.tips.customItemNames": "Customize the names of your items with /skyblocker custom renameItem",
"skyblocker.tips.customArmorDyeColors": "Apply a custom dye color to your leather armour with /skyblocker custom dyeColor",
"skyblocker.tips.customArmorTrims": "You can set custom armor trims on your armor using /skyblocker custom armorTrim.",
+ "skyblocker.tips.customAnimatedDyes": "You can apply a custom animated dye to your leather armour with /skyblocker custom animatedDye!",
"skyblocker.tips.fancyTabExtraInfo": "Did you know you can see extra info on our fancy tab menu when holding N or M?",
"skyblocker.tips.helpCommand": "Use command /skyblocker help and you might find some more nifty features!",
"skyblocker.tips.discordRichPresence": "Use Discord Rich Presence to show your friends how loaded you are!",
diff --git a/src/main/resources/skyblocker.mixins.json b/src/main/resources/skyblocker.mixins.json
index 11002372..9f5f8240 100644
--- a/src/main/resources/skyblocker.mixins.json
+++ b/src/main/resources/skyblocker.mixins.json
@@ -9,6 +9,7 @@
"BatEntityMixin",
"ClientPlayerEntityMixin",
"ClientPlayNetworkHandlerMixin",
+ "CommandTreeS2CPacketMixin",
"DataTrackerMixin",
"DrawContextMixin",
"DyeableItemMixin",