aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron <51387595+AzureAaron@users.noreply.github.com>2024-04-09 15:58:13 -0400
committerGitHub <noreply@github.com>2024-04-09 15:58:13 -0400
commitb5775f7f9a8cc9c12cc5fa3ce136cdf37361a567 (patch)
treedfa6e10c1258c29fca833c33b31203467dcd5b6f
parentaf64b5f098d47caa5fabd5c1fb4f8edb9ae714b6 (diff)
parent37365dd77a5f706ae8b5fa60655482e407ef2193 (diff)
downloadSkyblocker-b5775f7f9a8cc9c12cc5fa3ce136cdf37361a567.tar.gz
Skyblocker-b5775f7f9a8cc9c12cc5fa3ce136cdf37361a567.tar.bz2
Skyblocker-b5775f7f9a8cc9c12cc5fa3ce136cdf37361a567.zip
Merge pull request #634 from AzureAaron/animated-dye-colours
Custom Animated Dyes
-rw-r--r--src/main/java/de/hysky/skyblocker/SkyblockerMod.java1
-rw-r--r--src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java4
-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/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
7 files changed, 203 insertions, 1 deletions
diff --git a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java
index 639b340f..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();
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/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/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 84409b9f..c3b8c92e 100644
--- a/src/main/resources/assets/skyblocker/lang/en_us.json
+++ b/src/main/resources/assets/skyblocker/lang/en_us.json
@@ -553,6 +553,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!",
@@ -572,6 +580,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!",