diff options
author | Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> | 2024-05-05 00:20:55 -0400 |
---|---|---|
committer | Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> | 2024-05-20 16:52:25 -0400 |
commit | 73c447e8fe535e857fc330d1823b6c9aac663b5c (patch) | |
tree | fb63de2c2cd98cc4da1974388526e45357b58f63 /src | |
parent | 610c64758fc8d0b8bea0145c33881b60c0747bd7 (diff) | |
download | Skyblocker-73c447e8fe535e857fc330d1823b6c9aac663b5c.tar.gz Skyblocker-73c447e8fe535e857fc330d1823b6c9aac663b5c.tar.bz2 Skyblocker-73c447e8fe535e857fc330d1823b6c9aac663b5c.zip |
Add coins per hour and refactor item price calculations
Diffstat (limited to 'src')
4 files changed, 115 insertions, 108 deletions
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/ChestValue.java b/src/main/java/de/hysky/skyblocker/skyblock/ChestValue.java index 7f8b2c71..7b36dd78 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/ChestValue.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/ChestValue.java @@ -7,13 +7,11 @@ import de.hysky.skyblocker.config.configs.UIAndVisualsConfig; import de.hysky.skyblocker.mixins.accessors.HandledScreenAccessor; import de.hysky.skyblocker.mixins.accessors.ScreenAccessor; import de.hysky.skyblocker.skyblock.item.tooltip.ItemTooltip; -import de.hysky.skyblocker.skyblock.item.tooltip.TooltipInfoType; import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.Utils; -import it.unimi.dsi.fastutil.longs.LongBooleanPair; +import it.unimi.dsi.fastutil.doubles.DoubleBooleanPair; import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents; import net.fabricmc.fabric.api.client.screen.v1.Screens; -import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.ingame.GenericContainerScreen; import net.minecraft.client.gui.tooltip.Tooltip; import net.minecraft.client.gui.widget.ButtonWidget; @@ -45,7 +43,7 @@ public class ChestValue { if (DUNGEON_CHESTS.contains(titleString)) { if (SkyblockerConfigManager.get().dungeons.dungeonChestProfit.enableProfitCalculator) { ScreenEvents.afterTick(screen).register(screen_ -> - ((ScreenAccessor) screen).setTitle(getDungeonChestProfit(genericContainerScreen.getScreenHandler(), title, titleString, client)) + ((ScreenAccessor) screen).setTitle(getDungeonChestProfit(genericContainerScreen.getScreenHandler(), title, titleString)) ); } } else if (SkyblockerConfigManager.get().uiAndVisuals.chestValue.enableChestValue && !titleString.equals("SkyBlock Menu")) { @@ -65,9 +63,9 @@ public class ChestValue { }); } - private static Text getDungeonChestProfit(GenericContainerScreenHandler handler, Text title, String titleString, MinecraftClient client) { + private static Text getDungeonChestProfit(GenericContainerScreenHandler handler, Text title, String titleString) { try { - long profit = 0; + double profit = 0; boolean hasIncompleteData = false, usedKismet = false; List<Slot> slots = handler.slots.subList(0, handler.getRows() * 9); @@ -85,12 +83,12 @@ public class ChestValue { //Regular item price if (id != null) { - LongBooleanPair priceData = getItemPrice(id); + DoubleBooleanPair priceData = ItemUtils.getItemPrice(id); if (!priceData.rightBoolean()) hasIncompleteData = true; //Add the item price to the profit - profit += priceData.leftLong() * stack.getCount(); + profit += priceData.leftDouble() * stack.getCount(); continue; } @@ -103,12 +101,12 @@ public class ChestValue { String type = matcher.group("type"); int amount = Integer.parseInt(matcher.group("amount")); - LongBooleanPair priceData = getItemPrice(("ESSENCE_" + type).toUpperCase()); + DoubleBooleanPair priceData = ItemUtils.getItemPrice(("ESSENCE_" + type).toUpperCase()); if (!priceData.rightBoolean()) hasIncompleteData = true; //Add the price of the essence to the profit - profit += priceData.leftLong() * amount; + profit += priceData.leftDouble() * amount; continue; } @@ -116,7 +114,7 @@ public class ChestValue { //Determine the cost of the chest if (name.contains("Open Reward Chest")) { - String foundString = searchLoreFor(stack, client, "Coins"); + String foundString = searchLoreFor(stack, "Coins"); //Incase we're searching the free chest if (!StringUtils.isBlank(foundString)) { @@ -128,19 +126,19 @@ public class ChestValue { //Determine if a kismet was used or not if (name.contains("Reroll Chest")) { - usedKismet = !StringUtils.isBlank(searchLoreFor(stack, client, "You already rerolled a chest!")); + usedKismet = !StringUtils.isBlank(searchLoreFor(stack, "You already rerolled a chest!")); } } if (SkyblockerConfigManager.get().dungeons.dungeonChestProfit.includeKismet && usedKismet) { - LongBooleanPair kismetPriceData = getItemPrice("KISMET_FEATHER"); + DoubleBooleanPair kismetPriceData = ItemUtils.getItemPrice("KISMET_FEATHER"); if (!kismetPriceData.rightBoolean()) hasIncompleteData = true; - profit -= kismetPriceData.leftLong(); + profit -= kismetPriceData.leftDouble(); } - return Text.literal(titleString).append(getProfitText(profit, hasIncompleteData)); + return Text.literal(titleString).append(getProfitText((long) profit, hasIncompleteData)); } catch (Exception e) { LOGGER.error("[Skyblocker Profit Calculator] Failed to calculate dungeon chest profit! ", e); } @@ -150,7 +148,7 @@ public class ChestValue { private static Text getChestValue(GenericContainerScreenHandler handler, Text title, String titleString) { try { - long value = 0; + double value = 0; boolean hasIncompleteData = false; List<Slot> slots = handler.slots.subList(0, handler.getRows() * 9); @@ -163,15 +161,15 @@ public class ChestValue { String id = ItemTooltip.getInternalNameFromNBT(stack, false); if (id != null) { - LongBooleanPair priceData = getItemPrice(id); + DoubleBooleanPair priceData = ItemUtils.getItemPrice(id); if (!priceData.rightBoolean()) hasIncompleteData = true; - value += priceData.leftLong() * stack.getCount(); + value += priceData.leftDouble() * stack.getCount(); } } - return Text.literal(titleString).append(getValueText(value, hasIncompleteData)); + return Text.literal(titleString).append(getValueText((long) value, hasIncompleteData)); } catch (Exception e) { LOGGER.error("[Skyblocker Value Calculator] Failed to calculate dungeon chest value! ", e); } @@ -180,33 +178,9 @@ public class ChestValue { } /** - * @return An {@link LongBooleanPair} with the {@code left long} representing the item's price, and the {@code right boolean} indicating if the price - * was based on complete data. - */ - private static LongBooleanPair getItemPrice(String id) { - JsonObject bazaarPrices = TooltipInfoType.BAZAAR.getData(); - JsonObject lbinPrices = TooltipInfoType.LOWEST_BINS.getData(); - - if (bazaarPrices == null || lbinPrices == null) return LongBooleanPair.of(0L, false); - - if (bazaarPrices.has(id)) { - JsonObject item = bazaarPrices.get(id).getAsJsonObject(); - boolean isPriceNull = item.get("sellPrice").isJsonNull(); - - return LongBooleanPair.of(isPriceNull ? 0L : (long) item.get("sellPrice").getAsDouble(), !isPriceNull); - } - - if (lbinPrices.has(id)) { - return LongBooleanPair.of((long) lbinPrices.get(id).getAsDouble(), true); - } - - return LongBooleanPair.of(0L, false); - } - - /** * Searches for a specific string of characters in the name and lore of an item */ - private static String searchLoreFor(ItemStack stack, MinecraftClient client, String searchString) { + private static String searchLoreFor(ItemStack stack, String searchString) { return ItemUtils.getLoreLineIf(stack, line -> line.contains(searchString)); } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/CroesusProfit.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/CroesusProfit.java index 70e785cb..0f459c9d 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/CroesusProfit.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/CroesusProfit.java @@ -35,13 +35,13 @@ public class CroesusProfit extends ContainerSolver { protected List<ColorHighlight> getColors(String[] groups, Int2ObjectMap<ItemStack> slots) { List<ColorHighlight> highlights = new ArrayList<>(); ItemStack bestChest = null, secondBestChest = null; - long bestValue = 0, secondBestValue = 0; // If negative value of chest - it is out of the question - long dungeonKeyPriceData = getItemPrice("DUNGEON_CHEST_KEY") * 2; // lesser ones don't worth the hassle + double bestValue = 0, secondBestValue = 0; // If negative value of chest - it is out of the question + double dungeonKeyPriceData = getItemPrice("DUNGEON_CHEST_KEY") * 2; // lesser ones don't worth the hassle for (Int2ObjectMap.Entry<ItemStack> entry : slots.int2ObjectEntrySet()) { ItemStack stack = entry.getValue(); if (stack.getName().getString().contains("Chest")) { - long value = valueChest(stack); + double value = valueChest(stack); if (value > bestValue) { secondBestChest = bestChest; secondBestValue = bestValue; @@ -68,8 +68,8 @@ public class CroesusProfit extends ContainerSolver { } - private long valueChest(@NotNull ItemStack chest) { - long chestValue = 0; + private double valueChest(@NotNull ItemStack chest) { + double chestValue = 0; int chestPrice = 0; List<String> chestItems = new ArrayList<>(); @@ -107,22 +107,8 @@ public class CroesusProfit extends ContainerSolver { } - private long getItemPrice(String itemDisplayName) { - JsonObject bazaarPrices = TooltipInfoType.BAZAAR.getData(); - JsonObject lbinPrices = TooltipInfoType.LOWEST_BINS.getData(); - long itemValue = 0; - String id = dungeonDropsNameToId.get(itemDisplayName); - - if (bazaarPrices == null || lbinPrices == null) return 0; - - if (bazaarPrices.has(id)) { - JsonObject item = bazaarPrices.get(id).getAsJsonObject(); - boolean isPriceNull = item.get("sellPrice").isJsonNull(); - return (isPriceNull ? 0L : item.get("sellPrice").getAsLong()); - } else if (lbinPrices.has(id)) { - return lbinPrices.get(id).getAsLong(); - } - return itemValue; + private double getItemPrice(String itemDisplayName) { + return ItemUtils.getItemPrice(dungeonDropsNameToId.get(itemDisplayName)).leftDouble(); } 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 f12f6fa8..9fba9249 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/garden/FarmingHudWidget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/garden/FarmingHudWidget.java @@ -6,6 +6,7 @@ import de.hysky.skyblocker.skyblock.tabhud.widget.Widget; import de.hysky.skyblocker.skyblock.tabhud.widget.component.PlainTextComponent; import de.hysky.skyblocker.skyblock.tabhud.widget.component.ProgressComponent; import de.hysky.skyblocker.utils.ItemUtils; +import it.unimi.dsi.fastutil.doubles.DoubleBooleanPair; import net.minecraft.client.MinecraftClient; import net.minecraft.entity.Entity; import net.minecraft.item.ItemStack; @@ -18,31 +19,31 @@ import java.util.Map; public class FarmingHudWidget extends Widget { private static final MutableText TITLE = Text.literal("Farming").formatted(Formatting.YELLOW, Formatting.BOLD); - public static final Map<String, ItemStack> FARMING_TOOLS = Map.ofEntries( - Map.entry("THEORETICAL_HOE_WHEAT_1", Ico.WHEAT), - Map.entry("THEORETICAL_HOE_WHEAT_2", Ico.WHEAT), - Map.entry("THEORETICAL_HOE_WHEAT_3", Ico.WHEAT), - Map.entry("THEORETICAL_HOE_CARROT_1", Ico.CARROT), - Map.entry("THEORETICAL_HOE_CARROT_2", Ico.CARROT), - Map.entry("THEORETICAL_HOE_CARROT_3", Ico.CARROT), - Map.entry("THEORETICAL_HOE_POTATO_1", Ico.POTATO), - Map.entry("THEORETICAL_HOE_POTATO_2", Ico.POTATO), - Map.entry("THEORETICAL_HOE_POTATO_3", Ico.POTATO), - Map.entry("THEORETICAL_HOE_CANE_1", Ico.SUGAR_CANE), - Map.entry("THEORETICAL_HOE_CANE_2", Ico.SUGAR_CANE), - Map.entry("THEORETICAL_HOE_CANE_3", Ico.SUGAR_CANE), - Map.entry("THEORETICAL_HOE_WARTS_1", Ico.NETHER_WART), - Map.entry("THEORETICAL_HOE_WARTS_2", Ico.NETHER_WART), - Map.entry("THEORETICAL_HOE_WARTS_3", Ico.NETHER_WART), - Map.entry("FUNGI_CUTTER", Ico.MUSHROOM), - Map.entry("CACTUS_KNIFE", Ico.CACTUS), - Map.entry("MELON_DICER", Ico.MELON), - Map.entry("MELON_DICER_2", Ico.MELON), - Map.entry("MELON_DICER_3", Ico.MELON), - Map.entry("PUMPKIN_DICER", Ico.PUMPKIN), - Map.entry("PUMPKIN_DICER_2", Ico.PUMPKIN), - Map.entry("PUMPKIN_DICER_3", Ico.PUMPKIN), - Map.entry("COCO_CHOPPER", Ico.COCOA_BEANS) + public static final Map<String, String> FARMING_TOOLS = Map.ofEntries( + Map.entry("THEORETICAL_HOE_WHEAT_1", "WHEAT"), + Map.entry("THEORETICAL_HOE_WHEAT_2", "WHEAT"), + Map.entry("THEORETICAL_HOE_WHEAT_3", "WHEAT"), + Map.entry("THEORETICAL_HOE_CARROT_1", "CARROT_ITEM"), + Map.entry("THEORETICAL_HOE_CARROT_2", "CARROT_ITEM"), + Map.entry("THEORETICAL_HOE_CARROT_3", "CARROT_ITEM"), + Map.entry("THEORETICAL_HOE_POTATO_1", "POTATO_ITEM"), + Map.entry("THEORETICAL_HOE_POTATO_2", "POTATO_ITEM"), + Map.entry("THEORETICAL_HOE_POTATO_3", "POTATO_ITEM"), + Map.entry("THEORETICAL_HOE_CANE_1", "SUGAR_CANE"), + Map.entry("THEORETICAL_HOE_CANE_2", "SUGAR_CANE"), + Map.entry("THEORETICAL_HOE_CANE_3", "SUGAR_CANE"), + Map.entry("THEORETICAL_HOE_WARTS_1", "NETHER_STALK"), + Map.entry("THEORETICAL_HOE_WARTS_2", "NETHER_STALK"), + Map.entry("THEORETICAL_HOE_WARTS_3", "NETHER_STALK"), + Map.entry("FUNGI_CUTTER", "RED_MUSHROOM"), + Map.entry("CACTUS_KNIFE", "CACTUS"), + Map.entry("MELON_DICER", "MELON"), + Map.entry("MELON_DICER_2", "MELON"), + Map.entry("MELON_DICER_3", "MELON"), + Map.entry("PUMPKIN_DICER", "PUMPKIN"), + Map.entry("PUMPKIN_DICER_2", "PUMPKIN"), + Map.entry("PUMPKIN_DICER_3", "PUMPKIN"), + Map.entry("COCO_CHOPPER", "INK_SACK.3") ); public static final FarmingHudWidget INSTANCE = new FarmingHudWidget(); private final MinecraftClient client = MinecraftClient.getInstance(); @@ -56,19 +57,25 @@ public class FarmingHudWidget extends Widget { @Override public void updateContent() { - ItemStack icon = client.player == null ? Ico.HOE : FARMING_TOOLS.getOrDefault(ItemUtils.getItemId(client.player.getMainHandStack()), Ico.HOE); - addSimpleIcoText(icon, "Counter: ", Formatting.YELLOW, FarmingHud.NUMBER_FORMAT.format(FarmingHud.counter())); - addSimpleIcoText(icon, "Crops/min: ", Formatting.YELLOW, FarmingHud.NUMBER_FORMAT.format((int) FarmingHud.cropsPerMinute() / 100 * 100)); - addSimpleIcoText(icon, "Blocks/s: ", Formatting.YELLOW, Integer.toString(FarmingHud.blockBreaks())); + if (client.player == null) return; + + ItemStack farmingTool = client.player.getMainHandStack(); + addSimpleIcoText(farmingTool, "Counter: ", Formatting.YELLOW, FarmingHud.NUMBER_FORMAT.format(FarmingHud.counter())); + float cropsPerMinute = FarmingHud.cropsPerMinute(); + addSimpleIcoText(farmingTool, "Crops/min: ", Formatting.YELLOW, FarmingHud.NUMBER_FORMAT.format((int) cropsPerMinute / 10 * 10)); + DoubleBooleanPair itemPrice = ItemUtils.getItemPrice(FARMING_TOOLS.get(ItemUtils.getItemId(farmingTool))); + addSimpleIcoText(Ico.GOLD, "Coins/h: ", Formatting.GOLD, itemPrice.rightBoolean() ? FarmingHud.NUMBER_FORMAT.format((int) (itemPrice.leftDouble() * cropsPerMinute * 0.6) * 100) : "No Data"); // Multiply by 60 to convert to hourly and divide by 100 for rounding is combined into multiplying by 0.6 + + addSimpleIcoText(farmingTool, "Blocks/s: ", Formatting.YELLOW, Integer.toString(FarmingHud.blockBreaks())); //noinspection DataFlowIssue addComponent(new ProgressComponent(Ico.LANTERN, Text.literal("Farming Level: "), FarmingHud.farmingXpPercentProgress(), Formatting.GOLD.getColorValue())); addSimpleIcoText(Ico.LIME_DYE, "Farming XP/h: ", Formatting.YELLOW, FarmingHud.NUMBER_FORMAT.format((int) FarmingHud.farmingXpPerHour())); Entity cameraEntity = client.getCameraEntity(); - double yaw = cameraEntity == null ? 0.0d : cameraEntity.getYaw(); - double pitch = cameraEntity == null ? 0.0d : cameraEntity.getPitch(); - addComponent(new PlainTextComponent(Text.literal("Yaw: " + String.format("%.3f", MathHelper.wrapDegrees(yaw))).formatted(Formatting.YELLOW))); - addComponent(new PlainTextComponent(Text.literal("Pitch: " + String.format("%.3f", MathHelper.wrapDegrees(pitch))).formatted(Formatting.YELLOW))); + String yaw = cameraEntity == null ? "No Camera Entity" : String.format("%.3f", MathHelper.wrapDegrees(cameraEntity.getYaw())); + String pitch = cameraEntity == null ? "No Camera Entity" : String.format("%.3f", MathHelper.wrapDegrees(cameraEntity.getPitch())); + addComponent(new PlainTextComponent(Text.literal("Yaw: " + yaw).formatted(Formatting.YELLOW))); + addComponent(new PlainTextComponent(Text.literal("Pitch: " + pitch).formatted(Formatting.YELLOW))); if (LowerSensitivity.isSensitivityLowered()) { addComponent(new PlainTextComponent(Text.translatable("skyblocker.garden.hud.mouseLocked").formatted(Formatting.ITALIC))); } diff --git a/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java b/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java index 1aa77080..24f30e48 100644 --- a/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java +++ b/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java @@ -1,5 +1,7 @@ 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; @@ -9,7 +11,10 @@ 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.item.tooltip.TooltipInfoType; +import it.unimi.dsi.fastutil.doubles.DoubleBooleanPair; import it.unimi.dsi.fastutil.ints.IntIntPair; +import it.unimi.dsi.fastutil.longs.LongBooleanPair; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; import net.minecraft.component.ComponentChanges; import net.minecraft.component.DataComponentTypes; @@ -64,7 +69,7 @@ public class ItemUtils { } @SuppressWarnings("deprecation") - public static NbtCompound getCustomData(@NotNull ItemStack stack) { + public static NbtCompound getCustomData(@NotNull ItemStack stack) { return stack.getOrDefault(DataComponentTypes.CUSTOM_DATA, NbtComponent.DEFAULT).getNbt(); } @@ -74,7 +79,7 @@ public class ItemUtils { * @param stack the item stack to get the internal name from * @return an optional containing the internal name of the item stack */ - public static Optional<String> getItemIdOptional(@NotNull ItemStack stack) { + public static Optional<String> getItemIdOptional(@NotNull ItemStack stack) { NbtCompound customData = getCustomData(stack); return customData.contains(ID) ? Optional.of(customData.getString(ID)) : Optional.empty(); } @@ -85,7 +90,7 @@ public class ItemUtils { * @param stack the item stack to get the internal name from * @return the internal name of the item stack, or an empty string if the item stack is null or does not have an internal name */ - public static String getItemId(@NotNull ItemStack stack) { + public static String getItemId(@NotNull ItemStack stack) { return getCustomData(stack).getString(ID); } @@ -95,7 +100,7 @@ public class ItemUtils { * @param stack the item stack to get the UUID from * @return an optional containing the UUID of the item stack */ - public static Optional<String> getItemUuidOptional(@NotNull ItemStack stack) { + public static Optional<String> getItemUuidOptional(@NotNull ItemStack stack) { NbtCompound customData = getCustomData(stack); return customData.contains(UUID) ? Optional.of(customData.getString(UUID)) : Optional.empty(); } @@ -106,11 +111,46 @@ public class ItemUtils { * @param stack the item stack to get the UUID from * @return the UUID of the item stack, or an empty string if the item stack is null or does not have a UUID */ - public static String getItemUuid(@NotNull ItemStack stack) { + public static String getItemUuid(@NotNull ItemStack stack) { return getCustomData(stack).getString(UUID); } /** + * Gets the bazaar sell price or the lowest bin based on the id of the item stack. + * + * @return An {@link LongBooleanPair} with the {@code left long} representing the item's price, + * and the {@code right boolean} indicating if the price was based on complete data. + */ + public static DoubleBooleanPair getItemPrice(@NotNull ItemStack stack) { + return getItemPrice(getItemId(stack)); + } + + /** + * Gets the bazaar sell price or the lowest bin of the item with the specified id. + * + * @return An {@link LongBooleanPair} with the {@code left long} representing the item's price, + * and the {@code right boolean} indicating if the price was based on complete data. + */ + public static DoubleBooleanPair getItemPrice(@Nullable String id) { + JsonObject bazaarPrices = TooltipInfoType.BAZAAR.getData(); + JsonObject lowestBinPrices = TooltipInfoType.LOWEST_BINS.getData(); + + if (id == null || id.isEmpty() || bazaarPrices == null || lowestBinPrices == null) return DoubleBooleanPair.of(0, false); + + if (bazaarPrices.has(id)) { + JsonElement sellPrice = bazaarPrices.get(id).getAsJsonObject().get("sellPrice"); + boolean isPriceNull = sellPrice.isJsonNull(); + return DoubleBooleanPair.of(isPriceNull ? 0 : sellPrice.getAsDouble(), !isPriceNull); + } + + if (lowestBinPrices.has(id)) { + return DoubleBooleanPair.of(lowestBinPrices.get(id).getAsDouble(), true); + } + + return DoubleBooleanPair.of(0, false); + } + + /** * This method converts the "timestamp" variable into the same date format as Hypixel represents it in the museum. * Currently, there are two types of string timestamps the legacy which is built like this * "dd/MM/yy hh:mm" ("25/04/20 16:38") and the current which is built like this @@ -126,7 +166,7 @@ public class ItemUtils { * @param stack the item under the pointer * @return if the item have a "Timestamp" it will be shown formated on the tooltip */ - public static String getTimestamp(ItemStack stack) { + public static String getTimestamp(ItemStack stack) { NbtCompound customData = getCustomData(stack); if (customData != null && customData.contains("timestamp", NbtElement.LONG_TYPE)) { @@ -197,7 +237,7 @@ public class ItemUtils { public static List<Text> getLore(ItemStack item) { return item.getOrDefault(DataComponentTypes.LORE, LoreComponent.DEFAULT).styledLines(); } - + public static PropertyMap propertyMapWithTexture(String textureValue) { return Codecs.GAME_PROFILE_PROPERTY_MAP.parse(JsonOps.INSTANCE, JsonParser.parseString("[{\"name\":\"textures\",\"value\":\"" + textureValue + "\"}]")).getOrThrow(); } @@ -206,12 +246,12 @@ public class ItemUtils { if (!stack.isOf(Items.PLAYER_HEAD) || !stack.contains(DataComponentTypes.PROFILE)) return ""; ProfileComponent profile = stack.get(DataComponentTypes.PROFILE); - String texture = profile.properties().get("textures").stream() + if (profile == null) return ""; + + return profile.properties().get("textures").stream() .map(Property::value) .findFirst() .orElse(""); - - return texture; } public static ItemStack getSkyblockerStack() { |