From 37484f635420f40b7af0f80102ca63b5a467758b Mon Sep 17 00:00:00 2001 From: violine1101 Date: Sat, 23 Aug 2025 10:47:51 +0200 Subject: [PATCH 1/4] 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 bf9747aa..6d071afd 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.literal("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 3314a5dc..b0966ec0 100644 --- a/src/main/resources/assets/island/lang/en_us.json +++ b/src/main/resources/assets/island/lang/en_us.json @@ -23,6 +23,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.option.discordPresence": "Enable Discord Presence", diff --git a/src/main/resources/islandutils.mixins.json b/src/main/resources/islandutils.mixins.json index 9ca0dd57..fd0d6c92 100644 --- a/src/main/resources/islandutils.mixins.json +++ b/src/main/resources/islandutils.mixins.json @@ -10,6 +10,7 @@ "cosmetics.ChestScreenMixin", "cosmetics.FontLoaderMixin", "cosmetics.PreviewTutorialMixin", + "cosmetics.ReputationBarMixin", "discord.ConnectionMixin", "discord.ScoreDisplayMixin", "resources.PackRepositoryMixin", From ffc70f90a0096ea3d3ffcbd71e756f16244210c2 Mon Sep 17 00:00:00 2001 From: violine1101 Date: Sat, 23 Aug 2025 12:18:48 +0200 Subject: [PATCH 2/4] 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 6d071afd..21dbfd15 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.literal("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 b0966ec0..d0d2c42f 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.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.option.discordPresence": "Enable Discord Presence", diff --git a/src/main/resources/islandutils.mixins.json b/src/main/resources/islandutils.mixins.json index fd0d6c92..ba24bc07 100644 --- a/src/main/resources/islandutils.mixins.json +++ b/src/main/resources/islandutils.mixins.json @@ -10,7 +10,7 @@ "cosmetics.ChestScreenMixin", "cosmetics.FontLoaderMixin", "cosmetics.PreviewTutorialMixin", - "cosmetics.ReputationBarMixin", + "cosmetics.ItemBarMixin", "discord.ConnectionMixin", "discord.ScoreDisplayMixin", "resources.PackRepositoryMixin", From daabdb73b93900019390e08a48d391cb4f73deef Mon Sep 17 00:00:00 2001 From: violine1101 Date: Sat, 23 Aug 2025 15:06:48 +0200 Subject: [PATCH 3/4] 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 d3f698b9..9132ea79 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.literal("Debug Options")) .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 d0d2c42f..5e162bd9 100644 --- a/src/main/resources/assets/island/lang/en_us.json +++ b/src/main/resources/assets/island/lang/en_us.json @@ -76,6 +76,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 ba24bc07..0746c6eb 100644 --- a/src/main/resources/islandutils.mixins.json +++ b/src/main/resources/islandutils.mixins.json @@ -10,7 +10,7 @@ "cosmetics.ChestScreenMixin", "cosmetics.FontLoaderMixin", "cosmetics.PreviewTutorialMixin", - "cosmetics.ItemBarMixin", + "ItemBarMixin", "discord.ConnectionMixin", "discord.ScoreDisplayMixin", "resources.PackRepositoryMixin", From d475af45d193060a3b4ea5b082158cc13d99cc72 Mon Sep 17 00:00:00 2001 From: violine1101 Date: Sat, 23 Aug 2025 23:23:09 +0200 Subject: [PATCH 4/4] 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); + } + } +}