From 99d2249714207ce99019db30a6c0251b59cfc326 Mon Sep 17 00:00:00 2001 From: Aaron <51387595+AzureAaron@users.noreply.github.com> Date: Sat, 24 Aug 2024 04:23:24 -0400 Subject: Tooltip Info Rework + Performance improvements --- .../skyblock/auction/AuctionBrowserScreen.java | 9 +- .../skyblocker/skyblock/bazaar/BazaarHelper.java | 2 +- .../skyblock/garden/FarmingHudWidget.java | 4 +- .../skyblock/item/tooltip/AccessoriesHelper.java | 14 +- .../skyblock/item/tooltip/ItemTooltip.java | 1 + .../skyblock/item/tooltip/TooltipInfoType.java | 165 --------------------- .../item/tooltip/adders/AccessoryTooltip.java | 2 +- .../item/tooltip/adders/AvgBinTooltip.java | 10 +- .../item/tooltip/adders/BazaarPriceTooltip.java | 14 +- .../skyblock/item/tooltip/adders/ColorTooltip.java | 9 +- .../item/tooltip/adders/CraftPriceTooltip.java | 16 +- .../item/tooltip/adders/EssenceShopPrice.java | 21 +-- .../tooltip/adders/EstimatedItemValueTooltip.java | 2 +- .../skyblock/item/tooltip/adders/LBinTooltip.java | 4 +- .../skyblock/item/tooltip/adders/MotesTooltip.java | 4 +- .../item/tooltip/adders/MuseumTooltip.java | 4 +- .../item/tooltip/adders/NpcPriceTooltip.java | 4 +- .../item/tooltip/adders/ObtainedDateTooltip.java | 2 +- .../item/tooltip/info/DataTooltipInfo.java | 97 ++++++++++++ .../item/tooltip/info/DataTooltipInfoType.java | 54 +++++++ .../item/tooltip/info/SimpleTooltipInfo.java | 19 +++ .../item/tooltip/info/TooltipInfoType.java | 59 ++++++++ .../skyblock/searchoverlay/SearchOverManager.java | 77 +++++----- .../de/hysky/skyblocker/utils/BazaarProduct.java | 19 +++ .../java/de/hysky/skyblocker/utils/CodecUtils.java | 18 +++ .../java/de/hysky/skyblocker/utils/ItemUtils.java | 24 +-- 26 files changed, 376 insertions(+), 278 deletions(-) delete mode 100644 src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipInfoType.java create mode 100644 src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/info/DataTooltipInfo.java create mode 100644 src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/info/DataTooltipInfoType.java create mode 100644 src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/info/SimpleTooltipInfo.java create mode 100644 src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/info/TooltipInfoType.java create mode 100644 src/main/java/de/hysky/skyblocker/utils/BazaarProduct.java (limited to 'src/main/java/de') diff --git a/src/main/java/de/hysky/skyblocker/skyblock/auction/AuctionBrowserScreen.java b/src/main/java/de/hysky/skyblocker/skyblock/auction/AuctionBrowserScreen.java index ecffab3e..eb0fa9b1 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/auction/AuctionBrowserScreen.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/auction/AuctionBrowserScreen.java @@ -7,7 +7,7 @@ import de.hysky.skyblocker.skyblock.auction.widgets.AuctionTypeWidget; import de.hysky.skyblocker.skyblock.auction.widgets.CategoryTabWidget; import de.hysky.skyblocker.skyblock.auction.widgets.RarityWidget; import de.hysky.skyblocker.skyblock.auction.widgets.SortWidget; -import de.hysky.skyblocker.skyblock.item.tooltip.TooltipInfoType; +import de.hysky.skyblocker.skyblock.item.tooltip.info.TooltipInfoType; import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.render.gui.AbstractCustomHypixelGUI; import it.unimi.dsi.fastutil.ints.Int2BooleanOpenHashMap; @@ -294,11 +294,8 @@ public class AuctionBrowserScreen extends AbstractCustomHypixelGUI parsed); - } + double price = TooltipInfoType.THREE_DAY_AVERAGE.getData().getDouble(stack.getNeuName()); + isSlotHighlighted.put(slotId, price > parsed); } catch (Exception e) { LOGGER.error("[Skyblocker Fancy Auction House] Failed to parse BIN price", e); } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/bazaar/BazaarHelper.java b/src/main/java/de/hysky/skyblocker/skyblock/bazaar/BazaarHelper.java index 842bbff9..9b8c5a2c 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/bazaar/BazaarHelper.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/bazaar/BazaarHelper.java @@ -4,7 +4,7 @@ import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.skyblock.item.slottext.SimpleSlotTextAdder; import de.hysky.skyblocker.skyblock.item.slottext.SlotText; import de.hysky.skyblocker.skyblock.item.tooltip.ItemTooltip; -import de.hysky.skyblocker.skyblock.item.tooltip.TooltipInfoType; +import de.hysky.skyblocker.skyblock.item.tooltip.info.TooltipInfoType; import de.hysky.skyblocker.skyblock.itemlist.ItemRepository; import de.hysky.skyblocker.utils.Constants; import de.hysky.skyblocker.utils.ItemUtils; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/garden/FarmingHudWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/garden/FarmingHudWidget.java index 51b52d6b..954c9f27 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/garden/FarmingHudWidget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/garden/FarmingHudWidget.java @@ -1,7 +1,7 @@ package de.hysky.skyblocker.skyblock.garden; import de.hysky.skyblocker.config.SkyblockerConfigManager; -import de.hysky.skyblocker.skyblock.item.tooltip.TooltipInfoType; +import de.hysky.skyblocker.skyblock.item.tooltip.info.TooltipInfoType; import de.hysky.skyblocker.skyblock.itemlist.ItemRepository; import de.hysky.skyblocker.skyblock.tabhud.util.Ico; import de.hysky.skyblocker.skyblock.tabhud.widget.Widget; @@ -93,7 +93,7 @@ public class FarmingHudWidget extends Widget { */ private String getPriceText(String cropItemId, float cropsPerMinute) { DoubleBooleanPair itemBazaarPrice = ItemUtils.getItemPrice(cropItemId); // Gets the bazaar sell price of the crop. - double itemNpcPrice = TooltipInfoType.NPC.hasOrNullWarning(cropItemId) ? TooltipInfoType.NPC.getData().get(cropItemId).getAsDouble() : Double.MIN_VALUE; // Gets the npc sell price of the crop or set to the min double value if it doesn't exist. + double itemNpcPrice = TooltipInfoType.NPC.hasOrNullWarning(cropItemId) ? TooltipInfoType.NPC.getData().getDouble(cropItemId) : Double.MIN_VALUE; // Gets the npc sell price of the crop or set to the min double value if it doesn't exist. boolean shouldUseNpcPrice = itemNpcPrice > itemBazaarPrice.leftDouble(); // Use the npc price if it's more than the bazaar sell price. double price = shouldUseNpcPrice ? itemNpcPrice : itemBazaarPrice.leftDouble(); // same as above diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/AccessoriesHelper.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/AccessoriesHelper.java index 992206ad..8c9190ca 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/AccessoriesHelper.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/AccessoriesHelper.java @@ -1,6 +1,5 @@ package de.hysky.skyblocker.skyblock.item.tooltip; -import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.mojang.logging.LogUtils; import com.mojang.serialization.Codec; @@ -8,6 +7,7 @@ import com.mojang.serialization.JsonOps; import com.mojang.serialization.codecs.RecordCodecBuilder; import com.mojang.util.UndashedUuid; import de.hysky.skyblocker.SkyblockerMod; +import de.hysky.skyblocker.skyblock.item.tooltip.info.TooltipInfoType; import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.Utils; import it.unimi.dsi.fastutil.Pair; @@ -165,12 +165,8 @@ public class AccessoriesHelper { return Pair.of(AccessoryReport.MISSING, String.format("(%d/%d)", accessory.tier(), highestTierInFamily)); } - static void refreshData(JsonObject data) { - try { - ACCESSORY_DATA = Accessory.MAP_CODEC.parse(JsonOps.INSTANCE, data).getOrThrow(); - } catch (Exception e) { - LOGGER.error("[Skyblocker Accessory Helper] Failed to parse data!", e); - } + public static void refreshData(Map data) { + ACCESSORY_DATA = data; } private record ProfileAccessoryData(Int2ObjectOpenHashMap> pages) { @@ -191,13 +187,13 @@ public class AccessoriesHelper { * @author AzureAaron * @implSpec Aaron's Mod */ - private record Accessory(String id, Optional family, int tier) { + public record Accessory(String id, Optional family, int tier) { private static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( Codec.STRING.fieldOf("id").forGetter(Accessory::id), Codec.STRING.optionalFieldOf("family").forGetter(Accessory::family), Codec.INT.optionalFieldOf("tier", 0).forGetter(Accessory::tier) ).apply(instance, Accessory::new)); - private static final Codec> MAP_CODEC = Codec.unboundedMap(Codec.STRING, CODEC); + public static final Codec> MAP_CODEC = Codec.unboundedMap(Codec.STRING, CODEC); private boolean hasFamily() { return family.isPresent(); 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 60a03118..5728bdae 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 @@ -3,6 +3,7 @@ package de.hysky.skyblocker.skyblock.item.tooltip; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.config.configs.GeneralConfig; import de.hysky.skyblocker.skyblock.item.tooltip.adders.CraftPriceTooltip; +import de.hysky.skyblocker.skyblock.item.tooltip.info.TooltipInfoType; import de.hysky.skyblocker.utils.Constants; import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.Utils; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipInfoType.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipInfoType.java deleted file mode 100644 index 04d0d81c..00000000 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipInfoType.java +++ /dev/null @@ -1,165 +0,0 @@ -package de.hysky.skyblocker.skyblock.item.tooltip; - -import com.google.gson.JsonObject; -import de.hysky.skyblocker.SkyblockerMod; -import de.hysky.skyblocker.config.SkyblockerConfigManager; -import de.hysky.skyblocker.config.configs.GeneralConfig; -import de.hysky.skyblocker.skyblock.item.tooltip.adders.EssenceShopPrice; -import de.hysky.skyblocker.utils.Http; -import de.hysky.skyblocker.utils.Utils; -import org.jetbrains.annotations.Nullable; - -import java.net.http.HttpHeaders; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.function.Consumer; -import java.util.function.Predicate; - -public enum TooltipInfoType implements Runnable { - NPC("https://hysky.de/api/npcprice", itemTooltip -> itemTooltip.enableNPCPrice, true), - BAZAAR("https://hysky.de/api/bazaar", itemTooltip -> itemTooltip.enableBazaarPrice || itemTooltip.enableCraftingCost.getOrder() != null || itemTooltip.enableEstimatedItemValue || SkyblockerConfigManager.get().dungeons.dungeonChestProfit.enableProfitCalculator || SkyblockerConfigManager.get().dungeons.dungeonChestProfit.croesusProfit || SkyblockerConfigManager.get().uiAndVisuals.chestValue.enableChestValue || itemTooltip.showEssenceCost, itemTooltip -> itemTooltip.enableBazaarPrice, false, EssenceShopPrice::refreshEssencePrices), - LOWEST_BINS("https://hysky.de/api/auctions/lowestbins", itemTooltip -> itemTooltip.enableLowestBIN || itemTooltip.enableCraftingCost.getOrder() != null || itemTooltip.enableEstimatedItemValue || SkyblockerConfigManager.get().dungeons.dungeonChestProfit.enableProfitCalculator || SkyblockerConfigManager.get().dungeons.dungeonChestProfit.croesusProfit || SkyblockerConfigManager.get().uiAndVisuals.chestValue.enableChestValue, itemTooltip -> itemTooltip.enableLowestBIN, false), - ONE_DAY_AVERAGE("https://hysky.de/api/auctions/lowestbins/average/1day.json", itemTooltip -> itemTooltip.enableAvgBIN, false), - THREE_DAY_AVERAGE("https://hysky.de/api/auctions/lowestbins/average/3day.json", itemTooltip -> itemTooltip.enableAvgBIN || SkyblockerConfigManager.get().uiAndVisuals.searchOverlay.enableAuctionHouse, itemTooltip -> itemTooltip.enableAvgBIN, false), - MOTES("https://hysky.de/api/motesprice", itemTooltip -> itemTooltip.enableMotesPrice, itemTooltip -> itemTooltip.enableMotesPrice && Utils.isInTheRift(), true), - OBTAINED(itemTooltip -> itemTooltip.enableObtainedDate), - MUSEUM("https://hysky.de/api/museum", itemTooltip -> itemTooltip.enableMuseumInfo, true), - COLOR("https://hysky.de/api/color", itemTooltip -> itemTooltip.enableExoticTooltip, true), - ACCESSORIES("https://hysky.de/api/accessories", itemTooltip -> itemTooltip.enableAccessoriesHelper, true, AccessoriesHelper::refreshData), - ESTIMATED_ITEM_VALUE(itemTooltip -> itemTooltip.enableEstimatedItemValue); - - private final String address; - private final Predicate dataEnabled; - private final Predicate tooltipEnabled; - private @Nullable JsonObject data; - private final boolean cacheable; - private long hash; - private final @Nullable Consumer callback; - - /** - * Use this for when you're adding tooltip info that has no data associated with it - */ - TooltipInfoType(Predicate enabled) { - this(null, itemTooltip -> false, enabled, false, null); - } - - /** - * @param address the address to download the data from - * @param enabled the predicate to check if the data should be downloaded and the tooltip should be shown - * @param cacheable whether the data should be cached - */ - TooltipInfoType(String address, Predicate enabled, boolean cacheable) { - this(address, enabled, enabled, cacheable, null); - } - - /** - * @param address the address to download the data from - * @param enabled the predicate to check if the data should be downloaded and the tooltip should be shown - * @param cacheable whether the data should be cached - * @param callback called when the {@code data} is refreshed - */ - TooltipInfoType(String address, Predicate enabled, boolean cacheable, Consumer callback) { - this(address, enabled, enabled, cacheable, callback); - } - - /** - * @param address the address to download the data from - * @param dataEnabled the predicate to check if data should be downloaded - * @param tooltipEnabled the predicate to check if the tooltip should be shown - * @param cacheable whether the data should be cached - */ - TooltipInfoType(String address, Predicate dataEnabled, Predicate tooltipEnabled, boolean cacheable) { - this(address, dataEnabled, tooltipEnabled, cacheable, null); - } - - /** - * @param address the address to download the data from - * @param dataEnabled the predicate to check if data should be downloaded - * @param tooltipEnabled the predicate to check if the tooltip should be shown - * @param cacheable whether the data should be cached - */ - TooltipInfoType(String address, Predicate dataEnabled, Predicate tooltipEnabled, boolean cacheable, @Nullable Consumer callback) { - this.address = address; - this.dataEnabled = dataEnabled; - this.tooltipEnabled = tooltipEnabled; - this.data = null; - this.cacheable = cacheable; - this.callback = callback; - } - - /** - * @return whether the data should be downloaded - */ - private boolean isDataEnabled() { - return dataEnabled.test(ItemTooltip.config); - } - - /** - * @return whether the tooltip should be shown - */ - public boolean isTooltipEnabled() { - return tooltipEnabled.test(ItemTooltip.config); - } - - public @Nullable JsonObject getData() { - return data; - } - - /** - * Checks if the data has the given member name and sends a warning message if data is null. - * - * @param memberName the member name to check - * @return whether the data has the given member name or not - */ - public boolean hasOrNullWarning(String memberName) { - if (data == null) { - ItemTooltip.nullWarning(); - return false; - } else return data.has(memberName); - } - - /** - * Downloads the data if it is enabled. - * - * @param futureList the list to add the future to - */ - public void downloadIfEnabled(List> futureList) { - if (isDataEnabled()) { - download(futureList); - } - } - - /** - * Downloads the data. - * - * @param futureList the list to add the future to - */ - public void download(List> futureList) { - futureList.add(CompletableFuture.runAsync(this)); - } - - /** - * Downloads the data. - */ - @Override - public void run() { - try { - if (cacheable) { - HttpHeaders headers = Http.sendHeadRequest(address); - long hash = Http.getEtag(headers).hashCode() + Http.getLastModified(headers).hashCode(); - if (this.hash == hash) return; - else this.hash = hash; - } - String response = Http.sendGetRequest(address); - if (response.trim().startsWith(" neuRecipes = neuItem.getRecipes(); - if (neuRecipes.isEmpty() || neuRecipes.getFirst() instanceof io.github.moulberry.repo.data.NEUKatUpgradeRecipe) return; + if (neuRecipes.isEmpty() || neuRecipes.getFirst() instanceof NEUKatUpgradeRecipe) return; try { double totalCraftCost = getItemCost(neuRecipes.getFirst(), 0); @@ -78,10 +81,11 @@ public class CraftPriceTooltip extends SimpleTooltipAdder { double itemCost = 0; - if (TooltipInfoType.BAZAAR.getData().has(inputItemName)) { - itemCost = TooltipInfoType.BAZAAR.getData().getAsJsonObject(inputItemName).get(SkyblockerConfigManager.get().general.itemTooltip.enableCraftingCost.getOrder()).getAsDouble(); - } else if (TooltipInfoType.LOWEST_BINS.getData().has(inputItemName)) { - itemCost = TooltipInfoType.LOWEST_BINS.getData().get(inputItemName).getAsDouble(); + 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) { diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/EssenceShopPrice.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/EssenceShopPrice.java index bc478d50..240a30ed 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/EssenceShopPrice.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/EssenceShopPrice.java @@ -1,12 +1,12 @@ package de.hysky.skyblocker.skyblock.item.tooltip.adders; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.skyblock.item.tooltip.SimpleTooltipAdder; +import de.hysky.skyblocker.utils.BazaarProduct; import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.RegexUtils; import it.unimi.dsi.fastutil.objects.Object2LongArrayMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import net.minecraft.item.ItemStack; import net.minecraft.screen.slot.Slot; import net.minecraft.text.Text; @@ -16,6 +16,7 @@ import org.jetbrains.annotations.Nullable; import java.text.NumberFormat; import java.util.List; import java.util.Locale; +import java.util.OptionalDouble; import java.util.OptionalLong; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -30,14 +31,16 @@ public class EssenceShopPrice extends SimpleTooltipAdder { super("\\S+ Essence Shop", priority); } - public static void refreshEssencePrices(JsonObject data) { + public static void refreshEssencePrices(Object2ObjectMap data) { for (String essenceType : ESSENCE_TYPES) { - JsonElement price = data.get("ESSENCE_" + essenceType); - if (price == null || !price.isJsonObject()) continue; - JsonElement sellPrice = price.getAsJsonObject().get("sellPrice"); - if (sellPrice == null) continue; - if (sellPrice.isJsonPrimitive()) { - ESSENCE_PRICES.put(essenceType, sellPrice.getAsLong()); + BazaarProduct product = data.get("ESSENCE_" + essenceType); + + if (product != null) { + OptionalDouble sellPrice = product.sellPrice(); + + if (sellPrice.isPresent()) { + ESSENCE_PRICES.put(essenceType, (long) sellPrice.getAsDouble()); + } } } } 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 cd2c587a..3009fedb 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 @@ -6,7 +6,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.TooltipInfoType; +import de.hysky.skyblocker.skyblock.item.tooltip.info.TooltipInfoType; import de.hysky.skyblocker.utils.networth.NetworthCalculator; import net.azureaaron.networth.NetworthResult; import net.minecraft.item.ItemStack; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/LBinTooltip.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/LBinTooltip.java index 2f9e143a..3838974a 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/LBinTooltip.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/LBinTooltip.java @@ -2,7 +2,7 @@ package de.hysky.skyblocker.skyblock.item.tooltip.adders; import de.hysky.skyblocker.skyblock.item.tooltip.ItemTooltip; import de.hysky.skyblocker.skyblock.item.tooltip.SimpleTooltipAdder; -import de.hysky.skyblocker.skyblock.item.tooltip.TooltipInfoType; +import de.hysky.skyblocker.skyblock.item.tooltip.info.TooltipInfoType; import net.minecraft.item.ItemStack; import net.minecraft.screen.slot.Slot; import net.minecraft.text.Text; @@ -32,7 +32,7 @@ public class LBinTooltip extends SimpleTooltipAdder { if (TooltipInfoType.LOWEST_BINS.hasOrNullWarning(skyblockApiId) && !BazaarPriceTooltip.bazaarExist) { lines.add(Text.literal(String.format("%-19s", "Lowest BIN Price:")) .formatted(Formatting.GOLD) - .append(ItemTooltip.getCoinsMessage(TooltipInfoType.LOWEST_BINS.getData().get(skyblockApiId).getAsDouble(), stack.getCount()))); + .append(ItemTooltip.getCoinsMessage(TooltipInfoType.LOWEST_BINS.getData().getDouble(skyblockApiId), stack.getCount()))); lbinExist = true; } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/MotesTooltip.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/MotesTooltip.java index 4efc443d..18d50fe8 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/MotesTooltip.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/MotesTooltip.java @@ -2,7 +2,7 @@ package de.hysky.skyblocker.skyblock.item.tooltip.adders; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.skyblock.item.tooltip.SimpleTooltipAdder; -import de.hysky.skyblocker.skyblock.item.tooltip.TooltipInfoType; +import de.hysky.skyblocker.skyblock.item.tooltip.info.TooltipInfoType; import net.minecraft.item.ItemStack; import net.minecraft.screen.slot.Slot; import net.minecraft.text.MutableText; @@ -24,7 +24,7 @@ public class MotesTooltip extends SimpleTooltipAdder { if (TooltipInfoType.MOTES.hasOrNullWarning(internalID)) { lines.add(Text.literal(String.format("%-20s", "Motes Price:")) .formatted(Formatting.LIGHT_PURPLE) - .append(getMotesMessage(TooltipInfoType.MOTES.getData().get(internalID).getAsInt(), stack.getCount()))); + .append(getMotesMessage(TooltipInfoType.MOTES.getData().getInt(internalID), stack.getCount()))); } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/MuseumTooltip.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/MuseumTooltip.java index 6a53dbdb..c4bf96c7 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/MuseumTooltip.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/MuseumTooltip.java @@ -2,7 +2,7 @@ package de.hysky.skyblocker.skyblock.item.tooltip.adders; import de.hysky.skyblocker.skyblock.item.MuseumItemCache; import de.hysky.skyblocker.skyblock.item.tooltip.SimpleTooltipAdder; -import de.hysky.skyblocker.skyblock.item.tooltip.TooltipInfoType; +import de.hysky.skyblocker.skyblock.item.tooltip.info.TooltipInfoType; import de.hysky.skyblocker.utils.ItemUtils; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NbtCompound; @@ -27,7 +27,7 @@ public class MuseumTooltip extends SimpleTooltipAdder { public void addToTooltip(@Nullable Slot focusedSlot, ItemStack stack, List lines) { final String internalID = stack.getSkyblockId(); if (TooltipInfoType.MUSEUM.hasOrNullWarning(internalID)) { - String itemCategory = TooltipInfoType.MUSEUM.getData().get(internalID).getAsString(); + String itemCategory = TooltipInfoType.MUSEUM.getData().get(internalID); String format = switch (itemCategory) { case "Weapons" -> "%-18s"; case "Armor" -> "%-19s"; 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 2801cfdc..6bb1bcdb 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 @@ -2,7 +2,7 @@ package de.hysky.skyblocker.skyblock.item.tooltip.adders; import de.hysky.skyblocker.skyblock.item.tooltip.ItemTooltip; import de.hysky.skyblocker.skyblock.item.tooltip.SimpleTooltipAdder; -import de.hysky.skyblocker.skyblock.item.tooltip.TooltipInfoType; +import de.hysky.skyblocker.skyblock.item.tooltip.info.TooltipInfoType; import net.minecraft.item.ItemStack; import net.minecraft.screen.slot.Slot; import net.minecraft.text.Text; @@ -38,7 +38,7 @@ public class NpcPriceTooltip extends SimpleTooltipAdder { } lines.add(Text.literal(String.format("%-21s", "NPC Sell Price:")) .formatted(Formatting.YELLOW) - .append(ItemTooltip.getCoinsMessage(TooltipInfoType.NPC.getData().get(internalID).getAsDouble(), amount))); + .append(ItemTooltip.getCoinsMessage(TooltipInfoType.NPC.getData().getDouble(internalID), amount))); } } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/ObtainedDateTooltip.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/ObtainedDateTooltip.java index 1cbff9d8..2071547c 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/ObtainedDateTooltip.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/ObtainedDateTooltip.java @@ -1,7 +1,7 @@ package de.hysky.skyblocker.skyblock.item.tooltip.adders; import de.hysky.skyblocker.skyblock.item.tooltip.SimpleTooltipAdder; -import de.hysky.skyblocker.skyblock.item.tooltip.TooltipInfoType; +import de.hysky.skyblocker.skyblock.item.tooltip.info.TooltipInfoType; import de.hysky.skyblocker.utils.ItemUtils; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NbtCompound; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/info/DataTooltipInfo.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/info/DataTooltipInfo.java new file mode 100644 index 00000000..ce18f438 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/info/DataTooltipInfo.java @@ -0,0 +1,97 @@ +package de.hysky.skyblocker.skyblock.item.tooltip.info; + +import java.net.http.HttpHeaders; +import java.util.function.BiPredicate; +import java.util.function.Consumer; +import java.util.function.Predicate; + +import org.jetbrains.annotations.Nullable; + +import com.google.gson.JsonParser; +import com.mojang.serialization.Codec; +import com.mojang.serialization.JsonOps; + +import de.hysky.skyblocker.config.configs.GeneralConfig; +import de.hysky.skyblocker.skyblock.item.tooltip.ItemTooltip; +import de.hysky.skyblocker.utils.Http; + +public final class DataTooltipInfo extends SimpleTooltipInfo implements DataTooltipInfoType { + private final Predicate dataEnabled; + private final String address; + private final Codec codec; + @Nullable + private T data; + private final boolean cacheable; + private long hash; + private final BiPredicate contains; + @Nullable + private final Consumer[] callbacks; + + @SafeVarargs + protected DataTooltipInfo(Predicate tooltipEnabled, Predicate dataEnabled, String address, Codec codec, boolean cacheable, BiPredicate contains, Consumer... callbacks) { + super(tooltipEnabled); + + this.dataEnabled = dataEnabled; + this.address = address; + this.codec = codec; + this.cacheable = cacheable; + this.contains = contains; + this.callbacks = callbacks; + } + + @Override + public boolean isDataEnabled() { + return dataEnabled.test(ItemTooltip.config); + } + + @Override + @Nullable + public T getData() { + return data; + } + + @Override + public Codec getCodec() { + return codec; + } + + @Override + public boolean hasOrNullWarning(String memberName) { + if (data == null) { + ItemTooltip.nullWarning(); + + return false; + } else { + return contains.test(data, memberName); + } + } + + @Override + public void run() { + try { + if (cacheable) { + HttpHeaders headers = Http.sendHeadRequest(address); + long hash = Http.getEtag(headers).hashCode() + Http.getLastModified(headers).hashCode(); + if (this.hash == hash) return; + else this.hash = hash; + } + + String response = Http.sendGetRequest(address); + + if (response.trim().startsWith(" callback : callbacks) { + callback.accept(data); + } + } + } catch (Exception e) { + ItemTooltip.LOGGER.warn("[Skyblocker] Failed to download {} prices!", this, e); + } + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/info/DataTooltipInfoType.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/info/DataTooltipInfoType.java new file mode 100644 index 00000000..38aad4fe --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/info/DataTooltipInfoType.java @@ -0,0 +1,54 @@ +package de.hysky.skyblocker.skyblock.item.tooltip.info; + +import java.util.List; +import java.util.concurrent.CompletableFuture; + +import org.jetbrains.annotations.Nullable; + +import com.mojang.serialization.Codec; + +public interface DataTooltipInfoType extends TooltipInfoType, Runnable { + /** + * @return whether the data should be downloaded (if there is any) + */ + boolean isDataEnabled(); + + @Nullable + T getData(); + + Codec getCodec(); + + /** + * Checks if the data has the given member name and sends a warning message if data is null. + * + * @param memberName the member name to check + * @return whether the data has the given member name or not + */ + boolean hasOrNullWarning(String memberName); + + /** + * Downloads the data if it is enabled. + * + * @param futureList the list to add the future to + */ + default void downloadIfEnabled(List> futureList) { + if (isDataEnabled()) { + download(futureList); + } + } + + /** + * Downloads the data. + * + * @param futureList the list to add the future to + */ + default void download(List> futureList) { + futureList.add(CompletableFuture.runAsync(this)); + } + + /** + * Downloads the data. + */ + @Override + void run(); +} \ No newline at end of file diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/info/SimpleTooltipInfo.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/info/SimpleTooltipInfo.java new file mode 100644 index 00000000..52f51fd9 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/info/SimpleTooltipInfo.java @@ -0,0 +1,19 @@ +package de.hysky.skyblocker.skyblock.item.tooltip.info; + +import java.util.function.Predicate; + +import de.hysky.skyblocker.config.configs.GeneralConfig; +import de.hysky.skyblocker.skyblock.item.tooltip.ItemTooltip; + +public class SimpleTooltipInfo implements TooltipInfoType { + private final Predicate tooltipEnabled; + + protected SimpleTooltipInfo(Predicate tooltipEnabled) { + this.tooltipEnabled = tooltipEnabled; + } + + @Override + public boolean isTooltipEnabled() { + return tooltipEnabled.test(ItemTooltip.config); + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/info/TooltipInfoType.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/info/TooltipInfoType.java new file mode 100644 index 00000000..789bb701 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/info/TooltipInfoType.java @@ -0,0 +1,59 @@ +package de.hysky.skyblocker.skyblock.item.tooltip.info; + +import java.util.Map; +import java.util.function.BiPredicate; +import java.util.function.Consumer; +import java.util.function.Predicate; + +import com.mojang.serialization.Codec; + +import de.hysky.skyblocker.config.SkyblockerConfig; +import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.config.configs.GeneralConfig; +import de.hysky.skyblocker.config.configs.GeneralConfig.Craft; +import de.hysky.skyblocker.skyblock.item.tooltip.AccessoriesHelper; +import de.hysky.skyblocker.skyblock.item.tooltip.AccessoriesHelper.Accessory; +import de.hysky.skyblocker.skyblock.item.tooltip.adders.EssenceShopPrice; +import de.hysky.skyblocker.utils.BazaarProduct; +import de.hysky.skyblocker.utils.CodecUtils; +import de.hysky.skyblocker.utils.Utils; +import it.unimi.dsi.fastutil.objects.Object2DoubleMap; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; + +public interface TooltipInfoType { + DataTooltipInfoType> NPC = ofData(itemTooltip -> itemTooltip.enableNPCPrice, "https://hysky.de/api/npcprice", CodecUtils.object2DoubleMapCodec(Codec.STRING), true, Object2DoubleMap::containsKey); + DataTooltipInfoType> BAZAAR = ofData(itemTooltip -> itemTooltip.enableBazaarPrice, itemTooltip -> itemTooltip.enableBazaarPrice || itemTooltip.enableCraftingCost != Craft.OFF || itemTooltip.enableEstimatedItemValue || getConfig().dungeons.dungeonChestProfit.enableProfitCalculator || getConfig().dungeons.dungeonChestProfit.croesusProfit || getConfig().uiAndVisuals.chestValue.enableChestValue || itemTooltip.showEssenceCost, "https://hysky.de/api/bazaar", BazaarProduct.MAP_CODEC, false, Object2ObjectMap::containsKey, EssenceShopPrice::refreshEssencePrices); + DataTooltipInfoType> LOWEST_BINS = ofData(itemTooltip -> itemTooltip.enableLowestBIN, itemTooltip -> itemTooltip.enableLowestBIN || itemTooltip.enableCraftingCost != Craft.OFF || itemTooltip.enableEstimatedItemValue || getConfig().dungeons.dungeonChestProfit.enableProfitCalculator || getConfig().dungeons.dungeonChestProfit.croesusProfit || getConfig().uiAndVisuals.chestValue.enableChestValue, "https://hysky.de/api/auctions/lowestbins", CodecUtils.object2DoubleMapCodec(Codec.STRING), false, Object2DoubleMap::containsKey); + DataTooltipInfoType> ONE_DAY_AVERAGE = ofData(itemTooltip -> itemTooltip.enableAvgBIN, "https://hysky.de/api/auctions/lowestbins/average/1day.json", CodecUtils.object2DoubleMapCodec(Codec.STRING), false, Object2DoubleMap::containsKey); + DataTooltipInfoType> THREE_DAY_AVERAGE = ofData(itemTooltip -> itemTooltip.enableAvgBIN, itemTooltip -> itemTooltip.enableAvgBIN || getConfig().uiAndVisuals.searchOverlay.enableAuctionHouse, "https://hysky.de/api/auctions/lowestbins/average/3day.json", CodecUtils.object2DoubleMapCodec(Codec.STRING), false, Object2DoubleMap::containsKey); + DataTooltipInfoType> MOTES = ofData(itemTooltip -> itemTooltip.enableMotesPrice, itemTooltip -> itemTooltip.enableMotesPrice && Utils.isInTheRift(), "https://hysky.de/api/motesprice", CodecUtils.object2IntMapCodec(Codec.STRING), true, Object2IntMap::containsKey); + TooltipInfoType OBTAINED = ofSimple(itemTooltip -> itemTooltip.enableObtainedDate); + DataTooltipInfoType> MUSEUM = ofData(itemTooltip -> itemTooltip.enableMuseumInfo, "https://hysky.de/api/museum", Codec.unboundedMap(Codec.STRING, Codec.STRING), true, Map::containsKey); + DataTooltipInfoType> COLOR = ofData(itemTooltip -> itemTooltip.enableExoticTooltip, "https://hysky.de/api/color", Codec.unboundedMap(Codec.STRING, Codec.STRING), true, Map::containsKey); + DataTooltipInfoType> ACCESSORIES = ofData(itemTooltip -> itemTooltip.enableAccessoriesHelper, "https://hysky.de/api/accessories", Accessory.MAP_CODEC, true, Map::containsKey, AccessoriesHelper::refreshData); + TooltipInfoType ESTIMATED_ITEM_VALUE = ofSimple(itemTooltip -> itemTooltip.enableEstimatedItemValue); + + /** + * @return whether the tooltip should be shown + */ + boolean isTooltipEnabled(); + + private static SkyblockerConfig getConfig() { + return SkyblockerConfigManager.get(); + } + + private static TooltipInfoType ofSimple(Predicate tooltipEnabled) { + return new SimpleTooltipInfo(tooltipEnabled); + } + + @SafeVarargs + private static DataTooltipInfoType ofData(Predicate tooltipEnabled, String address, Codec codec, boolean cacheable, BiPredicate contains, Consumer... callbacks) { + return ofData(tooltipEnabled, tooltipEnabled, address, codec, cacheable, contains, callbacks); + } + + @SafeVarargs + private static DataTooltipInfoType ofData(Predicate tooltipEnabled, Predicate dataEnabled, String address, Codec codec, boolean cacheable, BiPredicate contains, Consumer... callbacks) { + return new DataTooltipInfo<>(tooltipEnabled, dataEnabled, address, codec, cacheable, contains, callbacks); + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/searchoverlay/SearchOverManager.java b/src/main/java/de/hysky/skyblocker/skyblock/searchoverlay/SearchOverManager.java index 70dd8ada..987bece2 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/searchoverlay/SearchOverManager.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/searchoverlay/SearchOverManager.java @@ -1,17 +1,18 @@ package de.hysky.skyblocker.skyblock.searchoverlay; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; import com.mojang.brigadier.Command; import com.mojang.brigadier.CommandDispatcher; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.config.configs.UIAndVisualsConfig; -import de.hysky.skyblocker.skyblock.item.tooltip.TooltipInfoType; +import de.hysky.skyblocker.skyblock.item.tooltip.info.TooltipInfoType; +import de.hysky.skyblocker.utils.BazaarProduct; import de.hysky.skyblocker.utils.NEURepoManager; import de.hysky.skyblocker.utils.scheduler.MessageScheduler; import io.github.moulberry.repo.data.NEUItem; import io.github.moulberry.repo.util.NEUId; import it.unimi.dsi.fastutil.Pair; +import it.unimi.dsi.fastutil.objects.Object2DoubleMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; import net.minecraft.block.entity.SignBlockEntity; @@ -100,41 +101,39 @@ public class SearchOverManager { try { if (TooltipInfoType.BAZAAR.getData() == null) TooltipInfoType.BAZAAR.run(); - JsonObject products = TooltipInfoType.BAZAAR.getData(); - for (Map.Entry entry : products.entrySet()) { - if (entry.getValue().isJsonObject()) { - JsonObject product = entry.getValue().getAsJsonObject(); - String id = product.get("id").getAsString(); - int sellVolume = product.get("sellVolume").getAsInt(); - if (sellVolume == 0) - continue; //do not add items that do not sell e.g. they are not actual in the bazaar - Matcher matcher = BAZAAR_ENCHANTMENT_PATTERN.matcher(id); - if (matcher.matches()) {//format enchantments - //remove ultimate if in name - String name = matcher.group(1); - if (!name.contains("WISE")) { //only way found to remove ultimate from everything but ultimate wise - name = name.replace("ULTIMATE_", ""); - } - name = name.replace("_", " "); - name = capitalizeFully(name); - int enchantLevel = Integer.parseInt(matcher.group(2)); - String level = ""; - if (enchantLevel > 0) { - level = ROMAN_NUMERALS[enchantLevel - 1]; - } - bazaarItems.add(name + " " + level); - namesToId.put(name + " " + level, matcher.group(1) + ";" + matcher.group(2)); - continue; - } - //look up id for name - NEUItem neuItem = NEURepoManager.NEU_REPO.getItems().getItemBySkyblockId(id); - if (neuItem != null) { - String name = Formatting.strip(neuItem.getDisplayName()); - bazaarItems.add(name); - namesToId.put(name, id); - continue; - } - } + Object2ObjectMap products = TooltipInfoType.BAZAAR.getData(); + for (Map.Entry entry : products.entrySet()) { + BazaarProduct product = entry.getValue(); + String id = product.id(); + int sellVolume = product.sellVolume(); + if (sellVolume == 0) + continue; //do not add items that do not sell e.g. they are not actual in the bazaar + Matcher matcher = BAZAAR_ENCHANTMENT_PATTERN.matcher(id); + if (matcher.matches()) {//format enchantments + //remove ultimate if in name + String name = matcher.group(1); + if (!name.contains("WISE")) { //only way found to remove ultimate from everything but ultimate wise + name = name.replace("ULTIMATE_", ""); + } + name = name.replace("_", " "); + name = capitalizeFully(name); + int enchantLevel = Integer.parseInt(matcher.group(2)); + String level = ""; + if (enchantLevel > 0) { + level = ROMAN_NUMERALS[enchantLevel - 1]; + } + bazaarItems.add(name + " " + level); + namesToId.put(name + " " + level, matcher.group(1) + ";" + matcher.group(2)); + continue; + } + //look up id for name + NEUItem neuItem = NEURepoManager.NEU_REPO.getItems().getItemBySkyblockId(id); + if (neuItem != null) { + String name = Formatting.strip(neuItem.getDisplayName()); + bazaarItems.add(name); + namesToId.put(name, id); + continue; + } } } catch (Exception e) { LOGGER.error("[Skyblocker] Failed to load bazaar item list! ", e); @@ -146,7 +145,7 @@ public class SearchOverManager { if (TooltipInfoType.THREE_DAY_AVERAGE.getData() == null) { TooltipInfoType.THREE_DAY_AVERAGE.run(); } - for (Map.Entry entry : TooltipInfoType.THREE_DAY_AVERAGE.getData().entrySet()) { + for (Object2DoubleMap.Entry entry : TooltipInfoType.THREE_DAY_AVERAGE.getData().object2DoubleEntrySet()) { String id = entry.getKey(); //look up in NEU repo. id = id.split("[+-]")[0]; diff --git a/src/main/java/de/hysky/skyblocker/utils/BazaarProduct.java b/src/main/java/de/hysky/skyblocker/utils/BazaarProduct.java new file mode 100644 index 00000000..58701fe6 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/utils/BazaarProduct.java @@ -0,0 +1,19 @@ +package de.hysky.skyblocker.utils; + +import java.util.OptionalDouble; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; + +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; + +public record BazaarProduct(String id, OptionalDouble buyPrice, OptionalDouble sellPrice, int buyVolume, int sellVolume) { + private static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( + Codec.STRING.fieldOf("id").forGetter(BazaarProduct::id), + CodecUtils.optionalDouble(Codec.DOUBLE.lenientOptionalFieldOf("buyPrice")).forGetter(BazaarProduct::buyPrice), + CodecUtils.optionalDouble(Codec.DOUBLE.lenientOptionalFieldOf("sellPrice")).forGetter(BazaarProduct::sellPrice), + Codec.INT.fieldOf("buyVolume").forGetter(BazaarProduct::buyVolume), + Codec.INT.fieldOf("sellVolume").forGetter(BazaarProduct::sellVolume)) + .apply(instance, BazaarProduct::new)); + public static final Codec> MAP_CODEC = CodecUtils.object2ObjectMapCodec(Codec.STRING, CODEC); +} diff --git a/src/main/java/de/hysky/skyblocker/utils/CodecUtils.java b/src/main/java/de/hysky/skyblocker/utils/CodecUtils.java index 272a7836..5fc917bb 100644 --- a/src/main/java/de/hysky/skyblocker/utils/CodecUtils.java +++ b/src/main/java/de/hysky/skyblocker/utils/CodecUtils.java @@ -5,6 +5,12 @@ import com.mojang.serialization.MapCodec; import it.unimi.dsi.fastutil.objects.Object2BooleanMap; import it.unimi.dsi.fastutil.objects.Object2BooleanOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2DoubleMap; +import it.unimi.dsi.fastutil.objects.Object2DoubleOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import java.util.Optional; import java.util.OptionalDouble; @@ -27,4 +33,16 @@ public final class CodecUtils { public static Codec> object2BooleanMapCodec(Codec keyCodec) { return Codec.unboundedMap(keyCodec, Codec.BOOL).xmap(Object2BooleanOpenHashMap::new, Object2BooleanOpenHashMap::new); } + + public static Codec> object2IntMapCodec(Codec keyCodec) { + return Codec.unboundedMap(keyCodec, Codec.INT).xmap(Object2IntOpenHashMap::new, Object2IntOpenHashMap::new); + } + + public static Codec> object2DoubleMapCodec(Codec keyCodec) { + return Codec.unboundedMap(keyCodec, Codec.DOUBLE).xmap(Object2DoubleOpenHashMap::new, Object2DoubleOpenHashMap::new); + } + + public static Codec> object2ObjectMapCodec(Codec keyCodec, Codec valueCodec) { + return Codec.unboundedMap(keyCodec, valueCodec).xmap(Object2ObjectOpenHashMap::new, Object2ObjectOpenHashMap::new); + } } diff --git a/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java b/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java index 35b5157b..e6fa3d98 100644 --- a/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java +++ b/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java @@ -1,7 +1,5 @@ package de.hysky.skyblocker.utils; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; @@ -12,13 +10,15 @@ 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.tooltip.TooltipInfoType; 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; import de.hysky.skyblocker.utils.networth.NetworthCalculator; import it.unimi.dsi.fastutil.doubles.DoubleBooleanPair; import it.unimi.dsi.fastutil.ints.IntIntPair; import it.unimi.dsi.fastutil.longs.LongBooleanPair; +import it.unimi.dsi.fastutil.objects.Object2DoubleMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import net.azureaaron.networth.Calculation; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; import net.minecraft.component.ComponentChanges; @@ -42,6 +42,7 @@ import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.Locale; import java.util.Optional; +import java.util.OptionalDouble; import java.util.function.Predicate; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -280,19 +281,20 @@ public final class ItemUtils { * and the {@code right boolean} indicating if the price was based on complete data. */ public static @NotNull DoubleBooleanPair getItemPrice(@Nullable String skyblockApiId, boolean useBazaarBuyPrice) { - JsonObject bazaarPrices = TooltipInfoType.BAZAAR.getData(); - JsonObject lowestBinPrices = TooltipInfoType.LOWEST_BINS.getData(); + Object2ObjectMap bazaarPrices = TooltipInfoType.BAZAAR.getData(); + Object2DoubleMap lowestBinPrices = TooltipInfoType.LOWEST_BINS.getData(); if (skyblockApiId == null || skyblockApiId.isEmpty() || bazaarPrices == null || lowestBinPrices == null) return DoubleBooleanPair.of(0, false); - if (bazaarPrices.has(skyblockApiId)) { - JsonElement price = bazaarPrices.get(skyblockApiId).getAsJsonObject().get(useBazaarBuyPrice ? "buyPrice" : "sellPrice"); - boolean isPriceNull = price.isJsonNull(); - return DoubleBooleanPair.of(isPriceNull ? 0 : price.getAsDouble(), !isPriceNull); + if (bazaarPrices.containsKey(skyblockApiId)) { + BazaarProduct product = bazaarPrices.get(skyblockApiId); + OptionalDouble price = useBazaarBuyPrice ? product.buyPrice() : product.sellPrice(); + + return DoubleBooleanPair.of(price.orElse(0d), price.isPresent()); } - if (lowestBinPrices.has(skyblockApiId)) { - return DoubleBooleanPair.of(lowestBinPrices.get(skyblockApiId).getAsDouble(), true); + if (lowestBinPrices.containsKey(skyblockApiId)) { + return DoubleBooleanPair.of(lowestBinPrices.getDouble(skyblockApiId), true); } return DoubleBooleanPair.of(0, false); -- cgit