From 5672ea1f299f7600c7ac88871b9fc99a2db53509 Mon Sep 17 00:00:00 2001 From: violine1101 Date: Sat, 23 Aug 2025 10:47:51 +0200 Subject: [PATCH 01/22] Add reputation bar to redeemed cosmetics --- .../mixins/cosmetics/ReputationBarMixin.java | 81 +++++++++++++++++++ .../options/categories/CosmeticsOptions.java | 15 +++- .../resources/assets/island/lang/en_us.json | 1 + src/main/resources/islandutils.mixins.json | 1 + 4 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 src/main/java/net/asodev/islandutils/mixins/cosmetics/ReputationBarMixin.java diff --git a/src/main/java/net/asodev/islandutils/mixins/cosmetics/ReputationBarMixin.java b/src/main/java/net/asodev/islandutils/mixins/cosmetics/ReputationBarMixin.java new file mode 100644 index 00000000..05ef7e4c --- /dev/null +++ b/src/main/java/net/asodev/islandutils/mixins/cosmetics/ReputationBarMixin.java @@ -0,0 +1,81 @@ +package net.asodev.islandutils.mixins.cosmetics; + +import net.asodev.islandutils.options.IslandOptions; +import net.asodev.islandutils.util.Utils; +import net.minecraft.util.ARGB; +import net.minecraft.util.Mth; +import net.minecraft.world.item.ItemStack; +import org.apache.commons.lang3.math.Fraction; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.Optional; +import java.util.regex.Pattern; + +@Mixin(ItemStack.class) +public class ReputationBarMixin { + @Unique + private static final Pattern REPUTATION_REGEX = Pattern.compile("^Royal Donations: (\\d+)/(\\d+)$"); + + @Unique + private static final int REPUTATION_BAR_COLOR = ARGB.colorFromFloat(1.0F, 0.66F, 0.33F, 1.0F); + + @Unique + private Optional getReputation() { + var itemStack = (ItemStack)(Object)this; + var lore = Utils.getLores(itemStack); + if (lore == null) return Optional.empty(); + + return lore.stream().>map(line -> { + var matcher = REPUTATION_REGEX.matcher(line.getString()); + if (!matcher.find()) return Optional.empty(); + + var level = Integer.parseInt(matcher.group(1)); + var max = Integer.parseInt(matcher.group(2)); + + try { + var fraction = Fraction.getFraction(level, max); + return Optional.of(fraction); + } catch (ArithmeticException e) { + return Optional.empty(); + } + }).filter(Optional::isPresent).map(Optional::get).findFirst(); + } + + @Inject( + method = "isBarVisible", + at = @At("RETURN"), + cancellable = true + ) + private void injectBarVisibility(CallbackInfoReturnable cir) { + if (!IslandOptions.getCosmetics().isShowReputationBar()) return; + this.getReputation().ifPresent(reputation -> cir.setReturnValue(true)); + } + + @Inject( + method = "getBarWidth", + at = @At("RETURN"), + cancellable = true + ) + private void injectBarWidth(CallbackInfoReturnable cir) { + if (!IslandOptions.getCosmetics().isShowReputationBar()) return; + this.getReputation().ifPresent(reputation -> + cir.setReturnValue(Math.min(Mth.mulAndTruncate(reputation, 13), 13)) + ); + } + + @Inject( + method = "getBarColor", + at = @At("RETURN"), + cancellable = true + ) + private void injectBarColor(CallbackInfoReturnable cir) { + if (!IslandOptions.getCosmetics().isShowReputationBar()) return; + if (this.getReputation().isPresent()) { + cir.setReturnValue(REPUTATION_BAR_COLOR); + } + } +} diff --git a/src/main/java/net/asodev/islandutils/options/categories/CosmeticsOptions.java b/src/main/java/net/asodev/islandutils/options/categories/CosmeticsOptions.java index ecff30e9..f85b6331 100644 --- a/src/main/java/net/asodev/islandutils/options/categories/CosmeticsOptions.java +++ b/src/main/java/net/asodev/islandutils/options/categories/CosmeticsOptions.java @@ -13,6 +13,7 @@ public class CosmeticsOptions implements OptionsCategory { boolean showPlayerPreview = true; boolean showOnHover = true; boolean showOnOnlyCosmeticMenus = true; + boolean showReputationBar = true; public boolean isShowPlayerPreview() { return showPlayerPreview; @@ -26,6 +27,10 @@ public boolean isShowOnOnlyCosmeticMenus() { return showOnOnlyCosmeticMenus; } + public boolean isShowReputationBar() { + return showReputationBar; + } + @Override public ConfigCategory getCategory() { Option showPreviewOption = Option.createBuilder() @@ -38,16 +43,22 @@ public ConfigCategory getCategory() { .controller(TickBoxControllerBuilder::create) .binding(defaults.showOnHover, () -> showOnHover, value -> this.showOnHover = value) .build(); - Option showInOnlyCosmeticMenu = Option.createBuilder() + Option showOnlyCosmeticMenusOption = Option.createBuilder() .name(Component.translatable("text.autoconfig.islandutils.option.showOnOnlyCosmeticMenus")) .controller(TickBoxControllerBuilder::create) .binding(defaults.showOnOnlyCosmeticMenus, () -> showOnOnlyCosmeticMenus, value -> this.showOnOnlyCosmeticMenus = value) .build(); + Option showReputationBarOption = Option.createBuilder() + .name(Component.translatable("text.autoconfig.islandutils.option.showReputationBar")) + .controller(TickBoxControllerBuilder::create) + .binding(defaults.showReputationBar, () -> showReputationBar, value -> this.showReputationBar = value) + .build(); return ConfigCategory.createBuilder() .name(Component.translatable("text.autoconfig.islandutils.category.cosmetics")) .option(showPreviewOption) .option(showHoverOption) - .option(showInOnlyCosmeticMenu) + .option(showOnlyCosmeticMenusOption) + .option(showReputationBarOption) .build(); } } diff --git a/src/main/resources/assets/island/lang/en_us.json b/src/main/resources/assets/island/lang/en_us.json index 8d533ad0..4c4d0c55 100644 --- a/src/main/resources/assets/island/lang/en_us.json +++ b/src/main/resources/assets/island/lang/en_us.json @@ -24,6 +24,7 @@ "text.autoconfig.islandutils.option.showPlayerPreview": "Show Cosmetic Previews", "text.autoconfig.islandutils.option.showOnHover": "Preview cosmetics on hover", "text.autoconfig.islandutils.option.showOnOnlyCosmeticMenus": "Show cosmetic preview only in Cosmetic Menus", + "text.autoconfig.islandutils.option.showReputationBar": "Show reputation bar", "text.autoconfig.islandutils.category.discord": "Discord Presence", "text.autoconfig.islandutils.group.presenceDisplayOptions": "Presence Display Options", diff --git a/src/main/resources/islandutils.mixins.json b/src/main/resources/islandutils.mixins.json index f586508d..578c2cbb 100644 --- a/src/main/resources/islandutils.mixins.json +++ b/src/main/resources/islandutils.mixins.json @@ -9,6 +9,7 @@ "accessors.WalkAnimStateAccessor", "cosmetics.ChestScreenMixin", "cosmetics.PreviewTutorialMixin", + "cosmetics.ReputationBarMixin", "discord.ConnectionMixin", "discord.ScoreDisplayMixin", "fontloader.FontLoaderMixin", From b4a85a3d518edbff9a84abf668eb99fd975c13de Mon Sep 17 00:00:00 2001 From: violine1101 Date: Sat, 23 Aug 2025 12:18:48 +0200 Subject: [PATCH 02/22] Add chroma bar to cosmetics --- .../mixins/cosmetics/ItemBarMixin.java | 140 ++++++++++++++++++ .../mixins/cosmetics/ReputationBarMixin.java | 81 ---------- .../modules/cosmetics/CosmeticChroma.java | 40 +++++ .../options/categories/CosmeticsOptions.java | 11 ++ .../resources/assets/island/lang/en_us.json | 1 + src/main/resources/islandutils.mixins.json | 2 +- 6 files changed, 193 insertions(+), 82 deletions(-) create mode 100644 src/main/java/net/asodev/islandutils/mixins/cosmetics/ItemBarMixin.java delete mode 100644 src/main/java/net/asodev/islandutils/mixins/cosmetics/ReputationBarMixin.java create mode 100644 src/main/java/net/asodev/islandutils/modules/cosmetics/CosmeticChroma.java diff --git a/src/main/java/net/asodev/islandutils/mixins/cosmetics/ItemBarMixin.java b/src/main/java/net/asodev/islandutils/mixins/cosmetics/ItemBarMixin.java new file mode 100644 index 00000000..45c3159d --- /dev/null +++ b/src/main/java/net/asodev/islandutils/mixins/cosmetics/ItemBarMixin.java @@ -0,0 +1,140 @@ +package net.asodev.islandutils.mixins.cosmetics; + +import net.asodev.islandutils.modules.cosmetics.CosmeticChroma; +import net.asodev.islandutils.options.IslandOptions; +import net.asodev.islandutils.util.Utils; +import net.minecraft.util.ARGB; +import net.minecraft.util.Mth; +import net.minecraft.world.item.ItemStack; +import org.apache.commons.lang3.math.Fraction; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.List; +import java.util.Optional; +import java.util.regex.Pattern; + +@Mixin(ItemStack.class) +public class ItemBarMixin { + @Unique + private static final Pattern REPUTATION_REGEX = Pattern.compile("^Royal Donations: (\\d+)/(\\d+)$"); + + @Unique + private static final String CHROMA_LABEL = "Chromas Unlocked:"; + + @Unique + private static final Pattern CHROMA_REGEX = Pattern.compile("^([\\uE02A\\uE02E\\uE02F\\uE02C\\uE02D\\uE02B]{5}) - (\\d+)\\uE328$"); + + @Unique + private static final int REPUTATION_BAR_COLOR = ARGB.colorFromFloat(1.0F, 0.66F, 0.33F, 1.0F); + + @Unique + private static final int CHROMA_BAR_COLOR_SPEED = 2000; + + @Unique + private Optional getReputation() { + var itemStack = (ItemStack)(Object)this; + var lore = Utils.getLores(itemStack); + if (lore == null) return Optional.empty(); + + return lore.stream().>map(line -> { + var matcher = REPUTATION_REGEX.matcher(line.getString()); + if (!matcher.find()) return Optional.empty(); + + var level = Integer.parseInt(matcher.group(1)); + var max = Integer.parseInt(matcher.group(2)); + + try { + var fraction = Fraction.getFraction(level, max); + return Optional.of(fraction); + } catch (ArithmeticException e) { + return Optional.empty(); + } + }).filter(Optional::isPresent).map(Optional::get).findFirst(); + } + + @Unique + private Optional> getChromas() { + var itemStack = (ItemStack)(Object)this; + var lore = Utils.getLores(itemStack); + if (lore == null) return Optional.empty(); + + if (lore.stream().noneMatch(it -> it.getString().equals(CHROMA_LABEL))) return Optional.empty(); + + return lore.stream().>>map(line -> { + var matcher = CHROMA_REGEX.matcher(line.getString()); + if (!matcher.find()) return Optional.empty(); + + var chromaChars = matcher.group(1).chars().mapToObj(c -> (char)c); + var chromaList = chromaChars + .map(CosmeticChroma::fromChar) + .filter(Optional::isPresent).map(Optional::get) + .toList(); + return Optional.of(chromaList); + }).filter(Optional::isPresent).map(Optional::get).findFirst(); + } + + @Inject( + method = "isBarVisible", + at = @At("RETURN"), + cancellable = true + ) + private void injectBarVisibility(CallbackInfoReturnable cir) { + if (IslandOptions.getCosmetics().isShowReputationBar()) { + this.getReputation().ifPresent(reputation -> cir.setReturnValue(true)); + } + if (IslandOptions.getCosmetics().isShowChromaBar()) { + this.getChromas().ifPresent(chroma -> cir.setReturnValue(true)); + } + } + + @Inject( + method = "getBarWidth", + at = @At("RETURN"), + cancellable = true + ) + private void injectBarWidth(CallbackInfoReturnable cir) { + if (IslandOptions.getCosmetics().isShowReputationBar()) { + this.getReputation().ifPresent(reputation -> + cir.setReturnValue(Math.min(Mth.mulAndTruncate(reputation, 13), 13)) + ); + } + if (IslandOptions.getCosmetics().isShowChromaBar()) { + this.getChromas().ifPresent(chromas -> + cir.setReturnValue(Math.min(Mth.mulAndTruncate(CosmeticChroma.toFraction(chromas), 13), 13)) + ); + } + } + + @Inject( + method = "getBarColor", + at = @At("RETURN"), + cancellable = true + ) + private void injectBarColor(CallbackInfoReturnable cir) { + if (IslandOptions.getCosmetics().isShowReputationBar()) { + if (this.getReputation().isPresent()) { + cir.setReturnValue(REPUTATION_BAR_COLOR); + } + } + if (IslandOptions.getCosmetics().isShowChromaBar()) { + this.getChromas().ifPresent(chromas -> { + if (chromas.isEmpty()) return; + + var currentChromaIdx = (int) ((System.currentTimeMillis() / CHROMA_BAR_COLOR_SPEED) % chromas.size()); + var nextChromaIdx = (currentChromaIdx + 1) % chromas.size(); + + var currentChromaColor = chromas.get(currentChromaIdx).toColor(); + var nextChromaColor = chromas.get(nextChromaIdx).toColor(); + + var interpolatedProgress = (float) (System.currentTimeMillis() % CHROMA_BAR_COLOR_SPEED) / CHROMA_BAR_COLOR_SPEED; + var interpolatedColor = ARGB.lerp(interpolatedProgress, currentChromaColor, nextChromaColor); + + cir.setReturnValue(interpolatedColor); + }); + } + } +} diff --git a/src/main/java/net/asodev/islandutils/mixins/cosmetics/ReputationBarMixin.java b/src/main/java/net/asodev/islandutils/mixins/cosmetics/ReputationBarMixin.java deleted file mode 100644 index 05ef7e4c..00000000 --- a/src/main/java/net/asodev/islandutils/mixins/cosmetics/ReputationBarMixin.java +++ /dev/null @@ -1,81 +0,0 @@ -package net.asodev.islandutils.mixins.cosmetics; - -import net.asodev.islandutils.options.IslandOptions; -import net.asodev.islandutils.util.Utils; -import net.minecraft.util.ARGB; -import net.minecraft.util.Mth; -import net.minecraft.world.item.ItemStack; -import org.apache.commons.lang3.math.Fraction; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -import java.util.Optional; -import java.util.regex.Pattern; - -@Mixin(ItemStack.class) -public class ReputationBarMixin { - @Unique - private static final Pattern REPUTATION_REGEX = Pattern.compile("^Royal Donations: (\\d+)/(\\d+)$"); - - @Unique - private static final int REPUTATION_BAR_COLOR = ARGB.colorFromFloat(1.0F, 0.66F, 0.33F, 1.0F); - - @Unique - private Optional getReputation() { - var itemStack = (ItemStack)(Object)this; - var lore = Utils.getLores(itemStack); - if (lore == null) return Optional.empty(); - - return lore.stream().>map(line -> { - var matcher = REPUTATION_REGEX.matcher(line.getString()); - if (!matcher.find()) return Optional.empty(); - - var level = Integer.parseInt(matcher.group(1)); - var max = Integer.parseInt(matcher.group(2)); - - try { - var fraction = Fraction.getFraction(level, max); - return Optional.of(fraction); - } catch (ArithmeticException e) { - return Optional.empty(); - } - }).filter(Optional::isPresent).map(Optional::get).findFirst(); - } - - @Inject( - method = "isBarVisible", - at = @At("RETURN"), - cancellable = true - ) - private void injectBarVisibility(CallbackInfoReturnable cir) { - if (!IslandOptions.getCosmetics().isShowReputationBar()) return; - this.getReputation().ifPresent(reputation -> cir.setReturnValue(true)); - } - - @Inject( - method = "getBarWidth", - at = @At("RETURN"), - cancellable = true - ) - private void injectBarWidth(CallbackInfoReturnable cir) { - if (!IslandOptions.getCosmetics().isShowReputationBar()) return; - this.getReputation().ifPresent(reputation -> - cir.setReturnValue(Math.min(Mth.mulAndTruncate(reputation, 13), 13)) - ); - } - - @Inject( - method = "getBarColor", - at = @At("RETURN"), - cancellable = true - ) - private void injectBarColor(CallbackInfoReturnable cir) { - if (!IslandOptions.getCosmetics().isShowReputationBar()) return; - if (this.getReputation().isPresent()) { - cir.setReturnValue(REPUTATION_BAR_COLOR); - } - } -} diff --git a/src/main/java/net/asodev/islandutils/modules/cosmetics/CosmeticChroma.java b/src/main/java/net/asodev/islandutils/modules/cosmetics/CosmeticChroma.java new file mode 100644 index 00000000..39d986a1 --- /dev/null +++ b/src/main/java/net/asodev/islandutils/modules/cosmetics/CosmeticChroma.java @@ -0,0 +1,40 @@ +package net.asodev.islandutils.modules.cosmetics; + +import net.minecraft.util.ARGB; +import org.apache.commons.lang3.math.Fraction; + +import java.util.List; +import java.util.Optional; + +public enum CosmeticChroma { + MECHANICAL, + NATURAL, + OCEANIC, + MAGICAL, + GRAYSCALE; + + public static Optional fromChar(char c) { + return Optional.ofNullable(switch (c) { + case '\uE02E' -> MECHANICAL; + case '\uE02F' -> NATURAL; + case '\uE02C' -> OCEANIC; + case '\uE02D' -> MAGICAL; + case '\uE02B' -> GRAYSCALE; + default -> null; + }); + } + + public int toColor() { + return switch (this) { + case MECHANICAL -> ARGB.colorFromFloat(1.0f, 1.0f, 0.33f, 0.0f); + case NATURAL -> ARGB.colorFromFloat(1.0f, 0.0f, 0.66f, 0.33f); + case OCEANIC -> ARGB.colorFromFloat(1.0f, 0.0f, 0.5f, 1.0f); + case MAGICAL -> ARGB.colorFromFloat(1.0f, 0.5f, 0.0f, 1.0f); + case GRAYSCALE -> ARGB.colorFromFloat(1.0f, 0.5f, 0.5f, 0.5f); + }; + } + + public static Fraction toFraction(List chromas) { + return Fraction.getFraction(chromas.size(), 5); + } +} diff --git a/src/main/java/net/asodev/islandutils/options/categories/CosmeticsOptions.java b/src/main/java/net/asodev/islandutils/options/categories/CosmeticsOptions.java index f85b6331..55fbe956 100644 --- a/src/main/java/net/asodev/islandutils/options/categories/CosmeticsOptions.java +++ b/src/main/java/net/asodev/islandutils/options/categories/CosmeticsOptions.java @@ -14,6 +14,7 @@ public class CosmeticsOptions implements OptionsCategory { boolean showOnHover = true; boolean showOnOnlyCosmeticMenus = true; boolean showReputationBar = true; + boolean showChromaBar = true; public boolean isShowPlayerPreview() { return showPlayerPreview; @@ -31,6 +32,10 @@ public boolean isShowReputationBar() { return showReputationBar; } + public boolean isShowChromaBar() { + return showChromaBar; + } + @Override public ConfigCategory getCategory() { Option showPreviewOption = Option.createBuilder() @@ -53,12 +58,18 @@ public ConfigCategory getCategory() { .controller(TickBoxControllerBuilder::create) .binding(defaults.showReputationBar, () -> showReputationBar, value -> this.showReputationBar = value) .build(); + Option showChromaBarOption = Option.createBuilder() + .name(Component.translatable("text.autoconfig.islandutils.option.showChromaBar")) + .controller(TickBoxControllerBuilder::create) + .binding(defaults.showChromaBar, () -> showChromaBar, value -> this.showChromaBar = value) + .build(); return ConfigCategory.createBuilder() .name(Component.translatable("text.autoconfig.islandutils.category.cosmetics")) .option(showPreviewOption) .option(showHoverOption) .option(showOnlyCosmeticMenusOption) .option(showReputationBarOption) + .option(showChromaBarOption) .build(); } } diff --git a/src/main/resources/assets/island/lang/en_us.json b/src/main/resources/assets/island/lang/en_us.json index 4c4d0c55..9908fbe9 100644 --- a/src/main/resources/assets/island/lang/en_us.json +++ b/src/main/resources/assets/island/lang/en_us.json @@ -25,6 +25,7 @@ "text.autoconfig.islandutils.option.showOnHover": "Preview cosmetics on hover", "text.autoconfig.islandutils.option.showOnOnlyCosmeticMenus": "Show cosmetic preview only in Cosmetic Menus", "text.autoconfig.islandutils.option.showReputationBar": "Show reputation bar", + "text.autoconfig.islandutils.option.showChromaBar": "Show chroma bar", "text.autoconfig.islandutils.category.discord": "Discord Presence", "text.autoconfig.islandutils.group.presenceDisplayOptions": "Presence Display Options", diff --git a/src/main/resources/islandutils.mixins.json b/src/main/resources/islandutils.mixins.json index 578c2cbb..363fb66b 100644 --- a/src/main/resources/islandutils.mixins.json +++ b/src/main/resources/islandutils.mixins.json @@ -9,7 +9,7 @@ "accessors.WalkAnimStateAccessor", "cosmetics.ChestScreenMixin", "cosmetics.PreviewTutorialMixin", - "cosmetics.ReputationBarMixin", + "cosmetics.ItemBarMixin", "discord.ConnectionMixin", "discord.ScoreDisplayMixin", "fontloader.FontLoaderMixin", From afd9beaebb2cb1faecedaf6cee604a48e62a3992 Mon Sep 17 00:00:00 2001 From: violine1101 Date: Sat, 23 Aug 2025 15:06:48 +0200 Subject: [PATCH 03/22] Add general progress bars --- .../mixins/{cosmetics => }/ItemBarMixin.java | 69 +++++++++++++++++-- .../options/categories/MiscOptions.java | 12 +++- .../resources/assets/island/lang/en_us.json | 2 + src/main/resources/islandutils.mixins.json | 2 +- 4 files changed, 76 insertions(+), 9 deletions(-) rename src/main/java/net/asodev/islandutils/mixins/{cosmetics => }/ItemBarMixin.java (63%) diff --git a/src/main/java/net/asodev/islandutils/mixins/cosmetics/ItemBarMixin.java b/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java similarity index 63% rename from src/main/java/net/asodev/islandutils/mixins/cosmetics/ItemBarMixin.java rename to src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java index 45c3159d..734e7090 100644 --- a/src/main/java/net/asodev/islandutils/mixins/cosmetics/ItemBarMixin.java +++ b/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java @@ -1,8 +1,9 @@ -package net.asodev.islandutils.mixins.cosmetics; +package net.asodev.islandutils.mixins; import net.asodev.islandutils.modules.cosmetics.CosmeticChroma; import net.asodev.islandutils.options.IslandOptions; import net.asodev.islandutils.util.Utils; +import net.minecraft.network.chat.Component; import net.minecraft.util.ARGB; import net.minecraft.util.Mth; import net.minecraft.world.item.ItemStack; @@ -19,20 +20,61 @@ @Mixin(ItemStack.class) public class ItemBarMixin { + @Unique + private static final Pattern PROGRESS_REGEX = Pattern.compile("^[\\uE001\\uE269\\uE26C\\uE266]* (\\d+)%$"); + @Unique + private static final String PROGRESS_COSMETIC_LABEL = "Left-Click to Equip"; + @Unique + private static final String PROGRESS_BADGE_PINNED_LABEL = "Shift-Click to Unpin"; + @Unique + private static final String PROGRESS_BADGE_LOCKED_LABEL = "Unlock this slot by reaching the below"; + @Unique + private static final String PROGRESS_QUEST_LABEL = "finish the quest."; + @Unique private static final Pattern REPUTATION_REGEX = Pattern.compile("^Royal Donations: (\\d+)/(\\d+)$"); @Unique private static final String CHROMA_LABEL = "Chromas Unlocked:"; - @Unique private static final Pattern CHROMA_REGEX = Pattern.compile("^([\\uE02A\\uE02E\\uE02F\\uE02C\\uE02D\\uE02B]{5}) - (\\d+)\\uE328$"); + @Unique + private static final int PROGRESS_BAR_COLOR = ARGB.colorFromFloat(1.0F, 0.33F, 1.0F, 0.33F); + @Unique private static final int REPUTATION_BAR_COLOR = ARGB.colorFromFloat(1.0F, 0.66F, 0.33F, 1.0F); @Unique - private static final int CHROMA_BAR_COLOR_SPEED = 2000; + private static final int CHROMA_BAR_COLOR_SPEED_MS = 2000; + + @Unique + private Optional getProgress() { + var itemStack = (ItemStack)(Object)this; + var lore = Utils.getLores(itemStack); + if (lore == null) return Optional.empty(); + + var isCosmetic = lore.stream().anyMatch(line -> line.getString().contains(PROGRESS_COSMETIC_LABEL)); + var isProfileBadge = lore.stream().map(Component::getString).anyMatch( + line -> line.contains(PROGRESS_BADGE_PINNED_LABEL) || line.contains(PROGRESS_BADGE_LOCKED_LABEL) + ); + if (isCosmetic || isProfileBadge) return Optional.empty(); + + var progresses = lore.stream().>map(line -> { + var matcher = PROGRESS_REGEX.matcher(line.getString()); + if (!matcher.find()) return Optional.empty(); + + var percentage = Integer.parseInt(matcher.group(1)); + return Optional.of(Fraction.getFraction(percentage, 100)); + }).filter(Optional::isPresent).map(Optional::get); + + var isQuest = lore.stream().anyMatch(line -> line.getString().contains(PROGRESS_QUEST_LABEL)); + if (isQuest) { + return progresses.max(Fraction::compareTo); + } else { + return progresses.findFirst(); + } + } @Unique private Optional getReputation() { @@ -83,6 +125,9 @@ private Optional> getChromas() { cancellable = true ) private void injectBarVisibility(CallbackInfoReturnable cir) { + if (IslandOptions.getMisc().isShowProgressBar()) { + this.getProgress().ifPresent(progress -> cir.setReturnValue(true)); + } if (IslandOptions.getCosmetics().isShowReputationBar()) { this.getReputation().ifPresent(reputation -> cir.setReturnValue(true)); } @@ -97,14 +142,19 @@ private void injectBarVisibility(CallbackInfoReturnable cir) { cancellable = true ) private void injectBarWidth(CallbackInfoReturnable cir) { + if (IslandOptions.getMisc().isShowProgressBar()) { + this.getProgress().ifPresent(progress -> + cir.setReturnValue(Math.min(Mth.mulAndTruncate(progress, 13), 13)) + ); + } if (IslandOptions.getCosmetics().isShowReputationBar()) { this.getReputation().ifPresent(reputation -> - cir.setReturnValue(Math.min(Mth.mulAndTruncate(reputation, 13), 13)) + cir.setReturnValue(Math.min(Mth.mulAndTruncate(reputation, 13), 13)) ); } if (IslandOptions.getCosmetics().isShowChromaBar()) { this.getChromas().ifPresent(chromas -> - cir.setReturnValue(Math.min(Mth.mulAndTruncate(CosmeticChroma.toFraction(chromas), 13), 13)) + cir.setReturnValue(Math.min(Mth.mulAndTruncate(CosmeticChroma.toFraction(chromas), 13), 13)) ); } } @@ -115,6 +165,11 @@ private void injectBarWidth(CallbackInfoReturnable cir) { cancellable = true ) private void injectBarColor(CallbackInfoReturnable cir) { + if (IslandOptions.getMisc().isShowProgressBar()) { + if (this.getProgress().isPresent()) { + cir.setReturnValue(PROGRESS_BAR_COLOR); + } + } if (IslandOptions.getCosmetics().isShowReputationBar()) { if (this.getReputation().isPresent()) { cir.setReturnValue(REPUTATION_BAR_COLOR); @@ -124,13 +179,13 @@ private void injectBarColor(CallbackInfoReturnable cir) { this.getChromas().ifPresent(chromas -> { if (chromas.isEmpty()) return; - var currentChromaIdx = (int) ((System.currentTimeMillis() / CHROMA_BAR_COLOR_SPEED) % chromas.size()); + var currentChromaIdx = (int) ((System.currentTimeMillis() / CHROMA_BAR_COLOR_SPEED_MS) % chromas.size()); var nextChromaIdx = (currentChromaIdx + 1) % chromas.size(); var currentChromaColor = chromas.get(currentChromaIdx).toColor(); var nextChromaColor = chromas.get(nextChromaIdx).toColor(); - var interpolatedProgress = (float) (System.currentTimeMillis() % CHROMA_BAR_COLOR_SPEED) / CHROMA_BAR_COLOR_SPEED; + var interpolatedProgress = (float) (System.currentTimeMillis() % CHROMA_BAR_COLOR_SPEED_MS) / CHROMA_BAR_COLOR_SPEED_MS; var interpolatedColor = ARGB.lerp(interpolatedProgress, currentChromaColor, nextChromaColor); cir.setReturnValue(interpolatedColor); diff --git a/src/main/java/net/asodev/islandutils/options/categories/MiscOptions.java b/src/main/java/net/asodev/islandutils/options/categories/MiscOptions.java index a8ac72d0..f784a3b5 100644 --- a/src/main/java/net/asodev/islandutils/options/categories/MiscOptions.java +++ b/src/main/java/net/asodev/islandutils/options/categories/MiscOptions.java @@ -19,6 +19,7 @@ public class MiscOptions implements OptionsCategory { boolean silverPreview = true; boolean channelSwitchers = true; boolean showFishingUpgradeIcon = true; + boolean showProgressBar = true; boolean enableConfigButton = true; boolean debugMode = false; @@ -44,6 +45,9 @@ public boolean showChannelSwitchers() { public boolean isShowFishingUpgradeIcon() { return showFishingUpgradeIcon; } + public boolean isShowProgressBar() { + return showProgressBar; + } public boolean isDebugMode() { return debugMode && !Utils.isLunarClient(); @@ -83,7 +87,6 @@ public ConfigCategory getCategory() { .build(); Option fishingUpgradeOption = Option.createBuilder() .name(Component.translatable("text.autoconfig.islandutils.option.showFishingUpgradeIcon")) - .description(OptionDescription.of(Component.translatable("text.autoconfig.islandutils.option.showFishingUpgradeIcon.@Tooltip"))) .controller(TickBoxControllerBuilder::create) .binding(defaults.showFishingUpgradeIcon, () -> showFishingUpgradeIcon, value -> this.showFishingUpgradeIcon = value) .build(); @@ -93,6 +96,12 @@ public ConfigCategory getCategory() { .controller(TickBoxControllerBuilder::create) .binding(defaults.enableConfigButton, () -> enableConfigButton, value -> this.enableConfigButton = value) .build(); + Option progressBarOption = Option.createBuilder() + .name(Component.translatable("text.autoconfig.islandutils.option.showProgressBar")) + .description(OptionDescription.of(Component.translatable("text.autoconfig.islandutils.option.showProgressBar.@Tooltip"))) + .controller(TickBoxControllerBuilder::create) + .binding(defaults.showProgressBar, () -> showProgressBar, value -> this.showProgressBar = value) + .build(); Option debugOption = Option.createBuilder() .name(Component.translatable("text.autoconfig.islandutils.option.debugMode")) .description(OptionDescription.of(Component.translatable("text.autoconfig.islandutils.option.debugMode.@Tooltip"))) @@ -114,6 +123,7 @@ public ConfigCategory getCategory() { .option(channelsOption) .option(fishingUpgradeOption) .option(buttonOption) + .option(progressBarOption) .group(OptionGroup.createBuilder() .name(Component.translatable("text.autoconfig.islandutils.group.debugOptions")) .collapsed(true) diff --git a/src/main/resources/assets/island/lang/en_us.json b/src/main/resources/assets/island/lang/en_us.json index 9908fbe9..7e3f966a 100644 --- a/src/main/resources/assets/island/lang/en_us.json +++ b/src/main/resources/assets/island/lang/en_us.json @@ -83,6 +83,8 @@ "text.autoconfig.islandutils.option.silverPreview.@Tooltip": "Shows all the items you'll earn in the Scavenging menu", "text.autoconfig.islandutils.option.channelSwitchers": "Show chat channel buttons", "text.autoconfig.islandutils.option.channelSwitchers.@Tooltip": "Shows the chat channel switcher buttons above the chat box", + "text.autoconfig.islandutils.option.showProgressBar": "Show progress bars", + "text.autoconfig.islandutils.option.showProgressBar.@Tooltip": "Adds an progress bar to inventories for menu items with progress in their tooltip, such as quests or fishing islands", "text.autoconfig.islandutils.option.hideSliders": "Hide Sound Sliders if not Online", "text.autoconfig.islandutils.option.hideSliders.@Tooltip": "Hides the Music Sliders if you're not on MCC Island", "text.autoconfig.islandutils.option.showFishingUpgradeIcon": "Show fishing upgrade icons", diff --git a/src/main/resources/islandutils.mixins.json b/src/main/resources/islandutils.mixins.json index 363fb66b..5f973c7e 100644 --- a/src/main/resources/islandutils.mixins.json +++ b/src/main/resources/islandutils.mixins.json @@ -9,7 +9,7 @@ "accessors.WalkAnimStateAccessor", "cosmetics.ChestScreenMixin", "cosmetics.PreviewTutorialMixin", - "cosmetics.ItemBarMixin", + "ItemBarMixin", "discord.ConnectionMixin", "discord.ScoreDisplayMixin", "fontloader.FontLoaderMixin", From e72c3c1f43400e08216d5be3a134794a049a0c17 Mon Sep 17 00:00:00 2001 From: violine1101 Date: Sat, 23 Aug 2025 23:23:09 +0200 Subject: [PATCH 04/22] Refactoring and tweaks --- .../islandutils/mixins/ItemBarMixin.java | 220 ++++++++---------- .../modules/cosmetics/CosmeticChroma.java | 4 +- .../net/asodev/islandutils/util/BarInfo.java | 14 ++ 3 files changed, 117 insertions(+), 121 deletions(-) create mode 100644 src/main/java/net/asodev/islandutils/util/BarInfo.java diff --git a/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java b/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java index 734e7090..534ff5b9 100644 --- a/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java +++ b/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java @@ -2,10 +2,10 @@ import net.asodev.islandutils.modules.cosmetics.CosmeticChroma; import net.asodev.islandutils.options.IslandOptions; +import net.asodev.islandutils.util.BarInfo; import net.asodev.islandutils.util.Utils; import net.minecraft.network.chat.Component; import net.minecraft.util.ARGB; -import net.minecraft.util.Mth; import net.minecraft.world.item.ItemStack; import org.apache.commons.lang3.math.Fraction; import org.spongepowered.asm.mixin.Mixin; @@ -14,33 +14,44 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import java.util.List; +import java.util.ArrayList; import java.util.Optional; import java.util.regex.Pattern; +import java.util.stream.Collectors; @Mixin(ItemStack.class) public class ItemBarMixin { @Unique - private static final Pattern PROGRESS_REGEX = Pattern.compile("^[\\uE001\\uE269\\uE26C\\uE266]* (\\d+)%$"); + private static final Pattern PROGRESS_REGEX = Pattern.compile(".*\\n[\\uE001\\uE269\\uE26C\\uE266]* (\\d+)%.*"); @Unique - private static final String PROGRESS_COSMETIC_LABEL = "Left-Click to Equip"; + private static final String PROGRESS_COSMETIC_LABEL = "Left-Click to Equip\n"; + @Unique + private static final String PROGRESS_COSMETIC_LABEL_2 = "Left-Click to Unequip\n"; @Unique private static final String PROGRESS_BADGE_PINNED_LABEL = "Shift-Click to Unpin"; @Unique - private static final String PROGRESS_BADGE_LOCKED_LABEL = "Unlock this slot by reaching the below"; + private static final String PROGRESS_BADGE_LOCKED_LABEL = "\nUnlock this slot by reaching the below\namount of Skill Trophies.\n"; + @Unique + private static final String PROGRESS_QUEST_LABEL = "\nComplete any of the below tasks to\nfinish the quest.\n"; + @Unique + private static final String PROGRESS_TOOL_USES_LABEL = "\nUses Remaining: "; @Unique - private static final String PROGRESS_QUEST_LABEL = "finish the quest."; + private static final String PROGRESS_TOOL_REPAIRABLE_LABEL = "\nThis item is out of uses! You can Repair\nit to restore all its uses, you can only\ndo this once per item.\n"; + @Unique + private static final String PROGRESS_TOOL_BROKEN_LABEL = "\nThis item is out of uses! You've already\nrepaired it once, so cannot do so\nagain."; @Unique - private static final Pattern REPUTATION_REGEX = Pattern.compile("^Royal Donations: (\\d+)/(\\d+)$"); + private static final Pattern REPUTATION_REGEX = Pattern.compile(".*\\nRoyal Donations: (\\d+)/(\\d+)\\n.*"); @Unique - private static final String CHROMA_LABEL = "Chromas Unlocked:"; + private static final String CHROMA_LABEL = "\nChromas Unlocked:\n"; @Unique - private static final Pattern CHROMA_REGEX = Pattern.compile("^([\\uE02A\\uE02E\\uE02F\\uE02C\\uE02D\\uE02B]{5}) - (\\d+)\\uE328$"); + private static final Pattern CHROMA_REGEX = Pattern.compile(".*\\n([\\uE02A\\uE02E\\uE02F\\uE02C\\uE02D\\uE02B]{5}) - (\\d+)\\uE328\\n.*"); @Unique private static final int PROGRESS_BAR_COLOR = ARGB.colorFromFloat(1.0F, 0.33F, 1.0F, 0.33F); + @Unique + private static final int REPAIRABLE_BAR_COLOR = ARGB.colorFromFloat(1.0F, 1.0F, 0.33F, 0.33F); @Unique private static final int REPUTATION_BAR_COLOR = ARGB.colorFromFloat(1.0F, 0.66F, 0.33F, 1.0F); @@ -49,147 +60,116 @@ public class ItemBarMixin { private static final int CHROMA_BAR_COLOR_SPEED_MS = 2000; @Unique - private Optional getProgress() { - var itemStack = (ItemStack)(Object)this; - var lore = Utils.getLores(itemStack); - if (lore == null) return Optional.empty(); + private Optional getProgressBar(String lore) { + if (!IslandOptions.getMisc().isShowProgressBar()) return Optional.empty(); - var isCosmetic = lore.stream().anyMatch(line -> line.getString().contains(PROGRESS_COSMETIC_LABEL)); - var isProfileBadge = lore.stream().map(Component::getString).anyMatch( - line -> line.contains(PROGRESS_BADGE_PINNED_LABEL) || line.contains(PROGRESS_BADGE_LOCKED_LABEL) - ); + var isCosmetic = lore.contains(PROGRESS_COSMETIC_LABEL) || lore.contains(PROGRESS_COSMETIC_LABEL_2); + var isProfileBadge = lore.contains(PROGRESS_BADGE_PINNED_LABEL) || lore.contains(PROGRESS_BADGE_LOCKED_LABEL); if (isCosmetic || isProfileBadge) return Optional.empty(); - var progresses = lore.stream().>map(line -> { - var matcher = PROGRESS_REGEX.matcher(line.getString()); - if (!matcher.find()) return Optional.empty(); + var isBrokenTool = lore.contains(PROGRESS_TOOL_BROKEN_LABEL); + if (isBrokenTool) return Optional.of(new BarInfo(Fraction.ZERO, PROGRESS_BAR_COLOR)); + + var isRepairableTool = lore.contains(PROGRESS_TOOL_REPAIRABLE_LABEL); + if (isRepairableTool) return Optional.of(new BarInfo(Fraction.getFraction(1, 100), REPAIRABLE_BAR_COLOR)); + var matcher = PROGRESS_REGEX.matcher(lore); + var progresses = new ArrayList(); + while (matcher.find()) { var percentage = Integer.parseInt(matcher.group(1)); - return Optional.of(Fraction.getFraction(percentage, 100)); - }).filter(Optional::isPresent).map(Optional::get); - - var isQuest = lore.stream().anyMatch(line -> line.getString().contains(PROGRESS_QUEST_LABEL)); - if (isQuest) { - return progresses.max(Fraction::compareTo); - } else { - return progresses.findFirst(); + var fraction = Fraction.getFraction(percentage, 100); + progresses.add(fraction); } + if (progresses.isEmpty()) return Optional.empty(); + + var isQuest = lore.contains(PROGRESS_QUEST_LABEL); + var fraction = isQuest ? progresses.stream().max(Fraction::compareTo) : progresses.stream().findFirst(); + + var isNonBrokenTool = lore.contains(PROGRESS_TOOL_USES_LABEL); + + return fraction.map(f -> new BarInfo(f, PROGRESS_BAR_COLOR)); } @Unique - private Optional getReputation() { - var itemStack = (ItemStack)(Object)this; - var lore = Utils.getLores(itemStack); - if (lore == null) return Optional.empty(); + private Optional getReputationBar(String lore) { + if (!IslandOptions.getCosmetics().isShowReputationBar()) return Optional.empty(); - return lore.stream().>map(line -> { - var matcher = REPUTATION_REGEX.matcher(line.getString()); - if (!matcher.find()) return Optional.empty(); + var matcher = REPUTATION_REGEX.matcher(lore); + if (!matcher.find()) return Optional.empty(); + + var level = Integer.parseInt(matcher.group(1)); + var max = Integer.parseInt(matcher.group(2)); + + try { + var fraction = Fraction.getFraction(level, max); + return Optional.of(new BarInfo(fraction, REPUTATION_BAR_COLOR)); + } catch (ArithmeticException e) { + return Optional.empty(); + } + } - var level = Integer.parseInt(matcher.group(1)); - var max = Integer.parseInt(matcher.group(2)); + @Unique + private Optional getChromaBar(String lore) { + if (!IslandOptions.getCosmetics().isShowChromaBar()) return Optional.empty(); + + if (!lore.contains(CHROMA_LABEL)) return Optional.empty(); + + var matcher = CHROMA_REGEX.matcher(lore); + if (!matcher.find()) return Optional.empty(); + var chromaChars = Optional.of(matcher.group(1).chars().mapToObj(c -> (char) c).toList()); + + return chromaChars.map(charList -> + charList.stream() + .map(CosmeticChroma::fromChar) + .filter(Optional::isPresent) + .map(Optional::get) + .toList() + ).map(chromas -> { + var fraction = CosmeticChroma.toFraction(chromas); + + var color = 0; + if (!chromas.isEmpty()) { + var currentChromaIdx = (int) ((System.currentTimeMillis() / CHROMA_BAR_COLOR_SPEED_MS) % chromas.size()); + var nextChromaIdx = (currentChromaIdx + 1) % chromas.size(); - try { - var fraction = Fraction.getFraction(level, max); - return Optional.of(fraction); - } catch (ArithmeticException e) { - return Optional.empty(); + var currentChromaColor = chromas.get(currentChromaIdx).toColor(); + var nextChromaColor = chromas.get(nextChromaIdx).toColor(); + + var interpolatedProgress = (float) (System.currentTimeMillis() % CHROMA_BAR_COLOR_SPEED_MS) / CHROMA_BAR_COLOR_SPEED_MS; + color = ARGB.lerp(interpolatedProgress, currentChromaColor, nextChromaColor); } - }).filter(Optional::isPresent).map(Optional::get).findFirst(); + + return new BarInfo(fraction, color); + }); } @Unique - private Optional> getChromas() { + private Optional getItemBar() { var itemStack = (ItemStack)(Object)this; var lore = Utils.getLores(itemStack); if (lore == null) return Optional.empty(); - if (lore.stream().noneMatch(it -> it.getString().equals(CHROMA_LABEL))) return Optional.empty(); + var loreStr = lore.stream().map(Component::getString).collect(Collectors.joining("\n")); - return lore.stream().>>map(line -> { - var matcher = CHROMA_REGEX.matcher(line.getString()); - if (!matcher.find()) return Optional.empty(); - - var chromaChars = matcher.group(1).chars().mapToObj(c -> (char)c); - var chromaList = chromaChars - .map(CosmeticChroma::fromChar) - .filter(Optional::isPresent).map(Optional::get) - .toList(); - return Optional.of(chromaList); - }).filter(Optional::isPresent).map(Optional::get).findFirst(); + return this.getChromaBar(loreStr) + .or(() -> this.getReputationBar(loreStr)) + .or(() -> this.getProgressBar(loreStr)); } - @Inject( - method = "isBarVisible", - at = @At("RETURN"), - cancellable = true - ) + @Inject(method = "isBarVisible", at = @At("RETURN"), cancellable = true) private void injectBarVisibility(CallbackInfoReturnable cir) { - if (IslandOptions.getMisc().isShowProgressBar()) { - this.getProgress().ifPresent(progress -> cir.setReturnValue(true)); - } - if (IslandOptions.getCosmetics().isShowReputationBar()) { - this.getReputation().ifPresent(reputation -> cir.setReturnValue(true)); - } - if (IslandOptions.getCosmetics().isShowChromaBar()) { - this.getChromas().ifPresent(chroma -> cir.setReturnValue(true)); + if (this.getItemBar().isPresent()) { + cir.setReturnValue(true); } } - @Inject( - method = "getBarWidth", - at = @At("RETURN"), - cancellable = true - ) + @Inject(method = "getBarWidth", at = @At("RETURN"), cancellable = true) private void injectBarWidth(CallbackInfoReturnable cir) { - if (IslandOptions.getMisc().isShowProgressBar()) { - this.getProgress().ifPresent(progress -> - cir.setReturnValue(Math.min(Mth.mulAndTruncate(progress, 13), 13)) - ); - } - if (IslandOptions.getCosmetics().isShowReputationBar()) { - this.getReputation().ifPresent(reputation -> - cir.setReturnValue(Math.min(Mth.mulAndTruncate(reputation, 13), 13)) - ); - } - if (IslandOptions.getCosmetics().isShowChromaBar()) { - this.getChromas().ifPresent(chromas -> - cir.setReturnValue(Math.min(Mth.mulAndTruncate(CosmeticChroma.toFraction(chromas), 13), 13)) - ); - } + this.getItemBar().ifPresent(barInfo -> cir.setReturnValue(barInfo.getBarWidth())); } - @Inject( - method = "getBarColor", - at = @At("RETURN"), - cancellable = true - ) + @Inject(method = "getBarColor", at = @At("RETURN"), cancellable = true) private void injectBarColor(CallbackInfoReturnable cir) { - if (IslandOptions.getMisc().isShowProgressBar()) { - if (this.getProgress().isPresent()) { - cir.setReturnValue(PROGRESS_BAR_COLOR); - } - } - if (IslandOptions.getCosmetics().isShowReputationBar()) { - if (this.getReputation().isPresent()) { - cir.setReturnValue(REPUTATION_BAR_COLOR); - } - } - if (IslandOptions.getCosmetics().isShowChromaBar()) { - this.getChromas().ifPresent(chromas -> { - if (chromas.isEmpty()) return; - - var currentChromaIdx = (int) ((System.currentTimeMillis() / CHROMA_BAR_COLOR_SPEED_MS) % chromas.size()); - var nextChromaIdx = (currentChromaIdx + 1) % chromas.size(); - - var currentChromaColor = chromas.get(currentChromaIdx).toColor(); - var nextChromaColor = chromas.get(nextChromaIdx).toColor(); - - var interpolatedProgress = (float) (System.currentTimeMillis() % CHROMA_BAR_COLOR_SPEED_MS) / CHROMA_BAR_COLOR_SPEED_MS; - var interpolatedColor = ARGB.lerp(interpolatedProgress, currentChromaColor, nextChromaColor); - - cir.setReturnValue(interpolatedColor); - }); - } + this.getItemBar().ifPresent(barInfo -> cir.setReturnValue(barInfo.color())); } } diff --git a/src/main/java/net/asodev/islandutils/modules/cosmetics/CosmeticChroma.java b/src/main/java/net/asodev/islandutils/modules/cosmetics/CosmeticChroma.java index 39d986a1..9a8887b0 100644 --- a/src/main/java/net/asodev/islandutils/modules/cosmetics/CosmeticChroma.java +++ b/src/main/java/net/asodev/islandutils/modules/cosmetics/CosmeticChroma.java @@ -13,6 +13,8 @@ public enum CosmeticChroma { MAGICAL, GRAYSCALE; + public static final int COUNT = 5; + public static Optional fromChar(char c) { return Optional.ofNullable(switch (c) { case '\uE02E' -> MECHANICAL; @@ -35,6 +37,6 @@ public int toColor() { } public static Fraction toFraction(List chromas) { - return Fraction.getFraction(chromas.size(), 5); + return Fraction.getFraction(chromas.size(), COUNT); } } diff --git a/src/main/java/net/asodev/islandutils/util/BarInfo.java b/src/main/java/net/asodev/islandutils/util/BarInfo.java new file mode 100644 index 00000000..5f5d41a6 --- /dev/null +++ b/src/main/java/net/asodev/islandutils/util/BarInfo.java @@ -0,0 +1,14 @@ +package net.asodev.islandutils.util; + +import net.minecraft.util.Mth; +import org.apache.commons.lang3.math.Fraction; + +public record BarInfo(Fraction fraction, int color) { + public int getBarWidth() { + if (fraction.compareTo(Fraction.ZERO) > 0) { + return Math.min(1 + Mth.mulAndTruncate(fraction, 12), 13); + } else { + return Math.min(Mth.mulAndTruncate(fraction, 13), 13); + } + } +} From 6156c2cdceaaeba3daf51809c8075667fccb26c1 Mon Sep 17 00:00:00 2001 From: violine1101 Date: Sun, 24 Aug 2025 18:13:39 +0200 Subject: [PATCH 05/22] Full red durability bar for repairable tools --- src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java b/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java index 534ff5b9..486c896e 100644 --- a/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java +++ b/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java @@ -71,7 +71,7 @@ private Optional getProgressBar(String lore) { if (isBrokenTool) return Optional.of(new BarInfo(Fraction.ZERO, PROGRESS_BAR_COLOR)); var isRepairableTool = lore.contains(PROGRESS_TOOL_REPAIRABLE_LABEL); - if (isRepairableTool) return Optional.of(new BarInfo(Fraction.getFraction(1, 100), REPAIRABLE_BAR_COLOR)); + if (isRepairableTool) return Optional.of(new BarInfo(Fraction.ONE, REPAIRABLE_BAR_COLOR)); var matcher = PROGRESS_REGEX.matcher(lore); var progresses = new ArrayList(); From 270eac4edead14d141a761b957048f5021878297 Mon Sep 17 00:00:00 2001 From: violine1101 Date: Mon, 25 Aug 2025 00:57:22 +0200 Subject: [PATCH 06/22] Use vanilla colors for tool durability bar --- .../java/net/asodev/islandutils/mixins/ItemBarMixin.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java b/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java index 486c896e..77ec75c7 100644 --- a/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java +++ b/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java @@ -6,6 +6,7 @@ import net.asodev.islandutils.util.Utils; import net.minecraft.network.chat.Component; import net.minecraft.util.ARGB; +import net.minecraft.util.Mth; import net.minecraft.world.item.ItemStack; import org.apache.commons.lang3.math.Fraction; import org.spongepowered.asm.mixin.Mixin; @@ -86,6 +87,12 @@ private Optional getProgressBar(String lore) { var fraction = isQuest ? progresses.stream().max(Fraction::compareTo) : progresses.stream().findFirst(); var isNonBrokenTool = lore.contains(PROGRESS_TOOL_USES_LABEL); + if (isNonBrokenTool) { + return fraction.map(f -> { + var color = Mth.hsvToRgb(f.floatValue() / 3.0F, 1.0F, 1.0F); + return new BarInfo(f, color); + }); + } return fraction.map(f -> new BarInfo(f, PROGRESS_BAR_COLOR)); } From 5d635f752cf8128508d73f68909eecd0c8f140b2 Mon Sep 17 00:00:00 2001 From: violine1101 Date: Mon, 1 Sep 2025 01:25:56 +0200 Subject: [PATCH 07/22] Don't show empty progress bar if progress is non-zero but rounded down to zero --- .../islandutils/mixins/ItemBarMixin.java | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java b/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java index 77ec75c7..cd94ca2d 100644 --- a/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java +++ b/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java @@ -9,6 +9,7 @@ import net.minecraft.util.Mth; import net.minecraft.world.item.ItemStack; import org.apache.commons.lang3.math.Fraction; +import org.jetbrains.annotations.NotNull; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; @@ -25,6 +26,8 @@ public class ItemBarMixin { @Unique private static final Pattern PROGRESS_REGEX = Pattern.compile(".*\\n[\\uE001\\uE269\\uE26C\\uE266]* (\\d+)%.*"); @Unique + private static final Pattern PROGRESS_TRUE_ZERO_REGEX = Pattern.compile(".*\\n[\\uE001\uE266]* 0%.*"); + @Unique private static final String PROGRESS_COSMETIC_LABEL = "Left-Click to Equip\n"; @Unique private static final String PROGRESS_COSMETIC_LABEL_2 = "Left-Click to Unequip\n"; @@ -74,13 +77,7 @@ private Optional getProgressBar(String lore) { var isRepairableTool = lore.contains(PROGRESS_TOOL_REPAIRABLE_LABEL); if (isRepairableTool) return Optional.of(new BarInfo(Fraction.ONE, REPAIRABLE_BAR_COLOR)); - var matcher = PROGRESS_REGEX.matcher(lore); - var progresses = new ArrayList(); - while (matcher.find()) { - var percentage = Integer.parseInt(matcher.group(1)); - var fraction = Fraction.getFraction(percentage, 100); - progresses.add(fraction); - } + var progresses = getProgresses(lore); if (progresses.isEmpty()) return Optional.empty(); var isQuest = lore.contains(PROGRESS_QUEST_LABEL); @@ -97,6 +94,25 @@ private Optional getProgressBar(String lore) { return fraction.map(f -> new BarInfo(f, PROGRESS_BAR_COLOR)); } + @Unique + private static @NotNull ArrayList getProgresses(String lore) { + var matcher = PROGRESS_REGEX.matcher(lore); + var progresses = new ArrayList(); + while (matcher.find()) { + var percentage = Integer.parseInt(matcher.group(1)); + if (percentage == 0) { + var trueZeroMatcher = PROGRESS_TRUE_ZERO_REGEX.matcher(matcher.group(0)); + if (!trueZeroMatcher.matches()) { + percentage = 1; + } + } + + var fraction = Fraction.getFraction(percentage, 100); + progresses.add(fraction); + } + return progresses; + } + @Unique private Optional getReputationBar(String lore) { if (!IslandOptions.getCosmetics().isShowReputationBar()) return Optional.empty(); From 6e4cf1e4ea68924d43bff0ebbe754781f6ad1c4f Mon Sep 17 00:00:00 2001 From: violine1101 Date: Mon, 1 Sep 2025 01:26:24 +0200 Subject: [PATCH 08/22] Add option to configure progress bar color; change default to white --- .../islandutils/mixins/ItemBarMixin.java | 6 ++---- .../options/categories/MiscOptions.java | 18 ++++++++++++++++++ .../resources/assets/island/lang/en_us.json | 1 + 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java b/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java index cd94ca2d..f70646d5 100644 --- a/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java +++ b/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java @@ -52,8 +52,6 @@ public class ItemBarMixin { @Unique private static final Pattern CHROMA_REGEX = Pattern.compile(".*\\n([\\uE02A\\uE02E\\uE02F\\uE02C\\uE02D\\uE02B]{5}) - (\\d+)\\uE328\\n.*"); - @Unique - private static final int PROGRESS_BAR_COLOR = ARGB.colorFromFloat(1.0F, 0.33F, 1.0F, 0.33F); @Unique private static final int REPAIRABLE_BAR_COLOR = ARGB.colorFromFloat(1.0F, 1.0F, 0.33F, 0.33F); @@ -72,7 +70,7 @@ private Optional getProgressBar(String lore) { if (isCosmetic || isProfileBadge) return Optional.empty(); var isBrokenTool = lore.contains(PROGRESS_TOOL_BROKEN_LABEL); - if (isBrokenTool) return Optional.of(new BarInfo(Fraction.ZERO, PROGRESS_BAR_COLOR)); + if (isBrokenTool) return Optional.of(new BarInfo(Fraction.ZERO, ARGB.alpha(0))); var isRepairableTool = lore.contains(PROGRESS_TOOL_REPAIRABLE_LABEL); if (isRepairableTool) return Optional.of(new BarInfo(Fraction.ONE, REPAIRABLE_BAR_COLOR)); @@ -91,7 +89,7 @@ private Optional getProgressBar(String lore) { }); } - return fraction.map(f -> new BarInfo(f, PROGRESS_BAR_COLOR)); + return fraction.map(f -> new BarInfo(f, IslandOptions.getMisc().getProgressBarColorARGB())); } @Unique diff --git a/src/main/java/net/asodev/islandutils/options/categories/MiscOptions.java b/src/main/java/net/asodev/islandutils/options/categories/MiscOptions.java index f784a3b5..79813073 100644 --- a/src/main/java/net/asodev/islandutils/options/categories/MiscOptions.java +++ b/src/main/java/net/asodev/islandutils/options/categories/MiscOptions.java @@ -4,10 +4,14 @@ import dev.isxander.yacl3.api.Option; import dev.isxander.yacl3.api.OptionDescription; import dev.isxander.yacl3.api.OptionGroup; +import dev.isxander.yacl3.api.controller.ColorControllerBuilder; import dev.isxander.yacl3.api.controller.TickBoxControllerBuilder; import net.asodev.islandutils.options.saving.Ignore; import net.asodev.islandutils.util.Utils; import net.minecraft.network.chat.Component; +import net.minecraft.util.ARGB; + +import java.awt.*; public class MiscOptions implements OptionsCategory { @Ignore @@ -22,6 +26,7 @@ public class MiscOptions implements OptionsCategory { boolean showProgressBar = true; boolean enableConfigButton = true; boolean debugMode = false; + int progressBarColorARGB = ARGB.opaque(Color.WHITE.getRGB()); public boolean isPauseConfirm() { return pauseConfirm; @@ -48,6 +53,9 @@ public boolean isShowFishingUpgradeIcon() { public boolean isShowProgressBar() { return showProgressBar; } + public int getProgressBarColorARGB() { + return progressBarColorARGB; + } public boolean isDebugMode() { return debugMode && !Utils.isLunarClient(); @@ -102,6 +110,15 @@ public ConfigCategory getCategory() { .controller(TickBoxControllerBuilder::create) .binding(defaults.showProgressBar, () -> showProgressBar, value -> this.showProgressBar = value) .build(); + Option progressBarColorOption = Option.createBuilder() + .name(Component.translatable("text.autoconfig.islandutils.option.progressBarColor")) + .controller(ColorControllerBuilder::create) + .binding( + new Color(defaults.progressBarColorARGB & 0xFFFFFF), + () -> new Color(progressBarColorARGB & 0xFFFFFF), + value -> this.progressBarColorARGB = ARGB.opaque(value.getRGB()) + ) + .build(); Option debugOption = Option.createBuilder() .name(Component.translatable("text.autoconfig.islandutils.option.debugMode")) .description(OptionDescription.of(Component.translatable("text.autoconfig.islandutils.option.debugMode.@Tooltip"))) @@ -124,6 +141,7 @@ public ConfigCategory getCategory() { .option(fishingUpgradeOption) .option(buttonOption) .option(progressBarOption) + .option(progressBarColorOption) .group(OptionGroup.createBuilder() .name(Component.translatable("text.autoconfig.islandutils.group.debugOptions")) .collapsed(true) diff --git a/src/main/resources/assets/island/lang/en_us.json b/src/main/resources/assets/island/lang/en_us.json index 7e3f966a..84273b72 100644 --- a/src/main/resources/assets/island/lang/en_us.json +++ b/src/main/resources/assets/island/lang/en_us.json @@ -85,6 +85,7 @@ "text.autoconfig.islandutils.option.channelSwitchers.@Tooltip": "Shows the chat channel switcher buttons above the chat box", "text.autoconfig.islandutils.option.showProgressBar": "Show progress bars", "text.autoconfig.islandutils.option.showProgressBar.@Tooltip": "Adds an progress bar to inventories for menu items with progress in their tooltip, such as quests or fishing islands", + "text.autoconfig.islandutils.option.progressBarColor": "Color for progress bars on items", "text.autoconfig.islandutils.option.hideSliders": "Hide Sound Sliders if not Online", "text.autoconfig.islandutils.option.hideSliders.@Tooltip": "Hides the Music Sliders if you're not on MCC Island", "text.autoconfig.islandutils.option.showFishingUpgradeIcon": "Show fishing upgrade icons", From db90b62a17d8a1a064d051e7c84e953f1c2dd580 Mon Sep 17 00:00:00 2001 From: violine1101 Date: Mon, 1 Sep 2025 01:35:38 +0200 Subject: [PATCH 09/22] Don't show progress bar on locked outfit slots --- .../java/net/asodev/islandutils/mixins/ItemBarMixin.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java b/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java index f70646d5..f38a1ab4 100644 --- a/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java +++ b/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java @@ -36,6 +36,8 @@ public class ItemBarMixin { @Unique private static final String PROGRESS_BADGE_LOCKED_LABEL = "\nUnlock this slot by reaching the below\namount of Skill Trophies.\n"; @Unique + private static final String PROGRESS_OUTFIT_LOCKED_LABEL = "Locked Outfit Slot\n\nSave a loadout of cosmetics and their"; + @Unique private static final String PROGRESS_QUEST_LABEL = "\nComplete any of the below tasks to\nfinish the quest.\n"; @Unique private static final String PROGRESS_TOOL_USES_LABEL = "\nUses Remaining: "; @@ -67,7 +69,8 @@ private Optional getProgressBar(String lore) { var isCosmetic = lore.contains(PROGRESS_COSMETIC_LABEL) || lore.contains(PROGRESS_COSMETIC_LABEL_2); var isProfileBadge = lore.contains(PROGRESS_BADGE_PINNED_LABEL) || lore.contains(PROGRESS_BADGE_LOCKED_LABEL); - if (isCosmetic || isProfileBadge) return Optional.empty(); + var isOutfitSlot = lore.contains(PROGRESS_OUTFIT_LOCKED_LABEL); + if (isCosmetic || isProfileBadge || isOutfitSlot) return Optional.empty(); var isBrokenTool = lore.contains(PROGRESS_TOOL_BROKEN_LABEL); if (isBrokenTool) return Optional.of(new BarInfo(Fraction.ZERO, ARGB.alpha(0))); From d90c194a6ba4423286bff47e2a171dce5125c0d0 Mon Sep 17 00:00:00 2001 From: violine1101 Date: Thu, 25 Sep 2025 02:29:52 +0200 Subject: [PATCH 10/22] Add debug hotkey F3+Z for printing item components --- .../islandutils/mixins/ItemIDMixin.java | 63 ++++++++++++++++--- 1 file changed, 56 insertions(+), 7 deletions(-) diff --git a/src/main/java/net/asodev/islandutils/mixins/ItemIDMixin.java b/src/main/java/net/asodev/islandutils/mixins/ItemIDMixin.java index 86cbf971..2881d171 100644 --- a/src/main/java/net/asodev/islandutils/mixins/ItemIDMixin.java +++ b/src/main/java/net/asodev/islandutils/mixins/ItemIDMixin.java @@ -20,7 +20,11 @@ import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.item.component.ItemLore; +import org.apache.commons.lang3.StringEscapeUtils; import org.jetbrains.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; @@ -28,10 +32,18 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; @Mixin(ItemStack.class) public abstract class ItemIDMixin implements DataComponentHolder { + @Unique + private static final Logger LOGGER = LoggerFactory.getLogger("IslandUtils"); + + @Unique + private int itemPrintCounter = -1; + @Inject( method = "getTooltipLines", at = @At( @@ -42,8 +54,14 @@ public abstract class ItemIDMixin implements DataComponentHolder { ) private void addTooltipLines(Item.TooltipContext tooltipContext, @Nullable Player player, TooltipFlag tooltipFlag, CallbackInfoReturnable> cir, @Local List list) { if (!MccIslandState.isOnline() || !IslandOptions.getMisc().isDebugMode()) return; - if (!InputConstants.isKeyDown(Minecraft.getInstance().getWindow().getWindow(), InputConstants.KEY_LCONTROL)) - return; + + var window = Minecraft.getInstance().getWindow().getWindow(); + + var itemPrintHotkeyHeld = InputConstants.isKeyDown(window, InputConstants.KEY_F3) && InputConstants.isKeyDown(window, InputConstants.KEY_Z); + itemPrintCounter = (itemPrintHotkeyHeld) ? itemPrintCounter + 1 : -1; + if (itemPrintCounter == 0) printItemInfo(); + + if (!InputConstants.isKeyDown(window, InputConstants.KEY_LCONTROL)) return; MutableComponent toAppend = Component.empty(); if (this.has(DataComponents.CUSTOM_DATA)) tryAddCustomItemID(toAppend); // Append MCCI Custom Item ID @@ -62,15 +80,46 @@ private void tryAddCustomItemID(MutableComponent toAppend) { } @Unique - private void tryAddSlotNumber(MutableComponent toAppend) { + private Optional getHoveredSlot() { ItemStack me = (ItemStack) (Object) this; Screen screen = Minecraft.getInstance().screen; - if (!(screen instanceof AbstractContainerScreen containerScreen)) return; + if (screen == null) return Optional.empty(); + if (!(screen instanceof AbstractContainerScreen containerScreen)) return Optional.empty(); Slot hoveredSlot = ((ContainerScreenAccessor) containerScreen).getHoveredSlot(); - if (hoveredSlot == null || !hoveredSlot.hasItem() || hoveredSlot.getItem() != me) return; - Component component = Component.literal(" (" + hoveredSlot.getContainerSlot() + ")").withStyle(ChatFormatting.GRAY); - toAppend.append(component); + if (!hoveredSlot.hasItem()) return Optional.empty(); + if (hoveredSlot.getItem() != me) return Optional.empty(); + return Optional.of(hoveredSlot); + } + + @Unique + private void tryAddSlotNumber(MutableComponent toAppend) { + getHoveredSlot().ifPresent(hoveredSlot -> { + Component component = Component.literal(" (" + hoveredSlot.getContainerSlot() + ")").withStyle(ChatFormatting.GRAY); + toAppend.append(component); + }); + } + + @Unique + private void printItemInfo() { + getHoveredSlot().ifPresent(hoveredSlot -> { + LOGGER.info("-----"); + LOGGER.info("Printing components of {}", hoveredSlot.getItem().getItem().getDescriptionId()); + LOGGER.info("-----"); + hoveredSlot.getItem().getComponents().forEach(component -> { + if (component.value() instanceof Component) { + LOGGER.info("{}=>\"{}\"", component.type(), ((Component) component.value()).getString()); + } else if (component.value() instanceof ItemLore) { + var lines = ((ItemLore) component.value()).lines(); + var lineStrings = lines.stream().map(Component::getString).map(StringEscapeUtils::escapeJava); + var fullString = lineStrings.collect(Collectors.joining("\\n")); + LOGGER.info("{}=>\"{}\"", component.type(), fullString); + } else { + LOGGER.info(component.toString()); + } + }); + LOGGER.info("-----"); + }); } } From 1b242d0d0797c99d9fae74e9908d582b72127471 Mon Sep 17 00:00:00 2001 From: violine1101 Date: Thu, 25 Sep 2025 02:42:11 +0200 Subject: [PATCH 11/22] Fix broken regexes from MCCI update --- .../java/net/asodev/islandutils/mixins/ItemBarMixin.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java b/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java index f38a1ab4..9f484f88 100644 --- a/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java +++ b/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java @@ -24,9 +24,9 @@ @Mixin(ItemStack.class) public class ItemBarMixin { @Unique - private static final Pattern PROGRESS_REGEX = Pattern.compile(".*\\n[\\uE001\\uE269\\uE26C\\uE266]* (\\d+)%.*"); + private static final Pattern PROGRESS_REGEX = Pattern.compile(".*\\n[\\uE001\\uE26A\\uE26D\\uE267]* (\\d+)%.*"); @Unique - private static final Pattern PROGRESS_TRUE_ZERO_REGEX = Pattern.compile(".*\\n[\\uE001\uE266]* 0%.*"); + private static final Pattern PROGRESS_TRUE_ZERO_REGEX = Pattern.compile(".*\\n[\\uE001\\uE267]* 0%.*"); @Unique private static final String PROGRESS_COSMETIC_LABEL = "Left-Click to Equip\n"; @Unique @@ -52,7 +52,7 @@ public class ItemBarMixin { @Unique private static final String CHROMA_LABEL = "\nChromas Unlocked:\n"; @Unique - private static final Pattern CHROMA_REGEX = Pattern.compile(".*\\n([\\uE02A\\uE02E\\uE02F\\uE02C\\uE02D\\uE02B]{5}) - (\\d+)\\uE328\\n.*"); + private static final Pattern CHROMA_REGEX = Pattern.compile(".*\\n([\\uE02A\\uE02E\\uE02F\\uE02C\\uE02D\\uE02B]{5}) - (\\d+)\\uE329\\n.*"); @Unique private static final int REPAIRABLE_BAR_COLOR = ARGB.colorFromFloat(1.0F, 1.0F, 0.33F, 0.33F); From 4884dec99bc134731ea1f3a0908e91dc3b629f28 Mon Sep 17 00:00:00 2001 From: violine1101 Date: Thu, 25 Sep 2025 02:45:00 +0200 Subject: [PATCH 12/22] Fix NullPointerException --- src/main/java/net/asodev/islandutils/mixins/ItemIDMixin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/asodev/islandutils/mixins/ItemIDMixin.java b/src/main/java/net/asodev/islandutils/mixins/ItemIDMixin.java index 2881d171..35c546ef 100644 --- a/src/main/java/net/asodev/islandutils/mixins/ItemIDMixin.java +++ b/src/main/java/net/asodev/islandutils/mixins/ItemIDMixin.java @@ -87,7 +87,7 @@ private Optional getHoveredSlot() { if (!(screen instanceof AbstractContainerScreen containerScreen)) return Optional.empty(); Slot hoveredSlot = ((ContainerScreenAccessor) containerScreen).getHoveredSlot(); - if (!hoveredSlot.hasItem()) return Optional.empty(); + if (hoveredSlot == null || !hoveredSlot.hasItem()) return Optional.empty(); if (hoveredSlot.getItem() != me) return Optional.empty(); return Optional.of(hoveredSlot); } From eae549b41cc652ab69db61dc036318f926227712 Mon Sep 17 00:00:00 2001 From: violine1101 Date: Fri, 26 Sep 2025 00:03:39 +0200 Subject: [PATCH 13/22] Fix progress bar for fishing items --- .../asodev/islandutils/mixins/ItemBarMixin.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java b/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java index 9f484f88..238a5ce0 100644 --- a/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java +++ b/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java @@ -24,9 +24,9 @@ @Mixin(ItemStack.class) public class ItemBarMixin { @Unique - private static final Pattern PROGRESS_REGEX = Pattern.compile(".*\\n[\\uE001\\uE26A\\uE26D\\uE267]* (\\d+)%.*"); + private static final Pattern PROGRESS_REGEX = Pattern.compile(".*\\n[\\uE001\\uE272\\uE267\\uE26A\\uE26C\\uE26D\\uE26F]* (\\d+)%.*"); @Unique - private static final Pattern PROGRESS_TRUE_ZERO_REGEX = Pattern.compile(".*\\n[\\uE001\\uE267]* 0%.*"); + private static final Pattern PROGRESS_TRUE_ZERO_REGEX = Pattern.compile(".*\\n[\\uE001\\uE267\\uE26C]* 0%.*"); @Unique private static final String PROGRESS_COSMETIC_LABEL = "Left-Click to Equip\n"; @Unique @@ -42,8 +42,12 @@ public class ItemBarMixin { @Unique private static final String PROGRESS_TOOL_USES_LABEL = "\nUses Remaining: "; @Unique + private static final String PROGRESS_TOOL_LINE_LABEL = "\nYour equipped line adds to your\n"; + @Unique private static final String PROGRESS_TOOL_REPAIRABLE_LABEL = "\nThis item is out of uses! You can Repair\nit to restore all its uses, you can only\ndo this once per item.\n"; @Unique + private static final String PROGRESS_TOOL_REPAIRED_LABEL = "\nThis item has previously been repaired.\n"; + @Unique private static final String PROGRESS_TOOL_BROKEN_LABEL = "\nThis item is out of uses! You've already\nrepaired it once, so cannot do so\nagain."; @Unique @@ -76,7 +80,7 @@ private Optional getProgressBar(String lore) { if (isBrokenTool) return Optional.of(new BarInfo(Fraction.ZERO, ARGB.alpha(0))); var isRepairableTool = lore.contains(PROGRESS_TOOL_REPAIRABLE_LABEL); - if (isRepairableTool) return Optional.of(new BarInfo(Fraction.ONE, REPAIRABLE_BAR_COLOR)); + if (isRepairableTool) return Optional.of(new BarInfo(Fraction.ONE_HALF, REPAIRABLE_BAR_COLOR)); var progresses = getProgresses(lore); if (progresses.isEmpty()) return Optional.empty(); @@ -87,6 +91,11 @@ private Optional getProgressBar(String lore) { var isNonBrokenTool = lore.contains(PROGRESS_TOOL_USES_LABEL); if (isNonBrokenTool) { return fraction.map(f -> { + var canRepairTool = !lore.contains(PROGRESS_TOOL_LINE_LABEL); + if (canRepairTool) { + var isRepairedTool = lore.contains(PROGRESS_TOOL_REPAIRED_LABEL); + f = (isRepairedTool ? f : f.add(Fraction.ONE)).divideBy(Fraction.getFraction(2, 1)); + } var color = Mth.hsvToRgb(f.floatValue() / 3.0F, 1.0F, 1.0F); return new BarInfo(f, color); }); From 1785cac636cf1b67a7ff43bab8e812c5a8081075 Mon Sep 17 00:00:00 2001 From: violine1101 Date: Wed, 8 Oct 2025 01:29:02 +0200 Subject: [PATCH 14/22] Don't show progress bar on badges with built-in progress indicator --- .../java/net/asodev/islandutils/mixins/ItemBarMixin.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java b/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java index 238a5ce0..31c1597b 100644 --- a/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java +++ b/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java @@ -32,6 +32,10 @@ public class ItemBarMixin { @Unique private static final String PROGRESS_COSMETIC_LABEL_2 = "Left-Click to Unequip\n"; @Unique + private static final String PROGRESS_BADGE_EARNED_LABEL = "Click to Display on Profile"; + @Unique + private static final String PROGRESS_BADGE_INCOMPLETE_LABEL = "\n\nStage incomplete\n\n"; + @Unique private static final String PROGRESS_BADGE_PINNED_LABEL = "Shift-Click to Unpin"; @Unique private static final String PROGRESS_BADGE_LOCKED_LABEL = "\nUnlock this slot by reaching the below\namount of Skill Trophies.\n"; @@ -72,9 +76,10 @@ private Optional getProgressBar(String lore) { if (!IslandOptions.getMisc().isShowProgressBar()) return Optional.empty(); var isCosmetic = lore.contains(PROGRESS_COSMETIC_LABEL) || lore.contains(PROGRESS_COSMETIC_LABEL_2); + var isNonEarnedBadge = lore.contains(PROGRESS_BADGE_INCOMPLETE_LABEL) && !lore.contains(PROGRESS_BADGE_EARNED_LABEL); var isProfileBadge = lore.contains(PROGRESS_BADGE_PINNED_LABEL) || lore.contains(PROGRESS_BADGE_LOCKED_LABEL); var isOutfitSlot = lore.contains(PROGRESS_OUTFIT_LOCKED_LABEL); - if (isCosmetic || isProfileBadge || isOutfitSlot) return Optional.empty(); + if (isCosmetic || isNonEarnedBadge || isProfileBadge || isOutfitSlot) return Optional.empty(); var isBrokenTool = lore.contains(PROGRESS_TOOL_BROKEN_LABEL); if (isBrokenTool) return Optional.of(new BarInfo(Fraction.ZERO, ARGB.alpha(0))); From ef94c989c9e733819e7a0ecc70b5953d963080d5 Mon Sep 17 00:00:00 2001 From: violine1101 Date: Mon, 13 Oct 2025 03:05:26 +0200 Subject: [PATCH 15/22] Adapt to code changes on main --- src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java b/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java index 31c1597b..4b3d2afe 100644 --- a/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java +++ b/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java @@ -184,7 +184,7 @@ private Optional getChromaBar(String lore) { @Unique private Optional getItemBar() { var itemStack = (ItemStack)(Object)this; - var lore = Utils.getLores(itemStack); + var lore = Utils.getTooltipLines(itemStack); if (lore == null) return Optional.empty(); var loreStr = lore.stream().map(Component::getString).collect(Collectors.joining("\n")); From 50cbaa94f8934e262b34776f81819c63a7da85f2 Mon Sep 17 00:00:00 2001 From: violine1101 Date: Fri, 31 Oct 2025 03:56:25 +0100 Subject: [PATCH 16/22] Fix half-filled progress bar character breaking progress detection --- src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java b/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java index 4b3d2afe..a912eca2 100644 --- a/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java +++ b/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java @@ -24,7 +24,7 @@ @Mixin(ItemStack.class) public class ItemBarMixin { @Unique - private static final Pattern PROGRESS_REGEX = Pattern.compile(".*\\n[\\uE001\\uE272\\uE267\\uE26A\\uE26C\\uE26D\\uE26F]* (\\d+)%.*"); + private static final Pattern PROGRESS_REGEX = Pattern.compile(".*\\n[\\uE001\\uE272\\uE267\\uE26A\\uE26C\\uE26D\\uE26F\\uE273]* (\\d+)%.*"); @Unique private static final Pattern PROGRESS_TRUE_ZERO_REGEX = Pattern.compile(".*\\n[\\uE001\\uE267\\uE26C]* 0%.*"); @Unique From 89936efaea4c119a2d31e07fdf2a6f122448c005 Mon Sep 17 00:00:00 2001 From: violine1101 Date: Fri, 31 Oct 2025 04:10:13 +0100 Subject: [PATCH 17/22] oops, fix regex, again --- src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java b/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java index a912eca2..644c4eaa 100644 --- a/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java +++ b/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java @@ -24,9 +24,9 @@ @Mixin(ItemStack.class) public class ItemBarMixin { @Unique - private static final Pattern PROGRESS_REGEX = Pattern.compile(".*\\n[\\uE001\\uE272\\uE267\\uE26A\\uE26C\\uE26D\\uE26F\\uE273]* (\\d+)%.*"); + private static final Pattern PROGRESS_REGEX = Pattern.compile(".*\\n[\\uE001\\uE272\\uE267\\uE26A\\uE26C\\uE26D\\uE26F\\uE270\\uE273]* (\\d+)%.*"); @Unique - private static final Pattern PROGRESS_TRUE_ZERO_REGEX = Pattern.compile(".*\\n[\\uE001\\uE267\\uE26C]* 0%.*"); + private static final Pattern PROGRESS_TRUE_ZERO_REGEX = Pattern.compile(".*\\n[\\uE001\\uE267\\uE26C\\uE26D]* 0%.*"); @Unique private static final String PROGRESS_COSMETIC_LABEL = "Left-Click to Equip\n"; @Unique From ca38f7afc5f4cdb135ab04ec76f709e4cebf022b Mon Sep 17 00:00:00 2001 From: violine1101 Date: Fri, 31 Oct 2025 19:25:06 +0100 Subject: [PATCH 18/22] Fix chroma regex --- src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java b/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java index 644c4eaa..7f1497eb 100644 --- a/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java +++ b/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java @@ -60,7 +60,7 @@ public class ItemBarMixin { @Unique private static final String CHROMA_LABEL = "\nChromas Unlocked:\n"; @Unique - private static final Pattern CHROMA_REGEX = Pattern.compile(".*\\n([\\uE02A\\uE02E\\uE02F\\uE02C\\uE02D\\uE02B]{5}) - (\\d+)\\uE329\\n.*"); + private static final Pattern CHROMA_REGEX = Pattern.compile(".*\\n([\\uE02A\\uE02E\\uE02F\\uE02C\\uE02D\\uE02B]{5}) - (\\d+)\\uE330\\n.*"); @Unique private static final int REPAIRABLE_BAR_COLOR = ARGB.colorFromFloat(1.0F, 1.0F, 0.33F, 0.33F); From c7c0a37375b5098e4ba90f9deb912a8d2d4200a2 Mon Sep 17 00:00:00 2001 From: violine1101 Date: Sat, 1 Nov 2025 00:14:36 +0100 Subject: [PATCH 19/22] Change default for reputation and chroma bars to off --- .../islandutils/options/categories/CosmeticsOptions.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/asodev/islandutils/options/categories/CosmeticsOptions.java b/src/main/java/net/asodev/islandutils/options/categories/CosmeticsOptions.java index 55fbe956..746a81d1 100644 --- a/src/main/java/net/asodev/islandutils/options/categories/CosmeticsOptions.java +++ b/src/main/java/net/asodev/islandutils/options/categories/CosmeticsOptions.java @@ -13,8 +13,8 @@ public class CosmeticsOptions implements OptionsCategory { boolean showPlayerPreview = true; boolean showOnHover = true; boolean showOnOnlyCosmeticMenus = true; - boolean showReputationBar = true; - boolean showChromaBar = true; + boolean showReputationBar = false; + boolean showChromaBar = false; public boolean isShowPlayerPreview() { return showPlayerPreview; From 5117b29a94066df06976fd455b6344005b5c8d7a Mon Sep 17 00:00:00 2001 From: violine1101 Date: Tue, 2 Dec 2025 01:47:22 +0100 Subject: [PATCH 20/22] fix progress regex for mcci update --- src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java b/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java index 7f1497eb..8d10fb6a 100644 --- a/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java +++ b/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java @@ -24,7 +24,7 @@ @Mixin(ItemStack.class) public class ItemBarMixin { @Unique - private static final Pattern PROGRESS_REGEX = Pattern.compile(".*\\n[\\uE001\\uE272\\uE267\\uE26A\\uE26C\\uE26D\\uE26F\\uE270\\uE273]* (\\d+)%.*"); + private static final Pattern PROGRESS_REGEX = Pattern.compile(".*\\n[\\uE001\\uE272\\uE267\\uE26A\\uE26C\\uE26D\\uE26F\\uE270\\uE273\\uE275]* (\\d+)%.*"); @Unique private static final Pattern PROGRESS_TRUE_ZERO_REGEX = Pattern.compile(".*\\n[\\uE001\\uE267\\uE26C\\uE26D]* 0%.*"); @Unique From dea4e3ecd73cb3f727f4c689684734ebf14c79f5 Mon Sep 17 00:00:00 2001 From: violine1101 Date: Sat, 6 Dec 2025 00:39:00 +0100 Subject: [PATCH 21/22] Fix regex for detecting a fully zero progress bar --- src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java b/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java index 8d10fb6a..9543b1ba 100644 --- a/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java +++ b/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java @@ -26,7 +26,7 @@ public class ItemBarMixin { @Unique private static final Pattern PROGRESS_REGEX = Pattern.compile(".*\\n[\\uE001\\uE272\\uE267\\uE26A\\uE26C\\uE26D\\uE26F\\uE270\\uE273\\uE275]* (\\d+)%.*"); @Unique - private static final Pattern PROGRESS_TRUE_ZERO_REGEX = Pattern.compile(".*\\n[\\uE001\\uE267\\uE26C\\uE26D]* 0%.*"); + private static final Pattern PROGRESS_TRUE_ZERO_REGEX = Pattern.compile(".*\\n[\\uE001\\uE267\\uE26C\\uE26D\\uE26F]* 0%.*"); @Unique private static final String PROGRESS_COSMETIC_LABEL = "Left-Click to Equip\n"; @Unique From a2be58e40f0358ffccc0cd3a2c34317d5fdad71b Mon Sep 17 00:00:00 2001 From: violine1101 Date: Sun, 14 Dec 2025 19:06:49 +0100 Subject: [PATCH 22/22] Adjust regexes again; single point of truth for custom icon unicode chars --- .../islandutils/mixins/ItemBarMixin.java | 16 ++++++++-- .../modules/cosmetics/CosmeticChroma.java | 30 +++++++++++++------ 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java b/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java index 9543b1ba..9077a8fb 100644 --- a/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java +++ b/src/main/java/net/asodev/islandutils/mixins/ItemBarMixin.java @@ -24,9 +24,17 @@ @Mixin(ItemStack.class) public class ItemBarMixin { @Unique - private static final Pattern PROGRESS_REGEX = Pattern.compile(".*\\n[\\uE001\\uE272\\uE267\\uE26A\\uE26C\\uE26D\\uE26F\\uE270\\uE273\\uE275]* (\\d+)%.*"); + private static final String BAR_SEGMENT_SPACE = "\\uE001"; @Unique - private static final Pattern PROGRESS_TRUE_ZERO_REGEX = Pattern.compile(".*\\n[\\uE001\\uE267\\uE26C\\uE26D\\uE26F]* 0%.*"); + private static final String BAR_SEGMENT_EMPTY = "\\uE27C"; + @Unique + private static final String BAR_SEGMENT_HALF = "\\uE282"; + @Unique + private static final String BAR_SEGMENT_FULL = "\\uE27F"; + @Unique + private static final Pattern PROGRESS_REGEX = Pattern.compile(".*\\n[" + BAR_SEGMENT_SPACE + BAR_SEGMENT_EMPTY + BAR_SEGMENT_HALF + BAR_SEGMENT_FULL + "]* (\\d+)%.*"); + @Unique + private static final Pattern PROGRESS_TRUE_ZERO_REGEX = Pattern.compile(".*\\n[" + BAR_SEGMENT_SPACE + BAR_SEGMENT_EMPTY + "]* 0%.*"); @Unique private static final String PROGRESS_COSMETIC_LABEL = "Left-Click to Equip\n"; @Unique @@ -60,7 +68,9 @@ public class ItemBarMixin { @Unique private static final String CHROMA_LABEL = "\nChromas Unlocked:\n"; @Unique - private static final Pattern CHROMA_REGEX = Pattern.compile(".*\\n([\\uE02A\\uE02E\\uE02F\\uE02C\\uE02D\\uE02B]{5}) - (\\d+)\\uE330\\n.*"); + private static final String STYLE_TROPHY_ICON = "\\uE34D"; + @Unique + private static final Pattern CHROMA_REGEX = Pattern.compile(".*\\n(" + CosmeticChroma.CHAR_REGEX + "{5}) - (\\d+)" + STYLE_TROPHY_ICON + "\\n.*"); @Unique private static final int REPAIRABLE_BAR_COLOR = ARGB.colorFromFloat(1.0F, 1.0F, 0.33F, 0.33F); diff --git a/src/main/java/net/asodev/islandutils/modules/cosmetics/CosmeticChroma.java b/src/main/java/net/asodev/islandutils/modules/cosmetics/CosmeticChroma.java index 9a8887b0..7ee68165 100644 --- a/src/main/java/net/asodev/islandutils/modules/cosmetics/CosmeticChroma.java +++ b/src/main/java/net/asodev/islandutils/modules/cosmetics/CosmeticChroma.java @@ -1,5 +1,7 @@ package net.asodev.islandutils.modules.cosmetics; +import com.google.common.collect.EnumHashBiMap; +import com.google.common.collect.ImmutableMap; import net.minecraft.util.ARGB; import org.apache.commons.lang3.math.Fraction; @@ -13,17 +15,27 @@ public enum CosmeticChroma { MAGICAL, GRAYSCALE; - public static final int COUNT = 5; + private static final char EMPTY_CHAR = '\uE02A'; + private static final EnumHashBiMap CHARS = EnumHashBiMap.create( + ImmutableMap.of( + MECHANICAL, '\uE02E', + NATURAL, '\uE02F', + OCEANIC, '\uE02C', + MAGICAL, '\uE02D', + GRAYSCALE, '\uE02B' + ) + ); + public static final String CHAR_REGEX = + "[" + EMPTY_CHAR + String.join("", CHARS.values().stream().map(String::valueOf).toList()) + "]"; + + public static final int COUNT = CHARS.size(); + + public final char toChar() { + return Optional.ofNullable(CHARS.get(this)).orElse(EMPTY_CHAR); + } public static Optional fromChar(char c) { - return Optional.ofNullable(switch (c) { - case '\uE02E' -> MECHANICAL; - case '\uE02F' -> NATURAL; - case '\uE02C' -> OCEANIC; - case '\uE02D' -> MAGICAL; - case '\uE02B' -> GRAYSCALE; - default -> null; - }); + return Optional.ofNullable(CHARS.inverse().get(c)); } public int toColor() {