diff options
11 files changed, 97 insertions, 43 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 7fa5390..b458704 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Added - SkyBlock Dwarven Mines update: - Added new minions to `/m analyzeIslands` (Mithril + t12) +- `/moo stalkskyblock` additions: + - Added 'last profile save' + - Added Enchanting, Farming and Mining 51-60 + - Added missing Runecrafting 25 + +### Changed +- Refined the comma representation of large numbers abbreviated with k, m, b + +### Fixed +- Fixed issue with 'no dung class selected' ## [1.8.9-0.12.0] - 03.01.2021 ### Added diff --git a/src/main/java/de/cowtipper/cowlection/command/MooCommand.java b/src/main/java/de/cowtipper/cowlection/command/MooCommand.java index 3a12f46..f3b2962 100644 --- a/src/main/java/de/cowtipper/cowlection/command/MooCommand.java +++ b/src/main/java/de/cowtipper/cowlection/command/MooCommand.java @@ -481,11 +481,15 @@ public class MooCommand extends CommandBase { HySkyBlockStats.Profile.Dungeons dungeons = member.getDungeons(); boolean hasPlayedDungeons = dungeons != null && dungeons.hasPlayed(); if (hasPlayedDungeons) { - DataHelper.DungeonClass selectedClass = dungeons.getSelectedClass(); - MooChatComponent dungeonHover = new MooChatComponent("Dungeoneering").gold().bold(); - int selectedClassLevel = dungeons.getSelectedClassLevel(); - dungeonsComponent = new MooChatComponent.KeyValueChatComponent("Dungeoneering", selectedClass.getName() + " " + (MooConfig.useRomanNumerals() ? Utils.convertArabicToRoman(selectedClassLevel) : selectedClassLevel)) + + DataHelper.DungeonClass selectedClass = dungeons.getSelectedClass(); + String selectedDungClass = "" + EnumChatFormatting.GRAY + EnumChatFormatting.ITALIC + "no class selected"; + if (selectedClass != null) { + int selectedClassLevel = dungeons.getSelectedClassLevel(); + selectedDungClass = selectedClass.getName() + " " + (MooConfig.useRomanNumerals() ? Utils.convertArabicToRoman(selectedClassLevel) : selectedClassLevel); + } + dungeonsComponent = new MooChatComponent.KeyValueChatComponent("Dungeoneering", selectedDungClass) .setHover(dungeonHover); @@ -616,6 +620,10 @@ public class MooCommand extends CommandBase { sbStats.appendFreshSibling(new MooChatComponent.KeyValueChatComponent("Fairy Souls", (member.getFairySoulsCollected() >= 0) ? String.valueOf(member.getFairySoulsCollected()) : "API access disabled")); // profile age: sbStats.appendFreshSibling(new MooChatComponent.KeyValueChatComponent("Profile age", fancyFirstJoined.first()).setHover(new MooChatComponent.KeyValueTooltipComponent("Join date", (fancyFirstJoined.second() == null ? "today" : fancyFirstJoined.second())))); + // last save: + Pair<String, String> fancyLastSave = member.getFancyLastSave(); + sbStats.appendFreshSibling(new MooChatComponent.KeyValueChatComponent("Last save", fancyLastSave.first() + " ago").setHover(new MooChatComponent.KeyValueTooltipComponent("Last save", (fancyLastSave.second() == null ? "today" : fancyLastSave.second())) + .appendFreshSibling(new MooChatComponent("= last time " + stalkedPlayer.getName() + " has played SkyBlock.").white()))); main.getChatHelper().sendMessage(sbStats); } else { diff --git a/src/main/java/de/cowtipper/cowlection/data/HyPlayerData.java b/src/main/java/de/cowtipper/cowlection/data/HyPlayerData.java index 5a7c168..feca6ba 100644 --- a/src/main/java/de/cowtipper/cowlection/data/HyPlayerData.java +++ b/src/main/java/de/cowtipper/cowlection/data/HyPlayerData.java @@ -16,6 +16,7 @@ public class HyPlayerData { private long lastLogin; private long lastLogout; private String mostRecentGameType; + @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") private Map<String, Integer> achievements; /** diff --git a/src/main/java/de/cowtipper/cowlection/data/HySkyBlockStats.java b/src/main/java/de/cowtipper/cowlection/data/HySkyBlockStats.java index b65e48c..fb9fcff 100644 --- a/src/main/java/de/cowtipper/cowlection/data/HySkyBlockStats.java +++ b/src/main/java/de/cowtipper/cowlection/data/HySkyBlockStats.java @@ -126,6 +126,7 @@ public class HySkyBlockStats { private double experience_skill_taming = -1; private Map<String, SlayerBossDetails> slayer_bosses; private List<Pet> pets; + private JacobData jacob2; private Dungeons dungeons; /** @@ -138,6 +139,10 @@ public class HySkyBlockStats { return Utils.getDurationAsWords(first_join); } + public Pair<String, String> getFancyLastSave() { + return Utils.getDurationAsWords(last_save); + } + public double getCoinPurse() { return coin_purse; } @@ -149,10 +154,10 @@ public class HySkyBlockStats { public Map<XpTables.Skill, Integer> getSkills() { Map<XpTables.Skill, Integer> skills = new TreeMap<>(); if (experience_skill_farming >= 0) { - skills.put(XpTables.Skill.FARMING, XpTables.Skill.FARMING.getLevel(experience_skill_farming)); + skills.put(XpTables.Skill.FARMING, XpTables.Skill.FARMING.getLevel(experience_skill_farming, getMaxFarmingLevel())); } if (experience_skill_mining >= 0) { - skills.put(XpTables.Skill.MINING, XpTables.Skill.MINING.getLevel(experience_skill_mining)); + skills.put(XpTables.Skill.MINING, XpTables.Skill.MINING.getLevel(experience_skill_mining, 60)); } if (experience_skill_combat >= 0) { skills.put(XpTables.Skill.COMBAT, XpTables.Skill.COMBAT.getLevel(experience_skill_combat)); @@ -164,7 +169,7 @@ public class HySkyBlockStats { skills.put(XpTables.Skill.FISHING, XpTables.Skill.FISHING.getLevel(experience_skill_fishing)); } if (experience_skill_enchanting >= 0) { - skills.put(XpTables.Skill.ENCHANTING, XpTables.Skill.ENCHANTING.getLevel(experience_skill_enchanting)); + skills.put(XpTables.Skill.ENCHANTING, XpTables.Skill.ENCHANTING.getLevel(experience_skill_enchanting, 60)); } if (experience_skill_alchemy >= 0) { skills.put(XpTables.Skill.ALCHEMY, XpTables.Skill.ALCHEMY.getLevel(experience_skill_alchemy)); @@ -209,6 +214,14 @@ public class HySkyBlockStats { return null; } + public int getMaxFarmingLevel() { + int farmingLevelCap = 50; + if (jacob2 != null && jacob2.perks != null) { + farmingLevelCap += jacob2.perks.getOrDefault("farming_level_cap", 0); + } + return farmingLevelCap; + } + public List<String> getArmor() { NBTTagCompound nbt = inv_armor.getDecodedData(); List<String> armorList = new ArrayList<>(); @@ -270,6 +283,10 @@ public class HySkyBlockStats { } } + private static class JacobData { + private Map<String, Integer> perks; + } + public static class Dungeons { private Map<String, Type> dungeon_types; private Map<DataHelper.DungeonClass, ClassDetails> player_classes; diff --git a/src/main/java/de/cowtipper/cowlection/data/XpTables.java b/src/main/java/de/cowtipper/cowlection/data/XpTables.java index 158fb66..efa576a 100644 --- a/src/main/java/de/cowtipper/cowlection/data/XpTables.java +++ b/src/main/java/de/cowtipper/cowlection/data/XpTables.java @@ -62,6 +62,16 @@ public class XpTables { XP_TO_LEVEL.put(47472425, 48); XP_TO_LEVEL.put(51172425, 49); XP_TO_LEVEL.put(55172425, 50); + XP_TO_LEVEL.put(59472425, 51); + XP_TO_LEVEL.put(64072425, 52); + XP_TO_LEVEL.put(68972425, 53); + XP_TO_LEVEL.put(74172425, 54); + XP_TO_LEVEL.put(79672425, 55); + XP_TO_LEVEL.put(85472425, 56); + XP_TO_LEVEL.put(91572425, 57); + XP_TO_LEVEL.put(97972425, 58); + XP_TO_LEVEL.put(104672425, 59); + XP_TO_LEVEL.put(111672425, 60); XP_TO_LEVEL_ALTERNATIVE.put(0, 0); XP_TO_LEVEL_ALTERNATIVE.put(50, 1); @@ -88,7 +98,7 @@ public class XpTables { XP_TO_LEVEL_ALTERNATIVE.put(47850, 22); XP_TO_LEVEL_ALTERNATIVE.put(60100, 23); XP_TO_LEVEL_ALTERNATIVE.put(75400, 24); - + XP_TO_LEVEL_ALTERNATIVE.put(94450, 25); } Skill() { @@ -101,9 +111,17 @@ public class XpTables { public int getLevel(double exp) { if (alternativeXpFormula) { - return XP_TO_LEVEL_ALTERNATIVE.floorEntry((int) exp).getValue(); + return getLevel(exp, 25); } else { - return XP_TO_LEVEL.floorEntry((int) exp).getValue(); + return getLevel(exp, 50); + } + } + + public int getLevel(double exp, int maxLevel) { + if (alternativeXpFormula) { + return Math.min(XP_TO_LEVEL_ALTERNATIVE.floorEntry((int) exp).getValue(), maxLevel); + } else { + return Math.min(XP_TO_LEVEL.floorEntry((int) exp).getValue(), maxLevel); } } diff --git a/src/main/java/de/cowtipper/cowlection/listener/skyblock/DungeonsListener.java b/src/main/java/de/cowtipper/cowlection/listener/skyblock/DungeonsListener.java index 5f25fa7..63927c6 100644 --- a/src/main/java/de/cowtipper/cowlection/listener/skyblock/DungeonsListener.java +++ b/src/main/java/de/cowtipper/cowlection/listener/skyblock/DungeonsListener.java @@ -158,7 +158,7 @@ public class DungeonsListener { hasCustomGearScore = true; } if (!hasCustomGearScore) { - customGearScore.append("―"); + customGearScore.append(EnumChatFormatting.LIGHT_PURPLE).append("100%").append(EnumChatFormatting.DARK_GRAY).append(" (never has randomized stats)"); } if (showItemQualityAndFloor) { if (MooConfig.isDungItemQualityAtTop()) { diff --git a/src/main/java/de/cowtipper/cowlection/listener/skyblock/DungeonsPartyListener.java b/src/main/java/de/cowtipper/cowlection/listener/skyblock/DungeonsPartyListener.java index a0162d3..9df27c5 100644 --- a/src/main/java/de/cowtipper/cowlection/listener/skyblock/DungeonsPartyListener.java +++ b/src/main/java/de/cowtipper/cowlection/listener/skyblock/DungeonsPartyListener.java @@ -244,13 +244,16 @@ public class DungeonsPartyListener { continue; } DataHelper.DungeonClass selectedClass = dungeons.getSelectedClass(); - int selectedClassLevel = dungeons.getSelectedClassLevel(); - String classAndDungeonTypeInfo = selectedClass.getName() + " " + (MooConfig.useRomanNumerals() ? Utils.convertArabicToRoman(selectedClassLevel) : selectedClassLevel) - + dungeons.getDungeonTypesLevels(); + String noClassSelected = EnumChatFormatting.ITALIC + "no class selected"; + String classAndDungeonTypeInfo = noClassSelected; + if (selectedClass != null) { + int selectedClassLevel = dungeons.getSelectedClassLevel(); + classAndDungeonTypeInfo = selectedClass.getName() + " " + (MooConfig.useRomanNumerals() ? Utils.convertArabicToRoman(selectedClassLevel) : selectedClassLevel); + } + classAndDungeonTypeInfo += dungeons.getDungeonTypesLevels(); playerEntry.append(classAndDungeonTypeInfo); // insert class + dungeon type data into str: - String noClassSelected = EnumChatFormatting.ITALIC + "no class selected"; int start = playerTooltip.indexOf(noClassSelected); playerTooltip.replace(start, start + noClassSelected.length(), classAndDungeonTypeInfo); 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 632ffa1..12f5e48 100644 --- a/src/main/java/de/cowtipper/cowlection/listener/skyblock/SkyBlockListener.java +++ b/src/main/java/de/cowtipper/cowlection/listener/skyblock/SkyBlockListener.java @@ -309,12 +309,13 @@ public class SkyBlockListener { if ((tooltipAuctionHousePriceEachDisplay == MooConfig.Setting.ALWAYS || tooltipAuctionHousePriceEachDisplay == MooConfig.Setting.SPECIAL && MooConfig.isTooltipToggleKeyBindingPressed()) && (e.entityPlayer.openContainer instanceof ContainerChest || Minecraft.getMinecraft().currentScreen instanceof MooConfigGui)) { int stackSize = e.itemStack.stackSize; - if ((stackSize == 1 && !isSubmitBidItem(e.itemStack)) || e.toolTip.size() < 4) { + boolean isSubmitBidItem = isSubmitBidItem(e.itemStack); + if ((stackSize == 1 && !isSubmitBidItem) || e.toolTip.size() < 4) { // only 1 item or irrelevant tooltip - nothing to do here, abort! return; } - if (isSubmitBidItem(e.itemStack)) { + if (isSubmitBidItem) { // special case: "place bid on an item" interface ("Auction View") ItemStack auctionedItem = e.entityPlayer.openContainer.getInventory().get(13); if (auctionedItem == null || auctionedItem.stackSize == 1) { diff --git a/src/main/java/de/cowtipper/cowlection/search/GuiSearch.java b/src/main/java/de/cowtipper/cowlection/search/GuiSearch.java index f10e024..ae17d32 100644 --- a/src/main/java/de/cowtipper/cowlection/search/GuiSearch.java +++ b/src/main/java/de/cowtipper/cowlection/search/GuiSearch.java @@ -26,7 +26,6 @@ import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.exception.ExceptionUtils; import org.apache.commons.lang3.tuple.ImmutableTriple; import org.lwjgl.input.Keyboard; -import org.lwjgl.opengl.GL11; import java.awt.*; import java.io.File; @@ -416,7 +415,7 @@ public class GuiSearch extends GuiScreen { drawString(fontRendererObj, "Log file: ", 2, 2, 0xff888888); GlStateManager.pushMatrix(); float scaleFactor = 0.75f; - GL11.glScalef(scaleFactor, scaleFactor, scaleFactor); + GlStateManager.scale(scaleFactor, scaleFactor, 0); fontRendererObj.drawSplitString(EnumChatFormatting.GRAY + Utils.toRealPath(hoveredEntry.getFilePath()), 5, (int) ((4 + fontRendererObj.FONT_HEIGHT) * (1 / scaleFactor)), (int) ((GuiSearch.this.fieldSearchQuery.xPosition - 8) * (1 / scaleFactor)), 0xff888888); GlStateManager.popMatrix(); drawString(fontRendererObj, "Result: " + EnumChatFormatting.WHITE + (hoveredSearchResultId + 1) + EnumChatFormatting.RESET + "/" + EnumChatFormatting.WHITE + this.rawResults.size(), 8, 48, 0xff888888); diff --git a/src/main/java/de/cowtipper/cowlection/util/Utils.java b/src/main/java/de/cowtipper/cowlection/util/Utils.java index 20794b1..d5c846d 100644 --- a/src/main/java/de/cowtipper/cowlection/util/Utils.java +++ b/src/main/java/de/cowtipper/cowlection/util/Utils.java @@ -12,9 +12,7 @@ import java.io.File; import java.io.IOException; import java.nio.file.Path; import java.text.DecimalFormat; -import java.util.Comparator; -import java.util.LinkedHashMap; -import java.util.Map; +import java.util.*; import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -22,7 +20,14 @@ import java.util.stream.Collectors; public final class Utils { public static final Pattern VALID_UUID_PATTERN = Pattern.compile("^(\\w{8})-(\\w{4})-(\\w{4})-(\\w{4})-(\\w{12})$"); private static final Pattern VALID_USERNAME = Pattern.compile("^[\\w]{1,16}$"); - private static final char[] LARGE_NUMBERS = new char[]{'k', 'm', 'b', 't'}; + private static final NavigableMap<Double, Character> NUMBER_SUFFIXES = new TreeMap<>(); + + static { + NUMBER_SUFFIXES.put(1_000d, 'k'); + NUMBER_SUFFIXES.put(1_000_000d, 'm'); + NUMBER_SUFFIXES.put(1_000_000_000d, 'b'); + NUMBER_SUFFIXES.put(1_000_000_000_000d, 't'); + } private Utils() { } @@ -105,27 +110,19 @@ public final class Utils { } /** - * Formats a large number with abbreviations for each factor of a thousand (k, m, ...) - * - * @param number the number to format - * @return a String representing the number n formatted in a cool looking way. - * @see <a href="https://stackoverflow.com/a/4753866">Source</a> + * Formats a large number with abbreviations for each factor of a thousand (k, m, b, t) */ public static String formatNumberWithAbbreviations(double number) { - return formatNumberWithAbbreviations(number, 0); - } + if (number == Double.MIN_VALUE) return formatNumberWithAbbreviations(Double.MIN_VALUE + 1); + if (number < 0) return "-" + formatNumberWithAbbreviations(-number); + if (number < 1000) return "" + (long) number; + + Map.Entry<Double, Character> e = NUMBER_SUFFIXES.floorEntry(number); + Double divideBy = e.getKey(); + Character suffix = e.getValue(); - private static String formatNumberWithAbbreviations(double number, int iteration) { - @SuppressWarnings("IntegerDivisionInFloatingPointContext") double d = ((long) number / 100) / 10.0; - boolean isRound = (d * 10) % 10 == 0; // true if the decimal part is equal to 0 (then it's trimmed anyway) - // this determines the class, i.e. 'k', 'm' etc - // this decides whether to trim the decimals - // (int) d * 10 / 10 drops the decimal - return d < 1000 ? // this determines the class, i.e. 'k', 'm' etc - (d > 99.9 || isRound || d > 9.99 ? // this decides whether to trim the decimals - (int) d * 10 / 10 : d + "" // (int) d * 10 / 10 drops the decimal - ) + "" + LARGE_NUMBERS[iteration] - : formatNumberWithAbbreviations(d, iteration + 1); + DecimalFormat df = new DecimalFormat("#,##0.#"); + return df.format(number / divideBy) + suffix; } /** diff --git a/src/main/resources/assets/cowlection/lang/en_US.lang b/src/main/resources/assets/cowlection/lang/en_US.lang index 93fef62..ede0dda 100644 --- a/src/main/resources/assets/cowlection/lang/en_US.lang +++ b/src/main/resources/assets/cowlection/lang/en_US.lang @@ -63,9 +63,9 @@ cowlection.config.lookupPriceKeyBinding.tooltip=Hover over an item in any invent cowlection.config.lookupItemDirectly=Open website directly? cowlection.config.lookupItemDirectly.tooltip=Should the corresponding website be opened immediately (§a✔§r) or sent as a chat message (§c✘§r)? cowlection.config.showItemQualityAndFloor=Show item quality + obtained floor -cowlection.config.showItemQualityAndFloor.tooltip=Should the item quality (in %%) and the obtained floor be added to the dungeon items' tooltips?\n§e'top' replaces the default 'gear score' entry §rwhich normally includes reforges and essence upgrades. +cowlection.config.showItemQualityAndFloor.tooltip=Should the item quality (in %%) and the obtained floor be added to the dungeon items' tooltips? cowlection.config.dungItemQualityPos=Item quality + obtained floor position -cowlection.config.dungItemQualityPos.tooltip=Position of item quality and otained floor in dungeon item tooltips +cowlection.config.dungItemQualityPos.tooltip=Position of item quality and obtained floor in dungeon item tooltips\n§e'top' replaces the default 'gear score' entry §rwhich normally includes reforges and essence upgrades. cowlection.config.dungItemToolTipToggleKeyBinding=Key binding: Show dungeon item base stats cowlection.config.dungItemToolTipToggleKeyBinding.tooltip=Hold down this key to toggle dungeon item tooltip.\nDisplays the base stats of an item without reforges and without essence upgrades.\n\n§7§odisable key binding: §e§oset key binding to §lESC cowlection.config.dungSendPerformanceOnDeath=Send player deaths overview after each death? |