aboutsummaryrefslogtreecommitdiff
path: root/src/main/java
diff options
context:
space:
mode:
authorAaron <51387595+AzureAaron@users.noreply.github.com>2024-11-25 22:49:57 -0500
committerGitHub <noreply@github.com>2024-11-25 22:49:57 -0500
commit768919dc3021b5496d2c9d4dcf7a2a5c36260997 (patch)
tree06e3a14a3e7ee4b0e76c6079ae77b7de419da500 /src/main/java
parent8d986df7fc39dac8a39426e80b277cc731c8dcc0 (diff)
downloadSkyblocker-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')
-rw-r--r--src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java8
-rw-r--r--src/main/java/de/hysky/skyblocker/config/configs/GeneralConfig.java3
-rw-r--r--src/main/java/de/hysky/skyblocker/injected/SkyblockerStack.java12
-rw-r--r--src/main/java/de/hysky/skyblocker/mixins/ItemStackMixin.java34
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/PetCache.java61
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/StatusBarTracker.java3
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/ItemCooldowns.java1
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/ItemRarityBackgrounds.java25
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/PetInfo.java30
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipManager.java2
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/SkyblockIdTooltip.java33
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/StackingEnchantProgressTooltip.java88
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/profileviewer/inventory/Pet.java4
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/profileviewer/inventory/itemLoaders/ItemLoader.java4
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/profileviewer/inventory/itemLoaders/PetsInventoryItemLoader.java4
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/ItemUtils.java28
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;
+ }
+
+ /**