aboutsummaryrefslogtreecommitdiff
path: root/src/main/java
diff options
context:
space:
mode:
authorolim <bobq4582@gmail.com>2024-04-10 22:07:34 +0100
committerolim <bobq4582@gmail.com>2024-04-10 22:07:34 +0100
commitb420949246daaefc0c381bbc3bfeadd5de44d16a (patch)
tree32803dd6a6f82d15ea1680f3a1d2d51d36b3a1c4 /src/main/java
parentf4b7cccafe1c84e3d7c2cd2da5633a4689b3c6e6 (diff)
parentfa978596931a020cca07ac5d19ed39807d0704e4 (diff)
downloadSkyblocker-b420949246daaefc0c381bbc3bfeadd5de44d16a.tar.gz
Skyblocker-b420949246daaefc0c381bbc3bfeadd5de44d16a.tar.bz2
Skyblocker-b420949246daaefc0c381bbc3bfeadd5de44d16a.zip
Merge remote-tracking branch 'upstream/master' into extended-fishing
Diffstat (limited to 'src/main/java')
-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/dwarven/CrystalsLocationsManager.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
9 files changed, 298 insertions, 12 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 01df542e..9ee1dabe 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/dwarven/CrystalsLocationsManager.java b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsLocationsManager.java
index f43574ab..9c37de51 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsLocationsManager.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsLocationsManager.java
@@ -4,11 +4,11 @@ import com.mojang.brigadier.Command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.logging.LogUtils;
-
import de.hysky.skyblocker.SkyblockerMod;
import de.hysky.skyblocker.config.SkyblockerConfigManager;
import de.hysky.skyblocker.utils.Constants;
import de.hysky.skyblocker.utils.Utils;
+import de.hysky.skyblocker.utils.scheduler.MessageScheduler;
import de.hysky.skyblocker.utils.scheduler.Scheduler;
import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
@@ -24,7 +24,9 @@ import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.text.ClickEvent;
import net.minecraft.text.MutableText;
import net.minecraft.text.Text;
+import net.minecraft.util.Formatting;
import net.minecraft.util.math.BlockPos;
+import org.slf4j.Logger;
import java.awt.*;
import java.util.Arrays;
@@ -35,11 +37,10 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
-import org.slf4j.Logger;
-
import static com.mojang.brigadier.arguments.StringArgumentType.getString;
import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.argument;
import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal;
+import static net.minecraft.command.CommandSource.suggestMatching;
public class CrystalsLocationsManager {
private static final Logger LOGGER = LogUtils.getLogger();
@@ -101,26 +102,34 @@ public class CrystalsLocationsManager {
LOGGER.error("[Skyblocker Crystals Locations Manager] Encountered an exception while extracing a location from a chat message!", e);
}
}
- protected static Boolean checkInCrystals(BlockPos pos){
+
+ protected static Boolean checkInCrystals(BlockPos pos) {
//checks if a location is inside crystal hollows bounds
return pos.getX() >= 202 && pos.getX() <= 823
&& pos.getZ() >= 202 && pos.getZ() <= 823
- && pos.getY() >= 31 && pos.getY() <= 188;
+ && pos.getY() >= 31 && pos.getY() <= 188;
}
private static void registerWaypointLocationCommands(CommandDispatcher<FabricClientCommandSource> dispatcher, CommandRegistryAccess registryAccess) {
dispatcher.register(literal(SkyblockerMod.NAMESPACE)
- .then(literal("crystalWaypoints")
- .then(argument("pos", BlockPosArgumentType.blockPos())
- .then(argument("place", StringArgumentType.greedyString())
- .executes(context -> addWaypointFromCommand(context.getSource(), getString(context, "place"), context.getArgument("pos", PosArgument.class)))
+ .then(literal("crystalWaypoints")
+ .then(argument("pos", BlockPosArgumentType.blockPos())
+ .then(argument("place", StringArgumentType.greedyString())
+ .suggests((context, builder) -> suggestMatching(WAYPOINT_LOCATIONS.keySet(), builder))
+ .executes(context -> addWaypointFromCommand(context.getSource(), getString(context, "place"), context.getArgument("pos", PosArgument.class)))
+ )
+ )
+ .then(literal("share")
+ .then(argument("place", StringArgumentType.greedyString())
+ .suggests((context, builder) -> suggestMatching(WAYPOINT_LOCATIONS.keySet(), builder))
+ .executes(context -> shareWaypoint(getString(context, "place")))
+ )
)
)
- )
);
}
- protected static Text getSetLocationMessage(String location,BlockPos blockPos) {
+ protected static Text getSetLocationMessage(String location, BlockPos blockPos) {
MutableText text = Constants.PREFIX.get();
text.append(Text.literal("Added waypoint for "));
Color locationColor = WAYPOINT_LOCATIONS.get(location).color;
@@ -159,6 +168,21 @@ public class CrystalsLocationsManager {
return Command.SINGLE_SUCCESS;
}
+ public static int shareWaypoint(String place) {
+ if (activeWaypoints.containsKey(place)) {
+ BlockPos pos = activeWaypoints.get(place).pos;
+ MessageScheduler.INSTANCE.sendMessageAfterCooldown(Constants.PREFIX.get().getString() + " " + place + ": " + pos.getX() + ", " + pos.getY() + ", " + pos.getZ());
+ } else {
+ //send fail message
+ if (CLIENT.player == null || CLIENT.getNetworkHandler() == null) {
+ return 0;
+ }
+ CLIENT.player.sendMessage(Constants.PREFIX.get().append(Text.translatable("text.autoconfig.skyblocker.option.locations.dwarvenMines.crystalsWaypoints.shareFail").formatted(Formatting.RED)), false);
+ }
+
+ return Command.SINGLE_SUCCESS;
+ }
+
private static void addCustomWaypoint(String waypointName, BlockPos pos) {
CrystalsWaypoint.Category category = WAYPOINT_LOCATIONS.get(waypointName);
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));