diff options
| author | Aaron <51387595+AzureAaron@users.noreply.github.com> | 2024-11-25 22:49:57 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-11-25 22:49:57 -0500 |
| commit | 768919dc3021b5496d2c9d4dcf7a2a5c36260997 (patch) | |
| tree | 06e3a14a3e7ee4b0e76c6079ae77b7de419da500 /src/main/java | |
| parent | 8d986df7fc39dac8a39426e80b277cc731c8dcc0 (diff) | |
| download | Skyblocker-768919dc3021b5496d2c9d4dcf7a2a5c36260997.tar.gz Skyblocker-768919dc3021b5496d2c9d4dcf7a2a5c36260997.tar.bz2 Skyblocker-768919dc3021b5496d2c9d4dcf7a2a5c36260997.zip | |
Item Stuff (#1060)
* Add getUuid and getPetInfo methods to ItemStacks
* Fix pet rarity backgrounds in the pets menu
* Skyblock ID Tooltip
* Stacking Enchantment Progress Tooltip
* Use Advanced Item Tooltips for skyblock id
Diffstat (limited to 'src/main/java')
16 files changed, 273 insertions, 67 deletions
diff --git a/src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java index 7b26793a..f7b0fead 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java @@ -255,6 +255,14 @@ public class GeneralCategory { newValue -> config.general.itemTooltip.enableEstimatedItemValue = newValue) .controller(ConfigUtils::createBooleanController) .build()) + .option(Option.<Boolean>createBuilder() + .name(Text.translatable("skyblocker.config.general.itemTooltip.enableStackingEnchantProgress")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.general.itemTooltip.enableStackingEnchantProgress.@Tooltip"))) + .binding(defaults.general.itemTooltip.enableStackingEnchantProgress, + () -> config.general.itemTooltip.enableStackingEnchantProgress, + newValue -> config.general.itemTooltip.enableStackingEnchantProgress = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) .build()) //Item Info Display diff --git a/src/main/java/de/hysky/skyblocker/config/configs/GeneralConfig.java b/src/main/java/de/hysky/skyblocker/config/configs/GeneralConfig.java index 1c845287..f2396284 100644 --- a/src/main/java/de/hysky/skyblocker/config/configs/GeneralConfig.java +++ b/src/main/java/de/hysky/skyblocker/config/configs/GeneralConfig.java @@ -138,6 +138,9 @@ public class GeneralConfig { @SerialEntry public boolean enableEstimatedItemValue = true; + + @SerialEntry + public boolean enableStackingEnchantProgress = true; } public enum Average { diff --git a/src/main/java/de/hysky/skyblocker/injected/SkyblockerStack.java b/src/main/java/de/hysky/skyblocker/injected/SkyblockerStack.java index 28282b20..55e694ee 100644 --- a/src/main/java/de/hysky/skyblocker/injected/SkyblockerStack.java +++ b/src/main/java/de/hysky/skyblocker/injected/SkyblockerStack.java @@ -2,6 +2,8 @@ package de.hysky.skyblocker.injected; import org.jetbrains.annotations.NotNull; +import de.hysky.skyblocker.skyblock.item.PetInfo; + public interface SkyblockerStack { @NotNull default String getSkyblockId() { @@ -17,4 +19,14 @@ public interface SkyblockerStack { default String getNeuName() { return ""; } + + @NotNull + default String getUuid() { + return ""; + } + + @NotNull + default PetInfo getPetInfo() { + return PetInfo.EMPTY; + } } diff --git a/src/main/java/de/hysky/skyblocker/mixins/ItemStackMixin.java b/src/main/java/de/hysky/skyblocker/mixins/ItemStackMixin.java index 2c555475..3eb924b6 100644 --- a/src/main/java/de/hysky/skyblocker/mixins/ItemStackMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/ItemStackMixin.java @@ -3,6 +3,7 @@ package de.hysky.skyblocker.mixins; import com.llamalad7.mixinextras.injector.ModifyReturnValue; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.injected.SkyblockerStack; +import de.hysky.skyblocker.skyblock.item.PetInfo; import de.hysky.skyblocker.skyblock.profileviewer.ProfileViewerScreen; import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.Utils; @@ -24,13 +25,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(ItemStack.class) public abstract class ItemStackMixin implements ComponentHolder, SkyblockerStack { - - @Shadow - public abstract int getDamage(); - - @Shadow - public abstract void setDamage(int damage); - @Unique private int maxDamage; @@ -43,6 +37,18 @@ public abstract class ItemStackMixin implements ComponentHolder, SkyblockerStack @Unique private String neuName; + @Unique + private String uuid; + + @Unique + private PetInfo petInfo; + + @Shadow + public abstract int getDamage(); + + @Shadow + public abstract void setDamage(int damage); + @ModifyReturnValue(method = "getName", at = @At("RETURN")) private Text skyblocker$customItemNames(Text original) { if (Utils.isOnSkyblock()) { @@ -138,4 +144,18 @@ public abstract class ItemStackMixin implements ComponentHolder, SkyblockerStack if (neuName != null && !neuName.isEmpty()) return neuName; return neuName = ItemUtils.getNeuId((ItemStack) (Object) this); } + + @Override + @NotNull + public String getUuid() { + if (uuid != null && !uuid.isEmpty()) return uuid; + return uuid = ItemUtils.getItemUuid(this); + } + + @Override + @NotNull + public PetInfo getPetInfo() { + if (petInfo != null) return petInfo; + return petInfo = ItemUtils.getPetInfo(this); + } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/PetCache.java b/src/main/java/de/hysky/skyblocker/skyblock/PetCache.java index e9bd1e40..35fea3fa 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/PetCache.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/PetCache.java @@ -4,17 +4,15 @@ import com.google.gson.JsonParser; import com.mojang.logging.LogUtils; import com.mojang.serialization.Codec; import com.mojang.serialization.JsonOps; -import com.mojang.serialization.codecs.RecordCodecBuilder; import de.hysky.skyblocker.SkyblockerMod; import de.hysky.skyblocker.annotations.Init; -import de.hysky.skyblocker.skyblock.item.SkyblockItemRarity; +import de.hysky.skyblocker.skyblock.item.PetInfo; import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.Utils; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents; import net.minecraft.client.gui.screen.ingame.GenericContainerScreen; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NbtCompound; import net.minecraft.screen.slot.Slot; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; @@ -24,7 +22,6 @@ import java.io.BufferedWriter; import java.nio.file.Files; import java.nio.file.NoSuchFileException; import java.nio.file.Path; -import java.util.Optional; import java.util.concurrent.CompletableFuture; /** @@ -36,6 +33,9 @@ public class PetCache { private static final Logger LOGGER = LogUtils.getLogger(); private static final Path FILE = SkyblockerMod.CONFIG_DIR.resolve("pet_cache.json"); private static final Object2ObjectOpenHashMap<String, Object2ObjectOpenHashMap<String, PetInfo>> CACHED_PETS = new Object2ObjectOpenHashMap<>(); + public static final Codec<Object2ObjectOpenHashMap<String, Object2ObjectOpenHashMap<String, PetInfo>>> SERIALIZATION_CODEC = Codec.unboundedMap(Codec.STRING, + Codec.unboundedMap(Codec.STRING, PetInfo.CODEC).xmap(Object2ObjectOpenHashMap::new, Object2ObjectOpenHashMap::new) + ).xmap(Object2ObjectOpenHashMap::new, Object2ObjectOpenHashMap::new); /** * Used in case the server lags to prevent the screen tick check from overwriting the clicked pet logic @@ -73,7 +73,7 @@ public class PetCache { private static void load() { CompletableFuture.runAsync(() -> { try (BufferedReader reader = Files.newBufferedReader(FILE)) { - CACHED_PETS.putAll(PetInfo.SERIALIZATION_CODEC.parse(JsonOps.INSTANCE, JsonParser.parseReader(reader)).getOrThrow()); + CACHED_PETS.putAll(SERIALIZATION_CODEC.parse(JsonOps.INSTANCE, JsonParser.parseReader(reader)).getOrThrow()); } catch (NoSuchFileException ignored) { } catch (Exception e) { LOGGER.error("[Skyblocker Pet Cache] Failed to load saved pet!", e); @@ -84,7 +84,7 @@ public class PetCache { private static void save() { CompletableFuture.runAsync(() -> { try (BufferedWriter writer = Files.newBufferedWriter(FILE)) { - SkyblockerMod.GSON.toJson(PetInfo.SERIALIZATION_CODEC.encodeStart(JsonOps.INSTANCE, CACHED_PETS).getOrThrow(), writer); + SkyblockerMod.GSON.toJson(SERIALIZATION_CODEC.encodeStart(JsonOps.INSTANCE, CACHED_PETS).getOrThrow(), writer); } catch (Exception e) { LOGGER.error("[Skyblocker Pet Cache] Failed to save pet data to the cache!", e); } @@ -101,30 +101,27 @@ public class PetCache { } private static void parsePet(ItemStack stack, boolean clicked) { - String id = ItemUtils.getItemId(stack); String profileId = Utils.getProfileId(); - if (id.equals("PET") && !profileId.isEmpty()) { - NbtCompound customData = ItemUtils.getCustomData(stack); + if (stack.getSkyblockId().equals("PET") && !profileId.isEmpty()) { + //I once hoped that all pets would have a petInfo field, but that turned out to be false ;( + PetInfo petInfo = stack.getPetInfo(); - //Should never fail, all pets must have this but you never know with Hypixel - try { - PetInfo petInfo = PetInfo.CODEC.parse(JsonOps.INSTANCE, JsonParser.parseString(customData.getString("petInfo"))).getOrThrow(); - shouldLook4Pets = false; + //This probably shouldn't happen since I would imagine pets inside of a pet menu would have a pet info but you never know... + if (petInfo.isEmpty()) return; - Object2ObjectOpenHashMap<String, PetInfo> playerData = CACHED_PETS.computeIfAbsent(Utils.getUndashedUuid(), _uuid -> new Object2ObjectOpenHashMap<>()); + shouldLook4Pets = false; - //Handle deselecting pets - if (clicked && getCurrentPet() != null && getCurrentPet().uuid().orElse("").equals(petInfo.uuid().orElse(""))) { - playerData.remove(profileId); - } else { - playerData.put(profileId, petInfo); - } + Object2ObjectOpenHashMap<String, PetInfo> playerData = CACHED_PETS.computeIfAbsent(Utils.getUndashedUuid(), _uuid -> new Object2ObjectOpenHashMap<>()); - save(); - } catch (Exception e) { - LOGGER.error(LogUtils.FATAL_MARKER, "[Skyblocker Pet Cache] Failed to parse pet's pet info!", e); + //Handle deselecting pets + if (clicked && getCurrentPet() != null && getCurrentPet().uuid().orElse("").equals(petInfo.uuid().orElse(""))) { + playerData.remove(profileId); + } else { + playerData.put(profileId, petInfo); } + + save(); } } @@ -135,22 +132,4 @@ public class PetCache { return CACHED_PETS.containsKey(uuid) && CACHED_PETS.get(uuid).containsKey(profileId) ? CACHED_PETS.get(uuid).get(profileId) : null; } - - public record PetInfo(String type, double exp, String tier, Optional<String> uuid, Optional<String> item, Optional<String> skin) { - public static final Codec<PetInfo> CODEC = RecordCodecBuilder.create(instance -> instance.group( - Codec.STRING.fieldOf("type").forGetter(PetInfo::type), - Codec.DOUBLE.fieldOf("exp").forGetter(PetInfo::exp), - Codec.STRING.fieldOf("tier").forGetter(PetInfo::tier), - Codec.STRING.optionalFieldOf("uuid").forGetter(PetInfo::uuid), - Codec.STRING.optionalFieldOf("heldItem").forGetter(PetInfo::item), - Codec.STRING.optionalFieldOf("skin").forGetter(PetInfo::skin) - ).apply(instance, PetInfo::new)); - private static final Codec<Object2ObjectOpenHashMap<String, Object2ObjectOpenHashMap<String, PetInfo>>> SERIALIZATION_CODEC = Codec.unboundedMap(Codec.STRING, - Codec.unboundedMap(Codec.STRING, CODEC).xmap(Object2ObjectOpenHashMap::new, Object2ObjectOpenHashMap::new) - ).xmap(Object2ObjectOpenHashMap::new, Object2ObjectOpenHashMap::new); - - public int tierIndex() { - return SkyblockItemRarity.valueOf(tier).ordinal(); - } - } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/StatusBarTracker.java b/src/main/java/de/hysky/skyblocker/skyblock/StatusBarTracker.java index c589438c..e6405ae1 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/StatusBarTracker.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/StatusBarTracker.java @@ -1,6 +1,7 @@ package de.hysky.skyblocker.skyblock; import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.skyblock.item.PetInfo; import de.hysky.skyblocker.utils.Location; import de.hysky.skyblocker.utils.RegexUtils; import de.hysky.skyblocker.utils.Utils; @@ -140,7 +141,7 @@ public class StatusBarTracker { max = 500; } - PetCache.PetInfo pet = PetCache.getCurrentPet(); + PetInfo pet = PetCache.getCurrentPet(); if (pet != null) { if (pet.type().contains("BLACK_CAT")) { max = 500; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/ItemCooldowns.java b/src/main/java/de/hysky/skyblocker/skyblock/item/ItemCooldowns.java index ee274236..cf0356bc 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/ItemCooldowns.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/ItemCooldowns.java @@ -3,7 +3,6 @@ package de.hysky.skyblocker.skyblock.item; import de.hysky.skyblocker.annotations.Init; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.skyblock.PetCache; -import de.hysky.skyblocker.skyblock.PetCache.PetInfo; import de.hysky.skyblocker.utils.ItemUtils; import net.fabricmc.fabric.api.event.client.player.ClientPlayerBlockBreakEvents; import net.fabricmc.fabric.api.event.player.UseItemCallback; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/ItemRarityBackgrounds.java b/src/main/java/de/hysky/skyblocker/skyblock/item/ItemRarityBackgrounds.java index b771b067..87b35af3 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/ItemRarityBackgrounds.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/ItemRarityBackgrounds.java @@ -69,23 +69,32 @@ public class ItemRarityBackgrounds { private static SkyblockItemRarity getItemRarity(ItemStack stack, ClientPlayerEntity player) { if (stack == null || stack.isEmpty()) return null; - String itemUuid = ItemUtils.getItemUuid(stack); + String itemUuid = stack.getUuid(); //If the item has an uuid, then use the hash code of the uuid otherwise use the identity hash code of the stack int hashCode = itemUuid.isEmpty() ? System.identityHashCode(stack) : itemUuid.hashCode(); if (CACHE.containsKey(hashCode)) return CACHE.get(hashCode); - List<Text> lore = ItemUtils.getLore(stack); - String[] stringifiedTooltip = lore.stream().map(Text::getString).toArray(String[]::new); + //For regular items check the lore, for pets we use the rarity in the petInfo so that the rarity background work in the pets menu + if (!stack.getSkyblockId().equals("PET")) { + List<Text> lore = ItemUtils.getLore(stack); + String[] stringifiedTooltip = lore.stream().map(Text::getString).toArray(String[]::new); - for (String rarityString : LORE_RARITIES.keySet()) { - if (Arrays.stream(stringifiedTooltip).anyMatch(line -> line.contains(rarityString))) { - SkyblockItemRarity rarity = LORE_RARITIES.get(rarityString); + for (String rarityString : LORE_RARITIES.keySet()) { + if (Arrays.stream(stringifiedTooltip).anyMatch(line -> line.contains(rarityString))) { + SkyblockItemRarity rarity = LORE_RARITIES.get(rarityString); - CACHE.put(hashCode, rarity); - return rarity; + CACHE.put(hashCode, rarity); + return rarity; + } } + } else { + PetInfo info = stack.getPetInfo(); + SkyblockItemRarity rarity = info.rarity(); + + CACHE.put(hashCode, rarity); + return rarity; } CACHE.put(hashCode, null); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/PetInfo.java b/src/main/java/de/hysky/skyblocker/skyblock/item/PetInfo.java new file mode 100644 index 00000000..585db88a --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/PetInfo.java @@ -0,0 +1,30 @@ +package de.hysky.skyblocker.skyblock.item; + +import java.util.Optional; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; + +public record PetInfo(String type, double exp, String tier, Optional<String> uuid, Optional<String> item, Optional<String> skin) { + public static final Codec<PetInfo> CODEC = RecordCodecBuilder.create(instance -> instance.group( + Codec.STRING.fieldOf("type").forGetter(PetInfo::type), + Codec.DOUBLE.fieldOf("exp").forGetter(PetInfo::exp), + Codec.STRING.fieldOf("tier").forGetter(PetInfo::tier), + Codec.STRING.optionalFieldOf("uuid").forGetter(PetInfo::uuid), + Codec.STRING.optionalFieldOf("heldItem").forGetter(PetInfo::item), + Codec.STRING.optionalFieldOf("skin").forGetter(PetInfo::skin) + ).apply(instance, PetInfo::new)); + public static final PetInfo EMPTY = new PetInfo("", 0, "", Optional.empty(), Optional.empty(), Optional.empty()); + + public SkyblockItemRarity rarity() { + return SkyblockItemRarity.valueOf(tier); + } + + public int tierIndex() { + return rarity().ordinal(); + } + + public boolean isEmpty() { + return this == EMPTY; + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipManager.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipManager.java index a8b04f66..c1a994e6 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipManager.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipManager.java @@ -29,6 +29,8 @@ public class TooltipManager { new SupercraftReminder(), ChocolateFactorySolver.INSTANCE, new ReorderHelper(), + new SkyblockIdTooltip(-1), //Would be great if it was under the minecraft id but there is limitations here... + new StackingEnchantProgressTooltip(0), //Would be best to have after the lore but the tech doesn't exist for that new NpcPriceTooltip(1), new BazaarPriceTooltip(2), new LBinTooltip(3), diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/SkyblockIdTooltip.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/SkyblockIdTooltip.java new file mode 100644 index 00000000..cc4e1b77 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/SkyblockIdTooltip.java @@ -0,0 +1,33 @@ +package de.hysky.skyblocker.skyblock.item.tooltip.adders; + +import java.util.List; + +import org.jetbrains.annotations.Nullable; + +import de.hysky.skyblocker.skyblock.item.tooltip.SimpleTooltipAdder; +import net.minecraft.client.MinecraftClient; +import net.minecraft.item.ItemStack; +import net.minecraft.screen.slot.Slot; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; + +public class SkyblockIdTooltip extends SimpleTooltipAdder { + + public SkyblockIdTooltip(int priority) { + super(priority); + } + + @Override + public void addToTooltip(@Nullable Slot focusedSlot, ItemStack stack, List<Text> lines) { + String skyblockId = stack.getSkyblockId(); + + if (!skyblockId.isEmpty()) { + lines.add(Text.literal("Skyblock ID: " + skyblockId).formatted(Formatting.DARK_GRAY)); + } + } + + @Override + public boolean isEnabled() { + return MinecraftClient.getInstance().options.advancedItemTooltips; + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/StackingEnchantProgressTooltip.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/StackingEnchantProgressTooltip.java new file mode 100644 index 00000000..1dabafe8 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/StackingEnchantProgressTooltip.java @@ -0,0 +1,88 @@ +package de.hysky.skyblocker.skyblock.item.tooltip.adders; + +import java.text.NumberFormat; +import java.util.List; +import java.util.Locale; +import java.util.Set; + +import org.jetbrains.annotations.Nullable; + +import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.skyblock.item.tooltip.SimpleTooltipAdder; +import de.hysky.skyblocker.utils.ItemUtils; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtElement; +import net.minecraft.screen.slot.Slot; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; + +public class StackingEnchantProgressTooltip extends SimpleTooltipAdder { + private static final Set<String> STACKING_ENCHANT_IDS = Set.of("expertise", "compact", "cultivating", "champion", "hecatomb", "toxophilite"); + private static final StackingEnchantInfo EXPERTISE_INFO = new StackingEnchantInfo("Expertise", "expertise_kills", "kills", 0, 50, 100, 250, 500, 1000, 2500, 5500, 10_000, 15_000); + private static final StackingEnchantInfo COMPACT_INFO = new StackingEnchantInfo("Compact", "compact_blocks", "blocks", 0, 100, 500, 1500, 5000, 15_000, 50_000, 150_000, 500_000, 1_000_000); + private static final StackingEnchantInfo CULTIVATING_INFO = new StackingEnchantInfo("Cultivating", "farmed_cultivating", "crops", 0, 1000, 5000, 25_000, 100_000, 300_000, 1_500_000, 5_000_000, 20_000_000, 100_000_000); + private static final StackingEnchantInfo CHAMPION_INFO = new StackingEnchantInfo("Champion", "champion_combat_xp", "Combat XP", 0, 50_000, 100_000, 250_000, 500_000, 1_000_000, 1_500_000, 2_000_000, 2_500_000, 3_000_000); + private static final StackingEnchantInfo HECATOMB_INFO = new StackingEnchantInfo("Hecatomb", "hecatomb_s_runs", "S runs", 0, 2, 5, 10, 20, 30, 40, 60, 80, 100); + private static final StackingEnchantInfo TOXOPHILITE_INFO = new StackingEnchantInfo("Toxophilite", "toxophilite_combat_xp", "Combat XP", 0, 50_000, 100_000, 250_000, 500_000, 1_000_000, 1_500_000, 2_000_000, 2_500_000, 3_000_000); + private static final NumberFormat FORMAT = NumberFormat.getInstance(Locale.ENGLISH); + + public StackingEnchantProgressTooltip(int priority) { + super(priority); + } + + @Override + public void addToTooltip(@Nullable Slot focusedSlot, ItemStack stack, List<Text> lines) { + NbtCompound customData = ItemUtils.getCustomData(stack); + + if (customData.contains("enchantments", NbtElement.COMPOUND_TYPE)) { + NbtCompound enchantments = customData.getCompound("enchantments"); + StackingEnchantInfo stackingEnchantInfo = null; + int stackingEnchantLevel = 0; + + for (String enchantment : enchantments.getKeys()) { + if (STACKING_ENCHANT_IDS.contains(enchantment)) { + stackingEnchantInfo = switch (enchantment) { + case "expertise" -> EXPERTISE_INFO; + case "compact" -> COMPACT_INFO; + case "cultivating" -> CULTIVATING_INFO; + case "champion" -> CHAMPION_INFO; + case "hecatomb" -> HECATOMB_INFO; + case "toxophilite" -> TOXOPHILITE_INFO; + + default -> throw new IllegalStateException("Unexpected stacking enchant: " + enchantment); + }; + stackingEnchantLevel = enchantments.getInt(enchantment); + + break; + } + } + + if (stackingEnchantInfo != null && stackingEnchantLevel > 0 && stackingEnchantLevel < 10) { + int progress = customData.getInt(stackingEnchantInfo.field()); + int needed = stackingEnchantInfo.ladder()[stackingEnchantLevel]; + Text text = Text.empty() + .append(Text.literal(stackingEnchantInfo.name() + " ").formatted(Formatting.GRAY)) + .append(Text.translatable("enchantment.level." + (stackingEnchantLevel + 1)).formatted(Formatting.GRAY)) + .append(Text.literal(": ").formatted(Formatting.GRAY)) + .append(Text.literal(FORMAT.format(progress)).formatted(Formatting.RED)) + .append(Text.literal("/").formatted(Formatting.GRAY)) + .append(Text.literal(FORMAT.format(needed)).formatted(Formatting.RED)) + .append(Text.literal(" " + stackingEnchantInfo.unit()).formatted(Formatting.GRAY)); + + lines.add(text); + } + } + } + + @Override + public boolean isEnabled() { + return SkyblockerConfigManager.get().general.itemTooltip.enableStackingEnchantProgress; + } + + private record StackingEnchantInfo(String name, String field, String unit, int... ladder) { + StackingEnchantInfo { + if (ladder.length != 10) throw new IllegalStateException("Ladder must have 10 entries but had only " + ladder.length + "!"); + } + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/profileviewer/inventory/Pet.java b/src/main/java/de/hysky/skyblocker/skyblock/profileviewer/inventory/Pet.java index 53d4886f..db9b8240 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/profileviewer/inventory/Pet.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/profileviewer/inventory/Pet.java @@ -1,6 +1,6 @@ package de.hysky.skyblocker.skyblock.profileviewer.inventory; -import de.hysky.skyblocker.skyblock.PetCache; +import de.hysky.skyblocker.skyblock.item.PetInfo; import de.hysky.skyblocker.skyblock.itemlist.ItemFixerUpper; import de.hysky.skyblocker.skyblock.itemlist.ItemRepository; import de.hysky.skyblocker.skyblock.profileviewer.utils.LevelFinder; @@ -68,7 +68,7 @@ public class Pet { 6, Formatting.AQUA // DIVINE (future proofing, because why not) ))); - public Pet(PetCache.PetInfo petData) { + public Pet(PetInfo petData) { LevelFinder.LevelInfo info = LevelFinder.getLevelInfo(petData.type().equals("GOLDEN_DRAGON") ? "PET_GREG" : "PET_" + petData.tier(), (long) petData.exp()); this.name = petData.type(); this.xp = petData.exp(); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/profileviewer/inventory/itemLoaders/ItemLoader.java b/src/main/java/de/hysky/skyblocker/skyblock/profileviewer/inventory/itemLoaders/ItemLoader.java index fd4d3f4c..aa503e28 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/profileviewer/inventory/itemLoaders/ItemLoader.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/profileviewer/inventory/itemLoaders/ItemLoader.java @@ -4,7 +4,7 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.mojang.serialization.JsonOps; -import de.hysky.skyblocker.skyblock.PetCache; +import de.hysky.skyblocker.skyblock.item.PetInfo; import de.hysky.skyblocker.skyblock.profileviewer.ProfileViewerScreen; import de.hysky.skyblocker.skyblock.profileviewer.inventory.Pet; import de.hysky.skyblocker.skyblock.tabhud.util.Ico; @@ -47,7 +47,7 @@ public class ItemLoader { NbtCompound customData = ItemUtils.getCustomData(stack); if (itemId.equals("PET")) { - PetCache.PetInfo petInfo = PetCache.PetInfo.CODEC.parse(JsonOps.INSTANCE, JsonParser.parseString(customData.getString("petInfo"))).getOrThrow(); + PetInfo petInfo = PetInfo.CODEC.parse(JsonOps.INSTANCE, JsonParser.parseString(customData.getString("petInfo"))).getOrThrow(); Pet pet = new Pet(petInfo); itemList.add(pet.getIcon()); continue; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/profileviewer/inventory/itemLoaders/PetsInventoryItemLoader.java b/src/main/java/de/hysky/skyblocker/skyblock/profileviewer/inventory/itemLoaders/PetsInventoryItemLoader.java index cd3b7a26..8ac5831e 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/profileviewer/inventory/itemLoaders/PetsInventoryItemLoader.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/profileviewer/inventory/itemLoaders/PetsInventoryItemLoader.java @@ -3,7 +3,7 @@ package de.hysky.skyblocker.skyblock.profileviewer.inventory.itemLoaders; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.mojang.serialization.JsonOps; -import de.hysky.skyblocker.skyblock.PetCache; +import de.hysky.skyblocker.skyblock.item.PetInfo; import de.hysky.skyblocker.skyblock.profileviewer.ProfileViewerScreen; import de.hysky.skyblocker.skyblock.profileviewer.inventory.Pet; import net.minecraft.item.ItemStack; @@ -22,7 +22,7 @@ public class PetsInventoryItemLoader extends ItemLoader { JsonObject petsData = data.getAsJsonObject("pets_data"); if (petsData != null && petsData.has("pets")) { for (var petElement : petsData.get("pets").getAsJsonArray()) { - PetCache.PetInfo petInfo = PetCache.PetInfo.CODEC.parse(JsonOps.INSTANCE, JsonParser.parseString(petElement.toString())).getOrThrow(); + PetInfo petInfo = PetInfo.CODEC.parse(JsonOps.INSTANCE, JsonParser.parseString(petElement.toString())).getOrThrow(); petList.add(new Pet(petInfo)); } } diff --git a/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java b/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java index 94dc75aa..b886f40f 100644 --- a/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java +++ b/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java @@ -9,7 +9,7 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.JsonOps; import com.mojang.serialization.codecs.RecordCodecBuilder; import de.hysky.skyblocker.SkyblockerMod; -import de.hysky.skyblocker.skyblock.PetCache; +import de.hysky.skyblocker.skyblock.item.PetInfo; import de.hysky.skyblocker.skyblock.item.tooltip.adders.ObtainedDateTooltip; import de.hysky.skyblocker.skyblock.item.tooltip.info.TooltipInfoType; import de.hysky.skyblocker.utils.datafixer.ItemStackComponentizationFixer; @@ -154,7 +154,7 @@ public final class ItemUtils { } case "PET" -> { if (customData.contains("petInfo")) { - PetCache.PetInfo petInfo = PetCache.PetInfo.CODEC.parse(JsonOps.INSTANCE, JsonParser.parseString(customData.getString("petInfo"))).getOrThrow(); + PetInfo petInfo = PetInfo.CODEC.parse(JsonOps.INSTANCE, JsonParser.parseString(customData.getString("petInfo"))).getOrThrow(); return "LVL_1_" + petInfo.tier() + "_" + petInfo.type(); } } @@ -240,7 +240,7 @@ public final class ItemUtils { } case "PET" -> { if (!customData.contains("petInfo")) yield id; - PetCache.PetInfo petInfo = PetCache.PetInfo.CODEC.parse(JsonOps.INSTANCE, JsonParser.parseString(customData.getString("petInfo"))).getOrThrow(); + PetInfo petInfo = PetInfo.CODEC.parse(JsonOps.INSTANCE, JsonParser.parseString(customData.getString("petInfo"))).getOrThrow(); yield petInfo.type() + ';' + petInfo.tierIndex(); } case "RUNE" -> { @@ -258,6 +258,28 @@ public final class ItemUtils { } /** + * Parses the {@code petInfo} field from a pet item that has it into the {@link PetInfo} record. + * + * @return the parsed {@link PetInfo} if successful, or {@link PetInfo#EMPTY} + */ + @NotNull + public static PetInfo getPetInfo(ComponentHolder stack) { + if (!getItemId(stack).equals("PET")) return PetInfo.EMPTY; + + String petInfo = getCustomData(stack).getString("petInfo"); + + if (!petInfo.isEmpty()) { + try { + return PetInfo.CODEC.parse(JsonOps.INSTANCE, JsonParser.parseString(petInfo)) + .setPartial(PetInfo.EMPTY) + .getPartialOrThrow(); + } catch (Exception ignored) {} + } + + return PetInfo.EMPTY; + } + + /** |
