From 52aa971ea53d3540010d1aede2fe9885461ff8dd Mon Sep 17 00:00:00 2001 From: Cow Date: Tue, 25 Jul 2023 23:11:11 +0200 Subject: Fixed detection of bestiary overview GUI --- CHANGELOG.md | 1 + .../config/gui/MooConfigCategoryScrolling.java | 2 +- .../cowtipper/cowlection/data/BestiaryEntry.java | 16 ++++--- .../listener/skyblock/SkyBlockListener.java | 51 ++++++++++++++++++---- 4 files changed, 56 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f188998..156a1a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ All other features of Cowlection *do not* require an API key and thus should be - `/guild notifications` to toggle Guild notifications, or `/settings` → Personal Guild Settings → Guild Notifications ### Fixed +- Bestiary Overview (`/moo config bestiary` + `/be`): adapted tooltip detection for newly added bestiary entries - Pet exp in tooltips: fixed rare crash caused by unexpected NBT data typing - Bazaar: fixed "Show items left to buy/sell" for buy/sell orders 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 diff --git a/src/main/java/de/cowtipper/cowlection/config/gui/MooConfigCategoryScrolling.java b/src/main/java/de/cowtipper/cowlection/config/gui/MooConfigCategoryScrolling.java index d33e68c..b264bd4 100644 --- a/src/main/java/de/cowtipper/cowlection/config/gui/MooConfigCategoryScrolling.java +++ b/src/main/java/de/cowtipper/cowlection/config/gui/MooConfigCategoryScrolling.java @@ -59,7 +59,7 @@ public class MooConfigCategoryScrolling extends GuiListExtended { this.mc = mc; listEntriesPreviews = new TreeMap<>(); - newConfigOptions = Sets.newHashSet("tooltipAuctionHousePriceEach", "tooltipAuctionHousePriceEachEnchantments", "bazaarShowItemsLeft", "showPetExp", "dungOverlayEnabled", "dungSendPerformanceOnDeath", "dungSendPerformanceOnEndScreen"); + newConfigOptions = Sets.newHashSet("bestiaryOverviewOrder", "tooltipAuctionHousePriceEach", "tooltipAuctionHousePriceEachEnchantments", "bazaarShowItemsLeft", "showPetExp", "dungOverlayEnabled", "dungSendPerformanceOnDeath", "dungSendPerformanceOnEndScreen"); explanations = new HashMap<>(); listEntries = new ArrayList<>(); } diff --git a/src/main/java/de/cowtipper/cowlection/data/BestiaryEntry.java b/src/main/java/de/cowtipper/cowlection/data/BestiaryEntry.java index a6c78e7..956422c 100644 --- a/src/main/java/de/cowtipper/cowlection/data/BestiaryEntry.java +++ b/src/main/java/de/cowtipper/cowlection/data/BestiaryEntry.java @@ -40,6 +40,8 @@ public class BestiaryEntry { spacerChar = ' '; } + private boolean isMaxed; + public BestiaryEntry(String mobName, int currentKills, int killsGoal) { this.mobName = mobName; this.killsToGo = killsGoal - currentKills; @@ -61,14 +63,15 @@ public class BestiaryEntry { } /** - * Bestiary not unlocked yet + * Bestiary is maxed (when isMaxed=true), or has not been unlocked yet (when isMaxed=false) */ - public BestiaryEntry(String mobName) { + public BestiaryEntry(String mobName, boolean isMaxed) { this.mobName = mobName; mobNameWidth = -1; - killsToGo = Integer.MAX_VALUE; + killsToGo = Integer.MAX_VALUE - (isMaxed ? 0 : 1); killsGoal = -1; - percentageToGo = Integer.MAX_VALUE; + percentageToGo = Integer.MAX_VALUE - (isMaxed ? 0 : 1); + this.isMaxed = isMaxed; } public static void reinitialize(ItemStack triggerItem) { @@ -96,7 +99,10 @@ public class BestiaryEntry { } public String getFormattedOutput(boolean sortBestiaryOverviewByKills) { - if (percentageToGo == Integer.MAX_VALUE) { + if (isMaxed) { + return mobName + EnumChatFormatting.WHITE + ": maxed!"; + } + if (percentageToGo == Integer.MAX_VALUE - 1) { return mobName + EnumChatFormatting.GRAY + ": not unlocked yet"; } 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 0024b71..59d7a9e 100644 --- a/src/main/java/de/cowtipper/cowlection/listener/skyblock/SkyBlockListener.java +++ b/src/main/java/de/cowtipper/cowlection/listener/skyblock/SkyBlockListener.java @@ -71,10 +71,13 @@ public class SkyBlockListener { private static final Pattern ITEM_COUNT_SUFFIXED_PATTERN = Pattern.compile(" (?:§[0-9a-fl-or])*x\\d+$"); private static final Pattern PET_NAME_PATTERN = Pattern.compile("^§7\\[Lvl (\\d+)] (§[0-9a-f])"); private static final Pattern TIER_SUFFIX_PATTERN = Pattern.compile(" [IVX0-9]+$"); - // example: " §a42§7x §fLeather §7for §6436.8 coins" + /** + * example: " §a42§7x §fLeather §7for §6436.8 coins" + */ private static final Pattern BAZAAR_SELL_ALL_PATTERN = Pattern.compile("^(?:§[0-9a-fl-or])* (?:§[0-9a-fl-or])+([0-9,]+)(?:§[0-9a-fl-or])+x (?:§[0-9a-fl-or])+.+ (?:§[0-9a-fl-or])+for (?:§[0-9a-fl-or])+([0-9,.]+) coins$"); private static final Pattern BAZAAR_TARGET_AMOUNT_PATTERN = Pattern.compile("^O(?:ff|rd)er amount: ([\\d,]+)x$"); private static final Pattern BAZAAR_FILLED_PATTERN = Pattern.compile("^Filled: ([\\d,.k]+)/[\\d,.k]+ \\(?([\\d.]+)%[)!]$"); + private static final Pattern BESTIARY_GUI_TITLE_PATTERN = Pattern.compile("^(?:\\(\\d+/\\d+\\) )?(Bestiary|.+) ➜ (.+)$"); List bestiaryOverview = null; private final NumberFormat numberFormatter; private final Cowlection main; @@ -349,7 +352,8 @@ public class SkyBlockListener { ContainerChest chestContainer = (ContainerChest) ((GuiChest) currentScreen).inventorySlots; IInventory inventory = chestContainer.getLowerChestInventory(); - for (int slot = 0; slot < inventory.getSizeInventory(); slot++) { + invLoop: + for (int slot = 9; slot < inventory.getSizeInventory(); slot++) { // slot 9 = start with 2nd row ItemStack item = inventory.getStackInSlot(slot); if (item != null) { // slot + item @@ -357,19 +361,24 @@ public class SkyBlockListener { if (itemNbtDisplay != null && itemNbtDisplay.hasKey("Lore", Constants.NBT.TAG_LIST)) { NBTTagList loreList = itemNbtDisplay.getTagList("Lore", Constants.NBT.TAG_STRING); - if (loreList.tagCount() < 10 || !"§eClick to view!".equals(loreList.getStringTagAt(loreList.tagCount() - 1))) { + if (loreList.tagCount() < 8 || !"§eClick to view!".equals(loreList.getStringTagAt(loreList.tagCount() - 1))) { if (item.getItem() == Items.dye && item.getMetadata() == EnumDyeColor.GRAY.getDyeDamage()) { // mob hasn't been killed yet - bestiaryOverview.add(new BestiaryEntry(item.getDisplayName())); + bestiaryOverview.add(new BestiaryEntry(item.getDisplayName(), false)); } // not a bestiary icon with additional data continue; } + boolean hasProgressBar = false; for (int loreLineNr = 0; loreLineNr < loreList.tagCount(); ++loreLineNr) { String loreLineFormatted = loreList.getStringTagAt(loreLineNr); String loreLine = EnumChatFormatting.getTextWithoutFormattingCodes(loreLineFormatted); - if (loreLine.startsWith(" ")) { // bar to next level + if (loreLine.startsWith("Families Found")) { + // bestiary sub category, e.g. Fishing + bestiaryOverview = null; + break invLoop; + } else if (loreLine.startsWith(" ")) { // bar to next level try { String progress = loreLine.substring(loreLine.lastIndexOf(' ') + 1); int divider = progress.indexOf('/'); @@ -377,12 +386,16 @@ public class SkyBlockListener { bestiaryOverview.add(new BestiaryEntry(TIER_SUFFIX_PATTERN.matcher(item.getDisplayName()).replaceFirst(""), abbreviatedToLongNumber(progress.substring(0, divider)), abbreviatedToLongNumber(progress.substring(divider + 1)))); + hasProgressBar = true; break; } } catch (NumberInvalidException ignored) { } } } + if (!hasProgressBar) { + bestiaryOverview.add(new BestiaryEntry(item.getDisplayName(), true)); + } } } } @@ -392,10 +405,11 @@ public class SkyBlockListener { // bestiary overview preview in config gui BestiaryEntry.reinitialize(e.itemStack); bestiaryOverview = new ArrayList<>(); - bestiaryOverview.add(new BestiaryEntry(EnumChatFormatting.GREEN + "Cow", 1, 2)); + bestiaryOverview.add(new BestiaryEntry(EnumChatFormatting.GREEN + "Sheep", 1, 2)); bestiaryOverview.add(new BestiaryEntry(EnumChatFormatting.GREEN + "Pig", 1163, 2500)); bestiaryOverview.add(new BestiaryEntry(EnumChatFormatting.GREEN + "Chicken", 10800, 15000)); - bestiaryOverview.add(new BestiaryEntry(EnumChatFormatting.RED + "Farmhand")); + bestiaryOverview.add(new BestiaryEntry(EnumChatFormatting.RED + "Farmhand", false)); + bestiaryOverview.add(new BestiaryEntry(EnumChatFormatting.GREEN + "Cow", true)); } } else { isBestiaryOverviewVisible = false; @@ -701,7 +715,28 @@ public class SkyBlockListener { IInventory inventory = guiChest.inventorySlots.getSlot(0).inventory; String inventoryName = (inventory.hasCustomName() ? EnumChatFormatting.getTextWithoutFormattingCodes(inventory.getDisplayName().getUnformattedTextForChat()) : inventory.getName()); String hoveredItemName = EnumChatFormatting.getTextWithoutFormattingCodes(hoveredItem.getDisplayName()); - if (inventoryName.startsWith("Bestiary ➜ ") && inventoryName.endsWith(hoveredItemName)) { + + Matcher bestiaryGuiTitleMatcher = BESTIARY_GUI_TITLE_PATTERN.matcher(inventoryName); + if (bestiaryGuiTitleMatcher.matches() && hoveredItemName.startsWith(bestiaryGuiTitleMatcher.group(2))) { + if (!"Bestiary".equals(bestiaryGuiTitleMatcher.group(1))) { + // special Bestiary sub category (e.g. Fishing) + NBTTagCompound itemNbtDisplay = hoveredItem.getSubCompound("display", false); + if (itemNbtDisplay != null && itemNbtDisplay.hasKey("Lore", Constants.NBT.TAG_LIST)) { + boolean loreContainsFamiliesFound = false; + NBTTagList loreList = itemNbtDisplay.getTagList("Lore", Constants.NBT.TAG_STRING); + for (int loreLineNr = 0; loreLineNr < loreList.tagCount(); ++loreLineNr) { + String loreLineFormatted = loreList.getStringTagAt(loreLineNr); + String loreLine = EnumChatFormatting.getTextWithoutFormattingCodes(loreLineFormatted); + if (loreLine.startsWith("Families Found")) { + loreContainsFamiliesFound = true; + break; + } + } + if (!loreContainsFamiliesFound) { + return false; + } + } + } // bestiary overview is enabled and mouse is hovering over bestiary category item (with same name as category) BestiaryEntry.triggerItem = hoveredItem; return true; -- cgit