aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/de
diff options
context:
space:
mode:
authorRime <81419447+Emirlol@users.noreply.github.com>2025-06-05 20:36:10 +0300
committerGitHub <noreply@github.com>2025-06-05 13:36:10 -0400
commit28802fb1db9e92fe0344b0063f6bd895f0db12e2 (patch)
treeeff23118a91f414367b924a2cde00232dd125133 /src/main/java/de
parent022b19558a4edf96f7832d08d5691b2da1a4588e (diff)
downloadSkyblocker-28802fb1db9e92fe0344b0063f6bd895f0db12e2.tar.gz
Skyblocker-28802fb1db9e92fe0344b0063f6bd895f0db12e2.tar.bz2
Skyblocker-28802fb1db9e92fe0344b0063f6bd895f0db12e2.zip
Fix npc price tooltip to include price * itemCount (#1301)
* Get rid of index magic * Clean up EstimatedItemValueTooltip --------- Co-authored-by: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com>
Diffstat (limited to 'src/main/java/de')
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java9
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/BazaarPriceTooltip.java36
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/CraftPriceTooltip.java178
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/EstimatedItemValueTooltip.java7
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/NpcPriceTooltip.java39
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/ItemUtils.java31
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/networth/NetworthCalculator.java7
7 files changed, 160 insertions, 147 deletions
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java
index fadff943..94ec29e6 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java
@@ -44,10 +44,19 @@ public class ItemTooltip {
}
}
+ /**
+ * Generates a formatted text message for displaying coin prices in tooltips, where the price is given per item.
+ * @param price the price of a single item
+ * @param count the number of items being priced
+ */
public static Text getCoinsMessage(double price, int count) {
return getCoinsMessage(price, count, false);
}
+ /**
+ * Generates a formatted text message for displaying coin prices in tooltips.
+ * @param preCounted Whether the count is already factored into the price. False if the price is per item, true if the price is the total price for the given count.
+ */
public static Text getCoinsMessage(double price, int count, boolean preCounted) {
// Format the price string once
String priceString = String.format(Locale.ENGLISH, "%1$,.1f", preCounted ? price / count : price);
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/BazaarPriceTooltip.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/BazaarPriceTooltip.java
index 4e1c0dc3..ec2f10cf 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/BazaarPriceTooltip.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/BazaarPriceTooltip.java
@@ -4,45 +4,41 @@ import de.hysky.skyblocker.skyblock.item.tooltip.ItemTooltip;
import de.hysky.skyblocker.skyblock.item.tooltip.SimpleTooltipAdder;
import de.hysky.skyblocker.skyblock.item.tooltip.info.TooltipInfoType;
import de.hysky.skyblocker.utils.BazaarProduct;
+import de.hysky.skyblocker.utils.ItemUtils;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.slot.Slot;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
-import org.apache.commons.lang3.math.NumberUtils;
import org.jetbrains.annotations.Nullable;
import java.util.List;
+import java.util.OptionalInt;
public class BazaarPriceTooltip extends SimpleTooltipAdder {
- public BazaarPriceTooltip(int priority) {
+ public BazaarPriceTooltip(int priority) {
super(priority);
}
@Override
public void addToTooltip(@Nullable Slot focusedSlot, ItemStack stack, List<Text> lines) {
- String skyblockApiId = stack.getSkyblockApiId();
+ String skyblockApiId = stack.getSkyblockApiId();
if (TooltipInfoType.BAZAAR.hasOrNullWarning(skyblockApiId)) {
- int count;
- if (lines.size() >= 4 && lines.get(3).getSiblings().size() >= 2 && lines.get(1).getString().endsWith("Sack")) {
- //The count is in the 2nd sibling of the 3rd line of the lore. here V
- //Example line: empty[style={color=dark_purple,!italic}, siblings=[literal{Stored: }[style={color=gray}], literal{0}[style={color=dark_gray}], literal{/20k}[style={color=gray}]]
- String line = lines.get(3).getSiblings().get(1).getString().replace(",", "");
- count = NumberUtils.isParsable(line) && !line.equals("0") ? Integer.parseInt(line) : stack.getCount();
- } else {
- count = stack.getCount();
- }
+ OptionalInt optCount = ItemUtils.getItemCountInSack(stack, lines);
+ // This clamp is here to ensure that the tooltip doesn't show a useless price of 0 coins if the item count is 0.
+ int count = optCount.isPresent() ? Math.max(optCount.getAsInt(), 1) : stack.getCount();
+
BazaarProduct product = TooltipInfoType.BAZAAR.getData().get(skyblockApiId);
lines.add(Text.literal(String.format("%-18s", "Bazaar buy Price:"))
- .formatted(Formatting.GOLD)
- .append(product.buyPrice().isEmpty()
- ? Text.literal("No data").formatted(Formatting.RED)
- : ItemTooltip.getCoinsMessage(product.buyPrice().getAsDouble(), count)));
+ .formatted(Formatting.GOLD)
+ .append(product.buyPrice().isEmpty()
+ ? Text.literal("No data").formatted(Formatting.RED)
+ : ItemTooltip.getCoinsMessage(product.buyPrice().getAsDouble(), count)));
lines.add(Text.literal(String.format("%-19s", "Bazaar sell Price:"))
- .formatted(Formatting.GOLD)
- .append(product.sellPrice().isEmpty()
- ? Text.literal("No data").formatted(Formatting.RED)
- : ItemTooltip.getCoinsMessage(product.sellPrice().getAsDouble(), count)));
+ .formatted(Formatting.GOLD)
+ .append(product.sellPrice().isEmpty()
+ ? Text.literal("No data").formatted(Formatting.RED)
+ : ItemTooltip.getCoinsMessage(product.sellPrice().getAsDouble(), count)));
}
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/CraftPriceTooltip.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/CraftPriceTooltip.java
index 943e855d..e42e76bb 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/CraftPriceTooltip.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/CraftPriceTooltip.java
@@ -7,6 +7,7 @@ import de.hysky.skyblocker.skyblock.item.tooltip.ItemTooltip;
import de.hysky.skyblocker.skyblock.item.tooltip.SimpleTooltipAdder;
import de.hysky.skyblocker.skyblock.item.tooltip.info.TooltipInfoType;
import de.hysky.skyblocker.utils.BazaarProduct;
+import de.hysky.skyblocker.utils.ItemUtils;
import de.hysky.skyblocker.utils.NEURepoManager;
import io.github.moulberry.repo.data.NEUIngredient;
import io.github.moulberry.repo.data.NEUItem;
@@ -16,103 +17,100 @@ import net.minecraft.item.ItemStack;
import net.minecraft.screen.slot.Slot;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
-import org.apache.commons.lang3.math.NumberUtils;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Map;
+import java.util.OptionalInt;
import java.util.concurrent.ConcurrentHashMap;
public class CraftPriceTooltip extends SimpleTooltipAdder {
- protected static final Logger LOGGER = LoggerFactory.getLogger(CraftPriceTooltip.class.getName());
- private static final Map<String, Double> cachedCraftCosts = new ConcurrentHashMap<>();
- private static final int MAX_RECURSION_DEPTH = 15;
-
- public CraftPriceTooltip(int priority) {
- super(priority);
- }
-
- @Override
- public void addToTooltip(@Nullable Slot focusedSloFt, ItemStack stack, List<Text> lines) {
- if (TooltipInfoType.LOWEST_BINS.getData() == null || TooltipInfoType.BAZAAR.getData() == null) {
- ItemTooltip.nullWarning();
- return;
- }
-
- NEUItem neuItem = NEURepoManager.NEU_REPO.getItems().getItemBySkyblockId(stack.getNeuName());
- if (neuItem == null) return;
-
- List<NEURecipe> neuRecipes = neuItem.getRecipes();
- if (neuRecipes.isEmpty() || neuRecipes.getFirst() instanceof NEUKatUpgradeRecipe) return;
-
- try {
- double totalCraftCost = getItemCost(neuRecipes.getFirst(), 0);
-
- if (totalCraftCost == 0) return;
-
- int amountInStack;
- if (lines.get(1).getString().endsWith("Sack")) {
- String line = lines.get(3).getSiblings().get(1).getString().replace(",", "");
- amountInStack = NumberUtils.isParsable(line) && !line.equals("0") ? Integer.parseInt(line) : stack.getCount();
- } else amountInStack = stack.getCount();
-
- neuRecipes.getFirst().getAllOutputs().stream().findFirst().ifPresent(outputIngredient ->
- lines.add(Text.literal(String.format("%-20s", "Crafting Price:")).formatted(Formatting.GOLD)
- .append(ItemTooltip.getCoinsMessage(totalCraftCost / outputIngredient.getAmount(), amountInStack))));
-
- } catch (Exception e) {
- LOGGER.error("[Skyblocker Craft Price] Error calculating craftprice tooltip for: " + stack.getNeuName(), e);
- }
- }
-
- private double getItemCost(NEURecipe recipe, int depth) {
- if (depth >= MAX_RECURSION_DEPTH) return -1;
-
- double totalCraftCost = 0;
- for (NEUIngredient input : recipe.getAllInputs()) {
- String inputItemName = input.getItemId();
- double inputItemCount = input.getAmount();
- if (cachedCraftCosts.containsKey(inputItemName)) {
- totalCraftCost += cachedCraftCosts.get(inputItemName) * inputItemCount;
- continue;
- }
-
- double itemCost = 0;
-
- if (TooltipInfoType.BAZAAR.getData().containsKey(inputItemName)) {
- BazaarProduct product = TooltipInfoType.BAZAAR.getData().get(inputItemName);
- itemCost = SkyblockerConfigManager.get().general.itemTooltip.enableCraftingCost == Craft.BUY_ORDER ? product.buyPrice().orElse(0d) : product.sellPrice().orElse(0d);
- } else if (TooltipInfoType.LOWEST_BINS.getData().containsKey(inputItemName)) {
- itemCost = TooltipInfoType.LOWEST_BINS.getData().getDouble(inputItemName);
- }
-
- if (itemCost > 0) {
- cachedCraftCosts.put(inputItemName, itemCost);
- }
-
- NEUItem neuItem = NEURepoManager.NEU_REPO.getItems().getItemBySkyblockId(inputItemName);
- if (neuItem != null) {
- List<NEURecipe> neuRecipes = neuItem.getRecipes();
- if (!neuRecipes.isEmpty()) {
- double craftCost = getItemCost(neuRecipes.getFirst(), depth + 1);
- if (craftCost != -1) itemCost = Math.min(itemCost, craftCost);
- cachedCraftCosts.put(inputItemName, itemCost);
- }
- }
-
- totalCraftCost += itemCost * inputItemCount;
- }
- return totalCraftCost;
- }
-
- public static void clearCache() {
- cachedCraftCosts.clear();
- }
-
- @Override
- public boolean isEnabled() {
- return SkyblockerConfigManager.get().general.itemTooltip.enableCraftingCost != GeneralConfig.Craft.OFF;
- }
+ protected static final Logger LOGGER = LoggerFactory.getLogger(CraftPriceTooltip.class.getName());
+ private static final Map<String, Double> cachedCraftCosts = new ConcurrentHashMap<>();
+ private static final int MAX_RECURSION_DEPTH = 15;
+
+ public CraftPriceTooltip(int priority) {
+ super(priority);
+ }
+
+ @Override
+ public void addToTooltip(@Nullable Slot focusedSloFt, ItemStack stack, List<Text> lines) {
+ if (TooltipInfoType.LOWEST_BINS.getData() == null || TooltipInfoType.BAZAAR.getData() == null) {
+ ItemTooltip.nullWarning();
+ return;
+ }
+
+ NEUItem neuItem = NEURepoManager.NEU_REPO.getItems().getItemBySkyblockId(stack.getNeuName());
+ if (neuItem == null) return;
+
+ List<NEURecipe> neuRecipes = neuItem.getRecipes();
+ if (neuRecipes.isEmpty() || neuRecipes.getFirst() instanceof NEUKatUpgradeRecipe) return;
+
+ try {
+ double totalCraftCost = getItemCost(neuRecipes.getFirst(), 0);
+
+ if (totalCraftCost == 0) return;
+
+ OptionalInt optCount = ItemUtils.getItemCountInSack(stack, lines);
+ // This clamp is here to ensure that the tooltip doesn't show a useless price of 0 coins if the item count is 0.
+ int count = optCount.isPresent() ? Math.max(optCount.getAsInt(), 1) : stack.getCount();
+
+ neuRecipes.getFirst().getAllOutputs().stream().findFirst().ifPresent(outputIngredient ->
+ lines.add(Text.literal(String.format("%-20s", "Crafting Price:")).formatted(Formatting.GOLD)
+ .append(ItemTooltip.getCoinsMessage(totalCraftCost / outputIngredient.getAmount(), count))));
+ } catch (Exception e) {
+ LOGGER.error("[Skyblocker Craft Price] Error calculating craftprice tooltip for: " + stack.getNeuName(), e);
+ }
+ }
+
+ private double getItemCost(NEURecipe recipe, int depth) {
+ if (depth >= MAX_RECURSION_DEPTH) return -1;
+
+ double totalCraftCost = 0;
+ for (NEUIngredient input : recipe.getAllInputs()) {
+ String inputItemName = input.getItemId();
+ double inputItemCount = input.getAmount();
+ if (cachedCraftCosts.containsKey(inputItemName)) {
+ totalCraftCost += cachedCraftCosts.get(inputItemName) * inputItemCount;
+ continue;
+ }
+
+ double itemCost = 0;
+
+ if (TooltipInfoType.BAZAAR.getData().containsKey(inputItemName)) {
+ BazaarProduct product = TooltipInfoType.BAZAAR.getData().get(inputItemName);
+ itemCost = SkyblockerConfigManager.get().general.itemTooltip.enableCraftingCost == Craft.BUY_ORDER ? product.buyPrice().orElse(0d) : product.sellPrice().orElse(0d);
+ } else if (TooltipInfoType.LOWEST_BINS.getData().containsKey(inputItemName)) {
+ itemCost = TooltipInfoType.LOWEST_BINS.getData().getDouble(inputItemName);
+ }
+
+ if (itemCost > 0) {
+ cachedCraftCosts.put(inputItemName, itemCost);
+ }
+
+ NEUItem neuItem = NEURepoManager.NEU_REPO.getItems().getItemBySkyblockId(inputItemName);
+ if (neuItem != null) {
+ List<NEURecipe> neuRecipes = neuItem.getRecipes();
+ if (!neuRecipes.isEmpty()) {
+ double craftCost = getItemCost(neuRecipes.getFirst(), depth + 1);
+ if (craftCost != -1) itemCost = Math.min(itemCost, craftCost);
+ cachedCraftCosts.put(inputItemName, itemCost);
+ }
+ }
+
+ totalCraftCost += itemCost * inputItemCount;
+ }
+ return totalCraftCost;
+ }
+
+ public static void clearCache() {
+ cachedCraftCosts.clear();
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return SkyblockerConfigManager.get().general.itemTooltip.enableCraftingCost != GeneralConfig.Craft.OFF;
+ }
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/EstimatedItemValueTooltip.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/EstimatedItemValueTooltip.java
index 3009fedb..a2509a82 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/EstimatedItemValueTooltip.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/EstimatedItemValueTooltip.java
@@ -7,6 +7,7 @@ import org.jetbrains.annotations.Nullable;
import de.hysky.skyblocker.skyblock.item.tooltip.ItemTooltip;
import de.hysky.skyblocker.skyblock.item.tooltip.SimpleTooltipAdder;
import de.hysky.skyblocker.skyblock.item.tooltip.info.TooltipInfoType;
+import de.hysky.skyblocker.utils.ItemUtils;
import de.hysky.skyblocker.utils.networth.NetworthCalculator;
import net.azureaaron.networth.NetworthResult;
import net.minecraft.item.ItemStack;
@@ -22,12 +23,14 @@ public class EstimatedItemValueTooltip extends SimpleTooltipAdder {
@Override
public void addToTooltip(@Nullable Slot focusedSlot, ItemStack stack, List<Text> lines) {
- NetworthResult result = NetworthCalculator.getItemNetworth(stack);
+ int count = Math.max(ItemUtils.getItemCountInSack(stack, lines).orElse(stack.getCount()), 1);
+
+ NetworthResult result = NetworthCalculator.getItemNetworth(stack, count);
if (result.price() > 0) {
lines.add(Text.literal(String.format("%-20s", "Est. Item Value:"))
.formatted(Formatting.GOLD)
- .append(ItemTooltip.getCoinsMessage(result.price(), stack.getCount(), true)));
+ .append(ItemTooltip.getCoinsMessage(result.price(), count, true)));
}
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/NpcPriceTooltip.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/NpcPriceTooltip.java
index 9b019531..13e2b213 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/NpcPriceTooltip.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/NpcPriceTooltip.java
@@ -1,30 +1,19 @@
package de.hysky.skyblocker.skyblock.item.tooltip.adders;
-import de.hysky.skyblocker.debug.Debug;
import de.hysky.skyblocker.skyblock.item.tooltip.ItemTooltip;
import de.hysky.skyblocker.skyblock.item.tooltip.SimpleTooltipAdder;
import de.hysky.skyblocker.skyblock.item.tooltip.info.TooltipInfoType;
-import de.hysky.skyblocker.utils.RegexUtils;
-import de.hysky.skyblocker.utils.TextUtils;
+import de.hysky.skyblocker.utils.ItemUtils;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.slot.Slot;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
-import net.minecraft.util.Util;
import org.jetbrains.annotations.Nullable;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.OptionalInt;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
public class NpcPriceTooltip extends SimpleTooltipAdder {
- private static final Pattern STORED_PATTERN = Pattern.compile("Stored: ([\\d,]+)/\\S+");
- private static final Logger LOGGER = LoggerFactory.getLogger(NpcPriceTooltip.class);
- private static final short LOG_INTERVAL = 1000;
- private static long lastLog = Util.getMeasuringTimeMs();
public NpcPriceTooltip(int priority) {
super(priority);
@@ -46,28 +35,12 @@ public class NpcPriceTooltip extends SimpleTooltipAdder {
double price = TooltipInfoType.NPC.getData().getOrDefault(internalID, -1); // The original default return value of 0 can be an actual price, so we use a value that can't be a price
if (price < 0) return;
- int amount = parseAmount(stack, lines);
+ OptionalInt optCount = ItemUtils.getItemCountInSack(stack, lines);
+ // This clamp is here to ensure that the tooltip doesn't show a useless price of 0 coins if the item count is 0.
+ int count = optCount.isPresent() ? Math.max(optCount.getAsInt(), 1) : stack.getCount();
+
lines.add(Text.literal(String.format("%-21s", "NPC Sell Price:"))
.formatted(Formatting.YELLOW)
- .append(ItemTooltip.getCoinsMessage(price, amount)));
- }
-
- private int parseAmount(ItemStack stack, List<Text> lines) {
- if (lines.size() >= 2 && lines.get(1).getString().endsWith("Sack")) {
- //Example line: empty[style={color=dark_purple,!italic}, siblings=[literal{Stored: }[style={color=gray}], literal{0}[style={color=dark_gray}], literal{/20k}[style={color=gray}]]
- Matcher matcher = TextUtils.matchInList(lines, STORED_PATTERN);
- if (matcher == null) {
- // Log a warning every second if the amount couldn't be found, to prevent spamming the logs every frame (which can be hundreds of times per second)
- if (Util.getMeasuringTimeMs() - lastLog > LOG_INTERVAL) {
- LOGGER.warn("Failed to find stored amount in sack tooltip for item `{}`", Debug.DumpFormat.JSON.format(stack).getString()); // This is a very unintended way of serializing the item stack, but it's so much cleaner than actually using the codec
- lastLog = Util.getMeasuringTimeMs();
- }
- return stack.getCount();
- } else {
- OptionalInt amount = RegexUtils.findIntFromMatcher(matcher);
- return amount.isPresent() ? amount.getAsInt() : stack.getCount();
- }
- }
- return stack.getCount();
+ .append(ItemTooltip.getCoinsMessage(price, count)));
}
}
diff --git a/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java b/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java
index 1988b8dc..56cec4c8 100644
--- a/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java
+++ b/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java
@@ -9,6 +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.debug.Debug;
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;
@@ -37,9 +38,12 @@ import net.minecraft.registry.Registries;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
+import net.minecraft.util.Util;
import net.minecraft.util.dynamic.Codecs;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.function.Predicate;
@@ -59,6 +63,10 @@ public final class ItemUtils {
Codec.INT.orElse(1).fieldOf("count").forGetter(ItemStack::getCount),
ComponentChanges.CODEC.optionalFieldOf("components", ComponentChanges.EMPTY).forGetter(ItemStack::getComponentChanges)
).apply(instance, ItemStack::new)));
+ private static final Logger LOGGER = LoggerFactory.getLogger(ItemUtils.class);
+ private static final Pattern STORED_PATTERN = Pattern.compile("Stored: ([\\d,]+)/\\S+");
+ private static final short LOG_INTERVAL = 1000;
+ private static long lastLog = Util.getMeasuringTimeMs();
private ItemUtils() {}
@@ -469,4 +477,27 @@ public final class ItemUtils {
.map(entity::getEquippedStack)
.toList();
}
+
+ /**
+ * Finds the number of items stored in a sack based on the tooltip lines.
+ * @param itemStack The item stack these lines belong to. This is used for logging purposes.
+ * @param lines The tooltip lines to search in. This isn't equivalent to the item's lore.
+ * @return An {@link OptionalInt} containing the number of items stored in the sack, or an empty {@link OptionalInt} if the item is not a sack or the amount could not be found.
+ */
+ public static OptionalInt getItemCountInSack(@NotNull ItemStack itemStack, @NotNull List<Text> lines) {
+ if (lines.size() >= 2 && lines.get(1).getString().endsWith("Sack")) {
+ // Example line: empty[style={color=dark_purple,!italic}, siblings=[literal{Stored: }[style={color=gray}], literal{0}[style={color=dark_gray}], literal{/20k}[style={color=gray}]]
+ // Which equals: `Stored: 0/20k`
+ Matcher matcher = TextUtils.matchInList(lines, STORED_PATTERN);
+ if (matcher == null) {
+ // Log a warning every second if the amount couldn't be found, to prevent spamming the logs every frame (which can be hundreds of times per second)
+ if (Util.getMeasuringTimeMs() - lastLog > LOG_INTERVAL) {
+ LOGGER.warn("Failed to find stored amount in sack tooltip for item `{}`", Debug.DumpFormat.JSON.format(itemStack).getString()); // This is a very unintended way of serializing the item stack, but it's so much cleaner than actually using the codec
+ lastLog = Util.getMeasuringTimeMs();
+ }
+ return OptionalInt.empty();
+ } else return RegexUtils.parseOptionalIntFromMatcher(matcher, 1);
+ }
+ return OptionalInt.empty();
+ }
}
diff --git a/src/main/java/de/hysky/skyblocker/utils/networth/NetworthCalculator.java b/src/main/java/de/hysky/skyblocker/utils/networth/NetworthCalculator.java
index 2b4094e0..da35f62d 100644
--- a/src/main/java/de/hysky/skyblocker/utils/networth/NetworthCalculator.java
+++ b/src/main/java/de/hysky/skyblocker/utils/networth/NetworthCalculator.java
@@ -14,12 +14,15 @@ import net.minecraft.nbt.NbtElement;
import net.minecraft.nbt.NbtOps;
public class NetworthCalculator {
-
public static NetworthResult getItemNetworth(ItemStack stack) {
+ return getItemNetworth(stack, stack.getCount());
+ }
+
+ public static NetworthResult getItemNetworth(ItemStack stack, int count) {
String itemId = ItemUtils.getItemId(stack);
NbtCompound customData = stack.getOrDefault(DataComponentTypes.CUSTOM_DATA, NbtComponent.DEFAULT).copyNbt();
Dynamic<NbtElement> customDataDynamic = new Dynamic<>(NbtOps.INSTANCE, customData);
- SkyblockItemStack skyblockItemStack = SkyblockItemStack.of(itemId, stack.getCount(), customDataDynamic, SkyblockItemMetadataRetriever.of(customData, itemId));
+ SkyblockItemStack skyblockItemStack = SkyblockItemStack.of(itemId, count, customDataDynamic, SkyblockItemMetadataRetriever.of(customData, itemId));
return ItemCalculator.calculate(skyblockItemStack, NetworthDataSuppliers::getPrice, NetworthDataSuppliers.getSkyblockItemData());
}