From b039b737e57be6c16b8170edbf0eee894c8c30dd Mon Sep 17 00:00:00 2001 From: Cow Date: Sun, 23 Jul 2023 18:00:23 +0200 Subject: Fixed calculated enchanted books price display Enchanted books are sold on the Bazaar, and not at the Auction house anymore --- CHANGELOG.md | 11 +- .../de/cowtipper/cowlection/config/MooConfig.java | 10 +- .../listener/skyblock/SkyBlockListener.java | 170 ++++++++++----------- .../resources/assets/cowlection/lang/en_US.lang | 8 +- 4 files changed, 99 insertions(+), 100 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd15470..35a8879 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,16 +28,19 @@ All other features *do not* require an API key and thus should be unaffected by - `/friend notifications` to cycle through the available Friends notifications options, or `/settings` → Social Settings → Friend Notifications: All / Best / None - `/guild notifications` to toggle Guild notifications, or `/settings` → Personal Guild Settings → Guild Notifications +### Fixed +- Pet exp in tooltips: fixed rare crash caused by unexpected NBT data typing +- Bazaar: fixed "Show items left to buy/sell" not working anymore +- Enchanted books: fixed "price converted to level 1 books", as enchantments are now sold on the Bazaar, and no longer inside the Auction house + - works on "intermediate" Bazaar pages, so the 'overview' Bazaar pages that list all levels of a certain enchantment (GUI title starts with either `Enchantments ➜` or `Ultimate Enchantments ➜`) + - (related config options: `/moo config enchantment`) + ### Changed - Dungeons overlay: now disabled by default (old config entries aren't modified) - SkyBlock player lookup: removed 'last played/last profile save' as it's no longer part of the API - Analyze island: added new Minion (Vampire) and updated texture IDs for minions that previously erroneously shared the same skin - some Hypixel API related changes regarding API key validation -### Fixed -- Pet exp in tooltips: fixed rare crash caused by unexpected NBT data typing -- Bazaar: fixed "Show items left to buy/sell" not working anymore - ## [1.8.9-0.15.1] - 22.12.2022 ### Fixed - Fixed Dungeons Party Finder player lookup when someone joins a party diff --git a/src/main/java/de/cowtipper/cowlection/config/MooConfig.java b/src/main/java/de/cowtipper/cowlection/config/MooConfig.java index 38b7396..e0e151e 100644 --- a/src/main/java/de/cowtipper/cowlection/config/MooConfig.java +++ b/src/main/java/de/cowtipper/cowlection/config/MooConfig.java @@ -478,6 +478,9 @@ public class MooConfig { Property propNumeralSystem = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), "numeralSystem", "Arabic: 1, 4, 10", "Use Roman or Arabic numeral system?", new String[]{"Arabic: 1, 4, 10", "Roman: I, IV, X"})); + Property propAuctionHouseMarkEndedAuctions = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), + "auctionHouseMarkEndedAuctions", "a letter", "Mark ended auctions", new String[]{"a letter", "a word", "disabled"})); + Map demoAhItemExtraAttributes = new HashMap<>(); demoAhItemExtraAttributes.put("id", new NBTTagString("BEACON")); ItemStack demoAhItem = MooConfigPreview.createDemoItem("beacon", "§764x §fB§8e§facon Block", new String[]{"§f§lCOMMON", "§8§m-----------------", "§7Seller: §6[MVP§0++§6] Enlightener", "§7Buy it now: §63,900,000 coins", "", "§7Ends in: §e13h 33m 37s", "", "§eDon't click to inspect!"}, demoAhItemExtraAttributes); @@ -490,9 +493,6 @@ public class MooConfig { "tooltipAuctionHousePriceEachEnchantments", new String[]{"overload", "rejuvenate"}, "Price per lvl 1 book enchantment") .setValidationPattern(Pattern.compile("^[A-Za-z_ -]+$"))); - Property propAuctionHouseMarkEndedAuctions = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), - "auctionHouseMarkEndedAuctions", "a letter", "Mark ended auctions", new String[]{"a letter", "a word", "disabled"})); - Property propBazaarSellAllOrder = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), "bazaarSellAllOrder", "price (sum)", "Bazaar: sell all order", new String[]{"price (sum)", "item amount", "unordered", "price (each)"}), new MooConfigPreview(MooConfigPreview.createDemoItem("chest", "§aSell Inventory Now", new String[]{"§7Instantly sell anything in", "§7your inventory that can be", "§7sold on the Bazaar.", "", " §a1§7x §aEnchanted Leather §7for §65,263.1 coins", " §a42§7x §fLeather §7for §6436.8 coins", " §a2§7x §fRabbit Hide §7for §642.0 coins", " §a79§7x §fRaw Beef §7for §6450.3 coins", " §a16§7x §aEnchanted Raw Beef §7for §69,867.2 coins", "", "§7You earn: §615,698 coins", "", "§eClick to sell!"}, Collections.emptyMap()))); @@ -929,9 +929,9 @@ public class MooConfig { } if (modifiedTooltipAuctionHousePriceEachEnchantments) { for (int i = 0, enchantmentsLength = tooltipAuctionHousePriceEachEnchantments.length; i < enchantmentsLength; i++) { - // standardize enchantment names to match their names in the NBT data + // standardize enchantment names String enchantmentName = tooltipAuctionHousePriceEachEnchantments[i]; - String standardizedEnchantmentName = enchantmentName.toLowerCase().replace(' ', '_'); + String standardizedEnchantmentName = enchantmentName.toLowerCase().replaceAll("[_ -]", ""); tooltipAuctionHousePriceEachEnchantments[i] = standardizedEnchantmentName; } propTooltipAuctionHousePriceEachEnchantments.set(tooltipAuctionHousePriceEachEnchantments); diff --git a/src/main/java/de/cowtipper/cowlection/listener/skyblock/SkyBlockListener.java b/src/main/java/de/cowtipper/cowlection/listener/skyblock/SkyBlockListener.java index f1d9108..0024b71 100644 --- a/src/main/java/de/cowtipper/cowlection/listener/skyblock/SkyBlockListener.java +++ b/src/main/java/de/cowtipper/cowlection/listener/skyblock/SkyBlockListener.java @@ -33,11 +33,10 @@ import net.minecraft.inventory.Slot; import net.minecraft.item.EnumDyeColor; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTBase; import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.nbt.NBTTagInt; import net.minecraft.nbt.NBTTagList; import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.MathHelper; import net.minecraft.util.ResourceLocation; import net.minecraft.util.StatCollector; import net.minecraftforge.client.event.GuiOpenEvent; @@ -45,7 +44,6 @@ import net.minecraftforge.client.event.GuiScreenEvent; import net.minecraftforge.common.util.Constants; import net.minecraftforge.event.entity.player.ItemTooltipEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import net.minecraftforge.fml.relauncher.ReflectionHelper; import org.apache.commons.lang3.StringUtils; import org.lwjgl.input.Keyboard; import org.lwjgl.input.Mouse; @@ -61,8 +59,10 @@ import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; +import java.util.ArrayList; +import java.util.Comparator; import java.util.List; -import java.util.*; +import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -524,54 +524,14 @@ public class SkyBlockListener { // for auction house: show price for each item if multiple items are sold at once or if higher tier ultimate enchantment books are sold MooConfig.Setting tooltipAuctionHousePriceEachDisplay = MooConfig.getTooltipAuctionHousePriceEachDisplay(); if ((tooltipAuctionHousePriceEachDisplay == MooConfig.Setting.ALWAYS || tooltipAuctionHousePriceEachDisplay == MooConfig.Setting.SPECIAL && MooConfig.isTooltipToggleKeyBindingPressed()) - && (e.entityPlayer.openContainer instanceof ContainerChest || Minecraft.getMinecraft().currentScreen instanceof MooConfigGui)) { - - int itemAmount = -1; - String superEnchant = null; - if (e.itemStack.getItem() == Items.enchanted_book && extraAttributes != null && extraAttributes.hasKey("enchantments", Constants.NBT.TAG_COMPOUND)) { - NBTTagCompound enchants = extraAttributes.getCompoundTag("enchantments"); - try { - Map enchantmentsMap = ReflectionHelper.getPrivateValue(NBTTagCompound.class, enchants, "tagMap", "field_74784_a"); - - if (enchantmentsMap.size() == 1) { - for (Map.Entry enchant : enchantmentsMap.entrySet()) { - String enchantKey = enchant.getKey(); - if (enchantKey.startsWith("ultimate_") && enchant.getValue() instanceof NBTTagInt) { - // enchanted book with 1 enchantment (which is an ultimate enchant) - // enchantment tier => amount of books needed - // I = 2^0 = 1 - // II = 2^1 = 2 - // III = 2^2 = 4 - // IV = 2^3 = 8 - // V = 2^4 = 16 - itemAmount = (int) Math.pow(2, ((NBTTagInt) enchant.getValue()).getInt() - 1); - superEnchant = Utils.fancyCase(enchantKey.substring("ultimate_".length())); - break; - } else if (enchantKey.startsWith("turbo_") && enchant.getValue() instanceof NBTTagInt) { - itemAmount = (int) Math.pow(2, ((NBTTagInt) enchant.getValue()).getInt() - 1); - superEnchant = "Turbo-" + Utils.fancyCase(enchantKey.substring("turbo_".length())); - if (superEnchant.equals("Turbo-Cactus")) { - // (╯°□°)╯︵ ┻━┻ - superEnchant = "Turbo-Cacti"; - } - break; - } - for (String priceEachEnchantment : MooConfig.tooltipAuctionHousePriceEachEnchantments) { - String priceEachEnchantKey = priceEachEnchantment; - int dashInEnchantName = priceEachEnchantKey.indexOf('-'); - if (dashInEnchantName > 0) { - priceEachEnchantKey = priceEachEnchantKey.replace('-', '_'); - } - if (enchantKey.equals(priceEachEnchantKey) && enchant.getValue() instanceof NBTTagInt) { - itemAmount = (int) Math.pow(2, ((NBTTagInt) enchant.getValue()).getInt() - 1); - superEnchant = Utils.fancyCase(priceEachEnchantment); - } - } - } - } - } catch (ReflectionHelper.UnableToAccessFieldException ignored) { - return; - } + && (e.entityPlayer.openContainer instanceof ContainerChest || currentScreen instanceof MooConfigGui)) { + + int itemAmount; + String enchantmentName = null; + Pair enchantedBookInfo = this.extractEnchantedBookInfo(currentScreen, e.itemStack); + if (enchantedBookInfo != null) { + enchantmentName = enchantedBookInfo.first(); + itemAmount = enchantedBookInfo.second(); } else { itemAmount = e.itemStack.stackSize; boolean isSubmitBidItem = isSubmitBidItem(e.itemStack); @@ -590,45 +550,39 @@ public class SkyBlockListener { itemAmount = auctionedItem.stackSize; } } - if (itemAmount > 1) { - List toolTip = e.toolTip; - String superEnchantName = null; - - // starting with i=1 because first line is never the one we're looking for - for (int i = 1; i < toolTip.size(); i++) { - String toolTipLine = toolTip.get(i); - String toolTipLineUnformatted = EnumChatFormatting.getTextWithoutFormattingCodes(toolTipLine); - if (superEnchant != null && superEnchantName == null && (toolTipLineUnformatted.startsWith(superEnchant) || toolTipLineUnformatted.startsWith("Ultimate " + superEnchant))) { - int lastSpace = toolTipLine.lastIndexOf(' '); - if (lastSpace > 0) { - superEnchantName = toolTipLine.substring(0, lastSpace); - } - } - if (toolTipLineUnformatted.startsWith("Top bid: ") - || toolTipLineUnformatted.startsWith("Starting bid: ") - || toolTipLineUnformatted.startsWith("Item price: ") - || toolTipLineUnformatted.startsWith("Buy it now: ") - || toolTipLineUnformatted.startsWith("Sold for: ") - || toolTipLineUnformatted.startsWith("New bid: ") /* special case: 'Submit Bid' item */) { + if (itemAmount <= 1) return; + + List toolTip = e.toolTip; + + // starting with i=1 because first line is never the one we're looking for + for (int i = 1; i < toolTip.size(); i++) { + String toolTipLine = toolTip.get(i); + String toolTipLineUnformatted = EnumChatFormatting.getTextWithoutFormattingCodes(toolTipLine); + if (toolTipLineUnformatted.startsWith("Top bid: ") + || toolTipLineUnformatted.startsWith("Starting bid: ") + || toolTipLineUnformatted.startsWith("Item price: ") + || toolTipLineUnformatted.startsWith("Buy it now: ") + || toolTipLineUnformatted.startsWith("Sold for: ") + || toolTipLineUnformatted.startsWith("New bid: ") /* special case: 'Submit Bid' item */ + || (enchantmentName != null && (toolTipLineUnformatted.startsWith("Buy price: ") || toolTipLineUnformatted.startsWith("Sell price: ")))) { - try { - String hopefullyAPrice = StringUtils.substringBetween(toolTipLineUnformatted, ": ", " coins"); - if (hopefullyAPrice == null) { - return; - } - long price = numberFormatter.parse(hopefullyAPrice).longValue(); - double priceEach = price / (double) itemAmount; - String formattedPriceEach = priceEach < 5000 ? numberFormatter.format(priceEach) : Utils.formatNumberWithAbbreviations(priceEach); - if (superEnchantName != null) { - toolTip.add(i + 1, EnumChatFormatting.YELLOW + " (≙ " + itemAmount + "x " + superEnchantName + " " + (MooConfig.useRomanNumerals() ? "I" : "1") + EnumChatFormatting.RESET + EnumChatFormatting.YELLOW + " for " + formattedPriceEach + " each)"); - } else { - String pricePerItem = EnumChatFormatting.YELLOW + " (" + formattedPriceEach + " each)"; - toolTip.set(i, toolTipLine + pricePerItem); - } + try { + String hopefullyAPrice = StringUtils.substringBetween(toolTipLineUnformatted, ": ", " coins"); + if (hopefullyAPrice == null) { return; - } catch (ParseException ex) { + } + long price = numberFormatter.parse(hopefullyAPrice).longValue(); + double priceEach = price / (double) itemAmount; + String formattedPriceEach = priceEach < 5000 ? numberFormatter.format(priceEach) : Utils.formatNumberWithAbbreviations(priceEach); + if (enchantmentName != null) { + toolTip.add(i + 1, EnumChatFormatting.YELLOW + " (≙ " + itemAmount + "x " + EnumChatFormatting.BLUE + enchantmentName + " " + (MooConfig.useRomanNumerals() ? "I" : "1") + EnumChatFormatting.RESET + EnumChatFormatting.YELLOW + " for " + formattedPriceEach + " each)"); + } else { + String pricePerItem = EnumChatFormatting.YELLOW + " (" + formattedPriceEach + " each)"; + toolTip.set(i, toolTipLine + pricePerItem); return; } + } catch (ParseException ex) { + return; } } } @@ -767,6 +721,48 @@ public class SkyBlockListener { return false; } + private Pair extractEnchantedBookInfo(GuiScreen currentScreen, ItemStack currentItem) { + if (!(currentScreen instanceof GuiChest) || currentItem.getItem() != Items.enchanted_book) { + return null; + } + + IInventory inventory = ((GuiChest) currentScreen).inventorySlots.getSlot(0).inventory; + String inventoryName = (inventory.hasCustomName() ? EnumChatFormatting.getTextWithoutFormattingCodes(inventory.getDisplayName().getUnformattedTextForChat()) : inventory.getName()); + String currentItemName = EnumChatFormatting.getTextWithoutFormattingCodes(currentItem.getDisplayName()); + + boolean shouldDisplayPriceEach = inventoryName.startsWith("Ultimate Enchantments ➜"); + if (!shouldDisplayPriceEach && inventoryName.startsWith("Enchantments ➜ ")) { + if (currentItemName.contains("Turbo-")) { + shouldDisplayPriceEach = true; + } else { + String currentItemNameNormalized = currentItemName.toLowerCase().replaceAll("[_ -]", ""); + for (String priceEachEnchantment : MooConfig.tooltipAuctionHousePriceEachEnchantments) { + if (currentItemNameNormalized.contains(priceEachEnchantment)) { + shouldDisplayPriceEach = true; + break; + } + } + } + } + if (!shouldDisplayPriceEach) return null; + + int lastSpace = currentItemName.lastIndexOf(' '); + + if (lastSpace < 0) return null; + String enchantmentLevelRaw = currentItemName.substring(lastSpace + 1); + int enchantmentLevel = MathHelper.parseIntWithDefault(enchantmentLevelRaw, Utils.convertRomanToArabic(enchantmentLevelRaw)); + if (enchantmentLevel < 1) return null; + // enchantment tier => amount of books needed + // I = 2^0 = 1 + // II = 2^1 = 2 + // III = 2^2 = 4 + // IV = 2^3 = 8 + // V = 2^4 = 16 + int itemAmount = (int) Math.pow(2, enchantmentLevel - 1); + String enchantmentName = currentItemName.substring(0, lastSpace); + return Pair.of(enchantmentName, itemAmount); + } + private int abbreviatedToLongNumber(String number) throws NumberInvalidException { try { number = number.replace(",", ""); diff --git a/src/main/resources/assets/cowlection/lang/en_US.lang b/src/main/resources/assets/cowlection/lang/en_US.lang index aa95c48..4bdf1e5 100644 --- a/src/main/resources/assets/cowlection/lang/en_US.lang +++ b/src/main/resources/assets/cowlection/lang/en_US.lang @@ -60,12 +60,12 @@ cowlection.config.showPetExp=§7Pets: §rShow pet exp cowlection.config.showPetExp.tooltip=Show pet exp?\n§7§oExp for max level pets §f§odon't §7§owork inside the pets menu (but in every other GUI)! cowlection.config.numeralSystem=Numeral system cowlection.config.numeralSystem.tooltip=Use Roman or Arabic numeral system?\nThis is currently used to display numbers for...\n ‣ §7command: §r/moo stalkSkyBlock\n ‣ §7command: §r/moo analyzeIsland\n ‣ Dungeon levels and floors -cowlection.config.tooltipAuctionHousePriceEach=§7Auction house: §rprice per item -cowlection.config.tooltipAuctionHousePriceEach.tooltip=Add price per item if multiple items are bought or sold?\nAlso add price for level 1 books for enchanted books with one single enchant. -cowlection.config.tooltipAuctionHousePriceEachEnchantments=§7AH: §rprice per lvl 1 enchantment +cowlection.config.tooltipAuctionHousePriceEach=§7AH/Bazaar: §rprice per item +cowlection.config.tooltipAuctionHousePriceEach.tooltip=§eAuction house\nAdd price per item if multiple items are bought or sold?\n\n§eBazaar\nConvert the prices of enchantment books to the price per book of the required level 1 books. +cowlection.config.tooltipAuctionHousePriceEachEnchantments=§7Bazaar: §rprice per lvl 1 enchantment cowlection.config.tooltipAuctionHousePriceEachEnchantments.tooltip=Breaks down the price of enchanted books with one higher-tiered enchantment into their potential level 1 book prices.\n§d§lUltimate§r and §eTurbo-Crop §renchantments are always included. Enchantments set in this config option get broken down additionally.\n§7Keep in mind that not all high-level enchantments can be created by combining lower level books! cowlection.config.auctionHouseMarkEndedAuctions=§7AH: §rmark sold/ended/expired auctions with... -cowlection.config.auctionHouseMarkEndedAuctions.tooltip=Add indicators to auctions that...\n ‣ sold: §aSold §ror §aS\n ‣ ended: §aEnded §ror §aE\n ‣ expired: §cExpired §ror §cE +cowlection.config.auctionHouseMarkEndedAuctions.tooltip=§eAuction house\nAdd indicators to auctions that...\n ‣ sold: §aSold §ror §aS\n ‣ ended: §aEnded §ror §aE\n ‣ expired: §cExpired §ror §cE cowlection.config.bazaarSellAllOrder=§7Bazaar: §rOrder 'Sell Inventory/Sacks Now' by... cowlection.config.bazaarSellAllOrder.tooltip=Order the Sell All tooltip inside the Bazaar by...\n ‣ price (sum)\n ‣ price (each)\n ‣ item amount\n ‣ or keep it unorderd cowlection.config.bazaarSellAllOrderAscDesc=§7Bazaar: §rOrder 'Sell Inventory/Sacks Now' from -- cgit