Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ private static OptionalDouble getPrice(Accessory acc) {
DoubleBooleanPair optionalPrice = ItemUtils.getItemPrice(stack);
double price;
if (optionalPrice.rightBoolean()) price = optionalPrice.firstDouble();
else price = ItemUtils.getCraftCost(stack.getSkyblockApiId());
else price = ItemUtils.getCraftCost(stack.getNeuName());
if (price <= 0) return OptionalDouble.empty();
return OptionalDouble.of(price);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,62 +10,71 @@
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;
import io.github.moulberry.repo.data.NEUKatUpgradeRecipe;
import io.github.moulberry.repo.data.NEUMobDropRecipe;
import io.github.moulberry.repo.data.NEURecipe;
import io.github.moulberry.repo.data.NEUTradeRecipe;
import it.unimi.dsi.fastutil.objects.Object2DoubleMap;
import it.unimi.dsi.fastutil.objects.Object2DoubleMaps;
import it.unimi.dsi.fastutil.objects.Object2DoubleOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
import org.jspecify.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Optional;
import java.util.Set;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.world.inventory.Slot;
import net.minecraft.world.item.ItemStack;

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 Map<String, Double> cachedCraftCosts = Object2DoubleMaps.synchronize(new Object2DoubleOpenHashMap<>());
private static final int MAX_RECURSION_DEPTH = 15;

public CraftPriceTooltip(int priority) {
super(priority);
}

@Override
public void addToTooltip(@Nullable Slot focusedSloFt, ItemStack stack, List<Component> lines) {
public void addToTooltip(@Nullable Slot focusedSlot, ItemStack stack, List<Component> lines) {
if (TooltipInfoType.LOWEST_BINS.getData() == null || TooltipInfoType.BAZAAR.getData() == null) {
ItemTooltip.nullWarning();
return;
}

NEUItem neuItem = NEURepoManager.getItemByNeuId(stack.getNeuName());
if (neuItem == null) return;

List<NEURecipe> neuRecipes = neuItem.getRecipes();
if (neuRecipes.isEmpty()) return;
NEURecipe recipe = neuRecipes.getFirst();

String itemId = stack.getNeuName();
try {
double totalCraftCost = getItemCost(recipe, 0);
if (totalCraftCost <= 0) return;
double craftPrice = cachedCraftCosts.computeIfAbsent(itemId, CraftPriceTooltip::getItemCost);
if (craftPrice <= 0) return;
int count = Math.max(ItemUtils.getItemCountInSack(stack, stack.skyblocker$getLoreStrings()).orElse(ItemUtils.getItemCountInStash(lines.getFirst()).orElse(stack.getCount())), 1);

recipe.getAllOutputs().stream().findFirst().ifPresent(outputIngredient ->
lines.add(Component.literal(String.format("%-20s", "Crafting Price:")).withStyle(ChatFormatting.GOLD)
.append(ItemTooltip.getCoinsMessage(totalCraftCost / outputIngredient.getAmount(), count))));
lines.add(Component.literal(String.format("%-20s", "Crafting Price:")).withStyle(ChatFormatting.GOLD)
.append(ItemTooltip.getCoinsMessage(craftPrice, count)));
} catch (Exception e) {
LOGGER.error("[Skyblocker Craft Price] Error calculating craftprice tooltip for: {}", stack.getNeuName(), e);
LOGGER.error("[Skyblocker Craft Price] Error calculating craft price for: {}", stack.getNeuName(), e);
}
}

public static double getItemCost(NEURecipe recipe, int depth) {
if (depth >= MAX_RECURSION_DEPTH || recipe instanceof NEUKatUpgradeRecipe || recipe instanceof NEUTradeRecipe) return -1;
public static double getItemCost(String neuId) {
return getItemCost(neuId, 0);
}

public static double getItemCost(String neuId, int depth) {
Set<NEURecipe> neuRecipes = NEURepoManager.getRecipes().get(neuId);
if (neuRecipes == null || neuRecipes.isEmpty()) return -1;

Optional<NEURecipe> recipe = neuRecipes.stream().filter(CraftPriceTooltip::isValidRecipe).findFirst();
if (recipe.isEmpty()) return -1;
return recipe.get().getAllOutputs().stream().filter(x -> x.getItemId().equals(neuId)).map(NEUIngredient::getAmount).findAny()
.map(amount -> getRecipeCost(recipe.get(), depth + 1) / amount).orElse(-1.0);
}

public static double getRecipeCost(NEURecipe recipe, int depth) {
if (depth >= MAX_RECURSION_DEPTH || !isValidRecipe(recipe)) return -1;

double totalCraftCost = 0;
for (NEUIngredient input : recipe.getAllInputs()) {
Expand All @@ -91,23 +100,26 @@ public static double getItemCost(NEURecipe recipe, int depth) {
cachedCraftCosts.put(inputItemName, itemCost);
}

NEUItem neuItem = NEURepoManager.getItemByNeuId(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);
}
double craftCost = getItemCost(inputItemName, depth + 1);
if (craftCost > 0) {
if (itemCost > 0) itemCost = Math.min(itemCost, craftCost);
else itemCost = craftCost;
cachedCraftCosts.put(inputItemName, itemCost);
}

totalCraftCost += itemCost * inputItemCount;
}
return totalCraftCost;
}

public static boolean isValidRecipe(NEURecipe recipe) {
return !(recipe instanceof NEUKatUpgradeRecipe || recipe instanceof NEUTradeRecipe || recipe instanceof NEUMobDropRecipe);
}

public static void clearCache() {
cachedCraftCosts.clear();
cachedCraftCosts.put(NEUIngredient.NEU_SENTINEL_COINS, 1d);
cachedCraftCosts.put(NEUIngredient.NEU_SENTINEL_EMPTY, 0d);
}

@Override
Expand Down
9 changes: 2 additions & 7 deletions src/main/java/de/hysky/skyblocker/utils/ItemUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import de.hysky.skyblocker.skyblock.item.tooltip.adders.ObtainedDateTooltip;
import de.hysky.skyblocker.skyblock.item.tooltip.info.TooltipInfoType;
import de.hysky.skyblocker.utils.networth.NetworthCalculator;
import io.github.moulberry.repo.data.NEUItem;
import it.unimi.dsi.fastutil.doubles.DoubleBooleanPair;
import it.unimi.dsi.fastutil.ints.IntIntPair;
import it.unimi.dsi.fastutil.longs.LongBooleanPair;
Expand Down Expand Up @@ -378,12 +377,8 @@ public static DoubleBooleanPair getItemPrice(@Nullable String skyblockApiId, boo
return DoubleBooleanPair.of(0, false);
}

public static double getCraftCost(String skyblockApiId) {
NEUItem neuItem = NEURepoManager.getItemByNeuId(skyblockApiId);
if (neuItem != null && !neuItem.getRecipes().isEmpty()) {
return CraftPriceTooltip.getItemCost(neuItem.getRecipes().getFirst(), 0);
}
return 0;
public static double getCraftCost(String neuId) {
return CraftPriceTooltip.getItemCost(neuId);
}

/**
Expand Down
Loading