diff options
Diffstat (limited to 'src/main/java')
10 files changed, 191 insertions, 61 deletions
diff --git a/src/main/java/de/cowtipper/cowlection/Cowlection.java b/src/main/java/de/cowtipper/cowlection/Cowlection.java index 2d7a988..3709172 100644 --- a/src/main/java/de/cowtipper/cowlection/Cowlection.java +++ b/src/main/java/de/cowtipper/cowlection/Cowlection.java @@ -14,6 +14,7 @@ import de.cowtipper.cowlection.listener.ChatListener; import de.cowtipper.cowlection.listener.PlayerListener; import de.cowtipper.cowlection.util.ChatHelper; import de.cowtipper.cowlection.util.VersionChecker; +import net.minecraft.client.Minecraft; import net.minecraft.client.settings.KeyBinding; import net.minecraftforge.client.ClientCommandHandler; import net.minecraftforge.common.MinecraftForge; @@ -39,8 +40,8 @@ public class Cowlection { public static final String GITURL = "@GITURL@"; public static KeyBinding[] keyBindings; private static Cowlection instance; - private File configDir; private File modsDir; + private File modOutDir; private MooConfig config; private CredentialStorage moo; private FriendsHandler friendsHandler; @@ -59,7 +60,7 @@ public class Cowlection { chatHelper = new ChatHelper(); - this.configDir = new File(e.getModConfigurationDirectory(), MODID + File.separatorChar); + File configDir = new File(e.getModConfigurationDirectory(), MODID + File.separatorChar); if (!configDir.exists()) { configDir.mkdirs(); } @@ -93,6 +94,7 @@ public class Cowlection { public void postInit(FMLPostInitializationEvent e) { versionChecker = new VersionChecker(this); playerCache = new PlayerCache(); + modOutDir = new File(Minecraft.getMinecraft().mcDataDir, Cowlection.MODID.toLowerCase() + "_out"); } public MooConfig getConfig() { @@ -147,14 +149,18 @@ public class Cowlection { return chestTracker; } - public File getConfigDirectory() { - return configDir; - } - public File getModsDirectory() { return modsDir; } + public File getModOutDirectory() { + if (!modOutDir.exists() && !modOutDir.mkdirs()) { + // dir didn't exist and couldn't be created + return null; + } + return modOutDir; + } + public Logger getLogger() { return logger; } diff --git a/src/main/java/de/cowtipper/cowlection/command/MooCommand.java b/src/main/java/de/cowtipper/cowlection/command/MooCommand.java index 2849666..8bab5ee 100644 --- a/src/main/java/de/cowtipper/cowlection/command/MooCommand.java +++ b/src/main/java/de/cowtipper/cowlection/command/MooCommand.java @@ -14,7 +14,6 @@ import de.cowtipper.cowlection.config.gui.MooConfigGui; import de.cowtipper.cowlection.data.*; import de.cowtipper.cowlection.data.HySkyBlockStats.Profile.Pet; import de.cowtipper.cowlection.handler.DungeonCache; -import de.cowtipper.cowlection.listener.skyblock.DungeonsListener; import de.cowtipper.cowlection.listener.skyblock.DungeonsPartyListener; import de.cowtipper.cowlection.search.GuiSearch; import de.cowtipper.cowlection.util.*; @@ -139,7 +138,7 @@ public class MooCommand extends CommandBase { main.getConfig().theyOpenedTheConfigGui(); displayGuiScreen(new MooConfigGui(buildString(args, 1))); } else if (args[0].equalsIgnoreCase("search")) { - displayGuiScreen(new GuiSearch(main.getConfigDirectory(), CommandBase.buildString(args, 1))); + displayGuiScreen(new GuiSearch(CommandBase.buildString(args, 1))); } else if (args[0].equalsIgnoreCase("guiscale")) { handleGuiScale(args); } else if (args[0].equalsIgnoreCase("rr")) { diff --git a/src/main/java/de/cowtipper/cowlection/config/MooConfig.java b/src/main/java/de/cowtipper/cowlection/config/MooConfig.java index ea980d0..f636559 100644 --- a/src/main/java/de/cowtipper/cowlection/config/MooConfig.java +++ b/src/main/java/de/cowtipper/cowlection/config/MooConfig.java @@ -60,6 +60,7 @@ public class MooConfig { private static final String CATEGORY_LOGS_SEARCH = "logssearch"; public static String[] logsDirs; private static String defaultStartDate; + private static int maxLogFileSize; // Category: Notifications public static boolean doUpdateCheck; public static boolean showBestFriendNotifications; @@ -85,6 +86,7 @@ public class MooConfig { public static String[] tooltipAuctionHousePriceEachEnchantments; private static String auctionHouseMarkEndedAuctions; public static String bazaarSellAllOrder; + public static String bazaarSellAllOrderAscDesc; private static String bazaarConnectGraphsNodes; public static int bazaarConnectGraphsLineWidth; public static String bestiaryOverviewOrder; @@ -95,9 +97,11 @@ public class MooConfig { // Category: SkyBlock Dungeons private static String showItemQualityAndFloor; private static String dungItemQualityPos; + public static boolean dungItemQualityShortenNonRandomized; public static boolean dungItemHideGearScore; public static int dungItemToolTipToggleKeyBinding; public static boolean dungSendPerformanceOnDeath; + public static boolean dungSendPerformanceOnEndScreen; public static boolean dungOverlayEnabled; public static int dungOverlayPositionX; public static int dungOverlayPositionY; @@ -117,6 +121,7 @@ public class MooConfig { private static String dungMarkPartiesWithHealer; private static String dungMarkPartiesWithMage; private static String dungMarkPartiesWithTank; + public static boolean dungSendWrongFloorWarning; private static Configuration cfg = null; private static final List<MooConfigCategory> configCategories = new ArrayList<>(); @@ -310,9 +315,12 @@ public class MooConfig { Property propDefaultStartDate = subCat.addConfigEntry(cfg.get(CATEGORY_LOGS_SEARCH, "defaultStartDate", "3", "Default start date (a number means X months ago, alternatively a fixed date à la yyyy-mm-dd can be used)")) .setValidationPattern(Pattern.compile("^[1-9][0-9]{0,2}|(2[0-9]{3}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01]))$")); + Property propMaxLogFileSize = subCat.addConfigEntry(cfg.get(CATEGORY_LOGS_SEARCH, + "maxLogFileSize", 2048, "Max log file size (in KB)?", 50, 10000)); logSearchProperties = new ArrayList<>(); logSearchProperties.add(propLogsDirs); logSearchProperties.add(propDefaultStartDate); + logSearchProperties.add(propMaxLogFileSize); // Category: Notifications configCat = new MooConfigCategory("Notifications", "notifications"); @@ -443,6 +451,9 @@ public class MooConfig { "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()))); + Property propBazaarSellAllOrderAscDesc = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), + "bazaarSellAllOrderAscDesc", "low → high", "Bazaar: sell all order asc/desc", new String[]{"low → high", "high → low"})); + MooConfigPreview bazaarGraphPreview = new MooConfigPreview(MooConfigPreview.createDemoItem("paper", "§aBuy Price §731d §77d §e24h", new String[]{ "§7The price at which buy orders have been filled.", "", "§r┌----------------------------------------------┐", "§r│§66. 1k§r+§bxxxxxx§8·································§bxx§r│", @@ -506,6 +517,9 @@ public class MooConfig { MooConfigPreview.createDungeonItem("light", "7/17/20 7:22 PM", "§7Gear Score: §d336 §8(526)", "§7Crit Chance: §c+5% §9(Light +2%)", "§7Crit Damage: §c+30% §9(Light +4%) §8(+48.9%)", "§7Bonus Attack Speed: §c+4% §9(Light +4%)", "", "§7Health: §a+126 HP §9(Light +15 HP) §8(+205.38 HP)", "§7Defense: §a+76 §9(Light +4) §8(+123.88)", "§7Speed: §a+4 §9(Light +4) §8(+6.52)", "", "§9Growth V, §9Protection V", "§9Thorns III", "", "§7Increase the damage you deal", "§7with arrows by §c5%§7.", "", "§6Full Set Bonus: Skeleton Soldier", "§7Increase the damage you deal", "§7with arrows by an extra §c25%§7.", "", "§aPerfect 52500 / 52500", "§5§lEPIC DUNGEON LEGGINGS"), MooConfigPreview.createDungeonItem("clean", "7/11/20 12:27 PM", "§7Gear Score: §d359 §8(561)", "§7Crit Chance: §c+11% §9(Clean +8%)", "§7Crit Damage: §c+26% §8(+42.38%)", "", "§7Health: §a+126 HP §9(Clean +15 HP) §8(+205.38 HP)", "§7Defense: §a+87 §9(Clean +15) §8(+141.81)", "", "§9Growth V, §9Protection V", "§9Thorns III", "", "§7Increase the damage you deal", "§7with arrows by §c5%§7.", "", "§6Full Set Bonus: Skeleton Soldier", "§7Increase the damage you deal", "§7with arrows by an extra §c25%§7.", "", "§aPerfect 52500 / 52500", "§5§lEPIC DUNGEON LEGGINGS"))); + Property propDungItemQualityShortenNonRandomized = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), + "dungItemQualityShortenNonRandomized", false, "Shorten item quality for non-randomized items?")); + Property propDungItemHideGearScore = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), "dungItemHideGearScore", false, "Hide Gear Score?")); @@ -523,6 +537,9 @@ public class MooConfig { Property propDungSendPerformanceOnDeath = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), "dungSendPerformanceOnDeath", true, "Send dungeon performance after a player died?")); + Property propDungSendPerformanceOnEndScreen = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), + "dungSendPerformanceOnEndScreen", true, "Send dungeon performance on end screen?")); + Property propDungOverlayEnabled = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), "dungOverlayEnabled", true, "Enable Dungeon performance overlay?")); @@ -624,6 +641,9 @@ public class MooConfig { "dungMarkPartiesWithTank", "do not mark", "Mark parties with Tank class?", new String[]{"always", "if duplicated", "do not mark"}), new MooConfigPreview(DataHelper.DungeonClass.TANK)); + Property propDungSendWrongFloorWarning = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), + "dungSendWrongFloorWarning", true, "Send warning when entering wrong floor?")); + boolean modifiedMooCmdAlias = false; String mooCmdAliasPreChange = mooCmdAlias; boolean modifiedTabCompletableCommandsList = false; @@ -642,6 +662,7 @@ public class MooConfig { tabCompletableNamesCommands = propTabCompletableNamesCommands.getStringList(); logsDirs = propLogsDirs.getStringList(); defaultStartDate = propDefaultStartDate.getString().trim(); + maxLogFileSize = propMaxLogFileSize.getInt(); // Category: Notifications doUpdateCheck = propDoUpdateCheck.getBoolean(); showBestFriendNotifications = propShowBestFriendNotifications.getBoolean(); @@ -667,6 +688,7 @@ public class MooConfig { tooltipAuctionHousePriceEachEnchantments = propTooltipAuctionHousePriceEachEnchantments.getStringList(); auctionHouseMarkEndedAuctions = propAuctionHouseMarkEndedAuctions.getString(); bazaarSellAllOrder = propBazaarSellAllOrder.getString(); + bazaarSellAllOrderAscDesc = propBazaarSellAllOrderAscDesc.getString(); bazaarConnectGraphsNodes = propBazaarConnectGraphsNodes.getString(); bazaarConnectGraphsLineWidth = propBazaarConnectGraphsLineWidth.getInt(); bestiaryOverviewOrder = propBestiaryOverviewOrder.getString(); @@ -676,9 +698,11 @@ public class MooConfig { // Category: SkyBlock Dungeons showItemQualityAndFloor = propShowItemQualityAndFloor.getString(); dungItemQualityPos = propDungItemQualityPos.getString(); + dungItemQualityShortenNonRandomized = propDungItemQualityShortenNonRandomized.getBoolean(); dungItemHideGearScore = propDungItemHideGearScore.getBoolean(); dungItemToolTipToggleKeyBinding = propDungItemToolTipToggleKeyBinding.getInt(); dungSendPerformanceOnDeath = propDungSendPerformanceOnDeath.getBoolean(); + dungSendPerformanceOnEndScreen = propDungSendPerformanceOnEndScreen.getBoolean(); dungOverlayEnabled = propDungOverlayEnabled.getBoolean(); dungOverlayPositionX = propDungOverlayPositionX.getInt(); dungOverlayPositionY = propDungOverlayPositionY.getInt(); @@ -698,6 +722,7 @@ public class MooConfig { dungMarkPartiesWithHealer = propDungMarkPartiesWithHealer.getString(); dungMarkPartiesWithMage = propDungMarkPartiesWithMage.getString(); dungMarkPartiesWithTank = propDungMarkPartiesWithTank.getString(); + dungSendWrongFloorWarning = propDungSendWrongFloorWarning.getBoolean(); if (!hasOpenedConfigGui && (!propDungOverlayEnabled.isDefault() || !propDungOverlayPositionX.isDefault() || !propDungOverlayPositionY.isDefault() || !propDungOverlayGuiScale.isDefault())) { // player hasn't opened config gui yet and but already moved the dungeon overlay @@ -725,6 +750,7 @@ public class MooConfig { propTabCompletableNamesCommands.set(tabCompletableNamesCommands); propLogsDirs.set(logsDirs); propDefaultStartDate.set(defaultStartDate); + propMaxLogFileSize.set(maxLogFileSize); // Category: Notifications propDoUpdateCheck.set(doUpdateCheck); propShowBestFriendNotifications.set(showBestFriendNotifications); @@ -750,6 +776,7 @@ public class MooConfig { propTooltipAuctionHousePriceEachEnchantments.set(tooltipAuctionHousePriceEachEnchantments); propAuctionHouseMarkEndedAuctions.set(auctionHouseMarkEndedAuctions); propBazaarSellAllOrder.set(bazaarSellAllOrder); + propBazaarSellAllOrderAscDesc.set(bazaarSellAllOrderAscDesc); propBazaarConnectGraphsNodes.set(bazaarConnectGraphsNodes); propBazaarConnectGraphsLineWidth.set(bazaarConnectGraphsLineWidth); propBestiaryOverviewOrder.set(bestiaryOverviewOrder); @@ -759,9 +786,11 @@ public class MooConfig { // Category: SkyBlock Dungeons propShowItemQualityAndFloor.set(showItemQualityAndFloor); propDungItemQualityPos.set(dungItemQualityPos); + propDungItemQualityShortenNonRandomized.set(dungItemQualityShortenNonRandomized); propDungItemHideGearScore.set(dungItemHideGearScore); propDungItemToolTipToggleKeyBinding.set(dungItemToolTipToggleKeyBinding); propDungSendPerformanceOnDeath.set(dungSendPerformanceOnDeath); + propDungSendPerformanceOnEndScreen.set(dungSendPerformanceOnEndScreen); propDungOverlayEnabled.set(dungOverlayEnabled); propDungOverlayPositionX.set(dungOverlayPositionX); propDungOverlayPositionY.set(dungOverlayPositionY); @@ -781,6 +810,7 @@ public class MooConfig { propDungMarkPartiesWithHealer.set(dungMarkPartiesWithHealer); propDungMarkPartiesWithMage.set(dungMarkPartiesWithMage); propDungMarkPartiesWithTank.set(dungMarkPartiesWithTank); + propDungSendWrongFloorWarning.set(dungSendWrongFloorWarning); if (saveToFile && cfg.hasChanged()) { boolean isPlayerIngame = Minecraft.getMinecraft().thePlayer != null; @@ -870,6 +900,13 @@ public class MooConfig { return logsDirs.toArray(new String[]{}); } + /** + * @return max log file size in Bytes + */ + public static long getMaxLogFileSize() { + return maxLogFileSize * 1024L; + } + // Category: General public static Setting getConfigGuiExplanationsDisplay() { return Setting.get(configGuiExplanations); 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 dedf163..a3b28e6 100644 --- a/src/main/java/de/cowtipper/cowlection/config/gui/MooConfigCategoryScrolling.java +++ b/src/main/java/de/cowtipper/cowlection/config/gui/MooConfigCategoryScrolling.java @@ -89,7 +89,7 @@ public class MooConfigCategoryScrolling extends GuiListExtended { // add control buttons to navigate to other guis if ("Other settings".equals(subCategory.getDisplayName())) { this.listEntries.add(new GuiSwitchEntry("gotoKeyBindings", "Controls", () -> mc.displayGuiScreen(new GuiControls(MooConfigCategoryScrolling.this.parent, mc.gameSettings)))); - this.listEntries.add(new GuiSwitchEntry("gotoLogSearchConfig", "Log Search", () -> mc.displayGuiScreen(new GuiSearch(Cowlection.getInstance().getConfigDirectory(), "")))); + this.listEntries.add(new GuiSwitchEntry("gotoLogSearchConfig", "Log Search", () -> mc.displayGuiScreen(new GuiSearch("")))); continue; // don't add properties to main config gui } @@ -215,7 +215,7 @@ public class MooConfigCategoryScrolling extends GuiListExtended { if (labelWidth > this.maxListLabelWidth) { this.maxListLabelWidth = labelWidth; } - this.listEntries.add(new GuiSwitchEntry("gotoLogSearchConfig", "Log Search", () -> mc.displayGuiScreen(new GuiSearch(Cowlection.getInstance().getConfigDirectory(), "")))); + this.listEntries.add(new GuiSwitchEntry("gotoLogSearchConfig", "Log Search", () -> mc.displayGuiScreen(new GuiSearch("")))); hasLogSearchBeenAdded = true; } else if (hasLogSearchBeenAdded) { // already added the replacement-entry, thus don't increase entry counter 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 9ae5d7e..009d694 100644 --- a/src/main/java/de/cowtipper/cowlection/listener/skyblock/DungeonsListener.java +++ b/src/main/java/de/cowtipper/cowlection/listener/skyblock/DungeonsListener.java @@ -31,7 +31,8 @@ import net.minecraftforge.client.event.GuiScreenEvent; import net.minecraftforge.client.event.RenderGameOverlayEvent; import net.minecraftforge.common.util.Constants; import net.minecraftforge.event.entity.player.ItemTooltipEvent; -import net.minecraftforge.fml.common.eventhandler.*; +import net.minecraftforge.fml.common.eventhandler.EventPriority; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.gameevent.TickEvent; import net.minecraftforge.fml.relauncher.Side; import org.lwjgl.input.Mouse; @@ -160,7 +161,11 @@ public class DungeonsListener { hasCustomGearScore = true; } if (!hasCustomGearScore) { - customGearScore.append(EnumChatFormatting.LIGHT_PURPLE).append("100%").append(EnumChatFormatting.DARK_GRAY).append(" (never has randomized stats)"); + if (MooConfig.dungItemQualityShortenNonRandomized) { + customGearScore.append(EnumChatFormatting.DARK_PURPLE).append("100%"); + } else { + customGearScore.append(EnumChatFormatting.LIGHT_PURPLE).append("100%").append(EnumChatFormatting.DARK_GRAY).append(" (never has randomized stats)"); + } } if (showItemQualityAndFloor) { if (MooConfig.isDungItemQualityAtTop()) { @@ -470,23 +475,23 @@ public class DungeonsListener { if (text.startsWith("[NPC] Mort: ")) { // Mort said something, probably entered dungeons main.getDungeonCache().onDungeonEnterOrLeave(true); - return; - } - Matcher dungeonEnteredMatcher = DUNGEON_ENTERED_DUNGEON.matcher(text); - if (dungeonEnteredMatcher.matches()) { - String floor = dungeonEnteredMatcher.group(1) != null ? "Entrance" : dungeonEnteredMatcher.group(2); - if (floor == null) { - // this shouldn't ever happen: neither a floor nor the entrance was entered - return; - } - String queuedFloor = main.getDungeonCache().getQueuedFloor(); - if (queuedFloor != null && !queuedFloor.equals(floor)) { - // queued and entered dungeon floors are different! - new TickDelay(() -> { - String attentionSeeker = "" + EnumChatFormatting.LIGHT_PURPLE + EnumChatFormatting.OBFUSCATED + "#"; - main.getChatHelper().sendMessage(EnumChatFormatting.RED, attentionSeeker + EnumChatFormatting.RED + " You entered dungeon floor " + EnumChatFormatting.DARK_RED + floor + EnumChatFormatting.RED + " but originally queued for floor " + EnumChatFormatting.DARK_RED + queuedFloor + " " + attentionSeeker); - Minecraft.getMinecraft().thePlayer.playSound("mob.cow.hurt", Minecraft.getMinecraft().gameSettings.getSoundLevel(SoundCategory.MASTER), 1); - }, 100); + } else if (MooConfig.dungSendWrongFloorWarning) { + Matcher dungeonEnteredMatcher = DUNGEON_ENTERED_DUNGEON.matcher(text); + if (dungeonEnteredMatcher.matches()) { + String floor = dungeonEnteredMatcher.group(1) != null ? "Entrance" : dungeonEnteredMatcher.group(2); + if (floor == null) { + // this shouldn't ever happen: neither a floor nor the entrance was entered + return; + } + String queuedFloor = main.getDungeonCache().getQueuedFloor(); + if (queuedFloor != null && !queuedFloor.equals(floor)) { + // queued and entered dungeon floors are different! + new TickDelay(() -> { + String attentionSeeker = "" + EnumChatFormatting.LIGHT_PURPLE + EnumChatFormatting.OBFUSCATED + "#"; + main.getChatHelper().sendMessage(EnumChatFormatting.RED, attentionSeeker + EnumChatFormatting.RED + " You entered dungeon floor " + EnumChatFormatting.DARK_RED + floor + EnumChatFormatting.RED + " but originally queued for floor " + EnumChatFormatting.DARK_RED + queuedFloor + " " + attentionSeeker); + Minecraft.getMinecraft().thePlayer.playSound("mob.cow.hurt", Minecraft.getMinecraft().gameSettings.getSoundLevel(SoundCategory.MASTER), 1); + }, 100); + } } } return; @@ -504,7 +509,9 @@ public class DungeonsListener { main.getDungeonCache().revivedPlayer(dungeonRevivedMatcher.group(1)); } else if (text.trim().equals("> EXTRA STATS <")) { // dungeon "end screen" - new TickDelay(() -> main.getDungeonCache().sendDungeonPerformance(), 5); + if (MooConfig.dungSendPerformanceOnEndScreen) { + new TickDelay(() -> main.getDungeonCache().sendDungeonPerformance(), 5); + } } else if (text.startsWith("PUZZLE FAIL!")) { // Skill: failed puzzle main.getDungeonCache().addFailedPuzzle(text); 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 a28905c..432489b 100644 --- a/src/main/java/de/cowtipper/cowlection/listener/skyblock/SkyBlockListener.java +++ b/src/main/java/de/cowtipper/cowlection/listener/skyblock/SkyBlockListener.java @@ -421,7 +421,11 @@ public class SkyBlockListener { numberFormatter.setMaximumFractionDigits(1); List<String> toolTip = e.toolTip; int startIndex = 1337; - TreeMultimap<Double, String> sellEntries = TreeMultimap.create(Ordering.natural().reverse(), Ordering.natural()); + Ordering<Double> tooltipOrdering = Ordering.natural(); + if("high → low".equals(MooConfig.bazaarSellAllOrderAscDesc)) { + tooltipOrdering = tooltipOrdering.reverse(); + } + TreeMultimap<Double, String> sellEntries = TreeMultimap.create(tooltipOrdering, Ordering.natural()); for (int i = 0; i < toolTip.size(); i++) { Matcher bazaarSellMatcher = BAZAAR_SELL_ALL_PATTERN.matcher(toolTip.get(i)); if (bazaarSellMatcher.matches()) { diff --git a/src/main/java/de/cowtipper/cowlection/search/GuiSearch.java b/src/main/java/de/cowtipper/cowlection/search/GuiSearch.java index 21059ca..7e721a9 100644 --- a/src/main/java/de/cowtipper/cowlection/search/GuiSearch.java +++ b/src/main/java/de/cowtipper/cowlection/search/GuiSearch.java @@ -23,7 +23,6 @@ import net.minecraftforge.fml.client.config.IConfigElement; import net.minecraftforge.fml.relauncher.ReflectionHelper; 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 java.awt.*; @@ -79,10 +78,11 @@ public class GuiSearch extends GuiScreen { private boolean isSearchInProgress; private String analyzedFiles; private String analyzedFilesWithHits; + private String skippedFiles; private boolean areEntriesSearchResults; - public GuiSearch(File configDirectory, String initialSearchQuery) { - this.mcLogOutputFile = new File(configDirectory, "mc-log.txt"); + public GuiSearch(String initialSearchQuery) { + this.mcLogOutputFile = new File(Cowlection.getInstance().getModOutDirectory(), "cowlection-mc-log-search-temp.txt"); try { mcLogOutputFile.createNewFile(); } catch (IOException e) { @@ -287,19 +287,21 @@ public class GuiSearch extends GuiScreen { executorService.execute(() -> { try { - ImmutableTriple<Integer, Integer, List<LogEntry>> searchResultsData = new LogFilesSearcher().searchFor(this.fieldSearchQuery.getText(), checkboxChatOnly.isChecked(), checkboxMatchCase.isChecked(), checkboxRemoveFormatting.isChecked(), dateStart, dateEnd); - this.searchResults = searchResultsData.right; - this.analyzedFiles = "Analyzed files: " + EnumChatFormatting.WHITE + searchResultsData.left; - this.analyzedFilesWithHits = "Files with hits: " + EnumChatFormatting.WHITE + searchResultsData.middle; + LogSearchResults searchResultsData = new LogFilesSearcher().searchFor(this.fieldSearchQuery.getText(), checkboxChatOnly.isChecked(), checkboxMatchCase.isChecked(), checkboxRemoveFormatting.isChecked(), dateStart, dateEnd); + this.searchResults = searchResultsData.getSortedSearchResults(); + this.analyzedFiles = "Analyzed files: " + EnumChatFormatting.WHITE + searchResultsData.getAnalyzedFiles(); + this.analyzedFilesWithHits = "Files with hits: " + EnumChatFormatting.WHITE + searchResultsData.getAnalyzedFilesWithHits(); + this.skippedFiles = "Skipped files: " + EnumChatFormatting.WHITE + searchResultsData.getSkippedFiles(); if (this.searchResults.isEmpty()) { this.searchResults.add(new LogEntry(EnumChatFormatting.ITALIC + "No results")); areEntriesSearchResults = false; } else { - areEntriesSearchResults = true; + areEntriesSearchResults = searchResultsData.getAnalyzedFiles() != 0; } } catch (IOException e) { if (e.getStackTrace().length > 0) { searchResults.add(new LogEntry(StringUtils.replaceEach(ExceptionUtils.getStackTrace(e), new String[]{"\t", "\r\n"}, new String[]{" ", "\n"}))); + areEntriesSearchResults = false; } } Minecraft.getMinecraft().addScheduledTask(() -> { @@ -319,6 +321,9 @@ public class GuiSearch extends GuiScreen { this.searchResults.add(new LogEntry("" + EnumChatFormatting.GOLD + EnumChatFormatting.BOLD + "Initial setup/configuration " + EnumChatFormatting.GRAY + EnumChatFormatting.ITALIC + "'Open Settings' (top right corner)")); this.searchResults.add(new LogEntry(EnumChatFormatting.GOLD + " 1) " + EnumChatFormatting.RESET + "Configure directories that should be scanned for log files (\"Directories with Minecraft log files\")")); this.searchResults.add(new LogEntry(EnumChatFormatting.GOLD + " 2) " + EnumChatFormatting.RESET + "Set default starting date (\"Start date for log file search\")")); + this.searchResults.add(new LogEntry(" ‣ can be a number (e.g. \"3\" means \"start searching 3 months ago\")")); + this.searchResults.add(new LogEntry(" ‣ or alternatively a fixed date (yyyy-mm-dd)")); + this.searchResults.add(new LogEntry(EnumChatFormatting.GOLD + " 3) " + EnumChatFormatting.RESET + "optional: change the maximum allowed log file size to be searched, but note that each log file must be unzipped before it can be analyzed, which can make the log file search take significantly longer for large files")); this.searchResults.add(new LogEntry("" + EnumChatFormatting.GOLD + EnumChatFormatting.BOLD + "Performing a search " + EnumChatFormatting.GRAY + EnumChatFormatting.ITALIC + "/moo search [initial search term]")); this.searchResults.add(new LogEntry(EnumChatFormatting.GOLD + " 1) " + EnumChatFormatting.RESET + "Enter search term")); this.searchResults.add(new LogEntry(EnumChatFormatting.GOLD + " 2) " + EnumChatFormatting.RESET + "Adjust start and end date")); @@ -360,6 +365,7 @@ public class GuiSearch extends GuiScreen { guiSearchResults.clearResults(); analyzedFiles = null; analyzedFilesWithHits = null; + skippedFiles = null; } else { buttonSearch.displayString = "Search"; } @@ -441,13 +447,16 @@ public class GuiSearch extends GuiScreen { } } else if (areEntriesSearchResults) { if (analyzedFiles != null) { - drawString(fontRendererObj, analyzedFiles, 8, 22, 0xff888888); + drawString(fontRendererObj, analyzedFiles, 8, 15, 0xff888888); } if (analyzedFilesWithHits != null) { - drawString(fontRendererObj, analyzedFilesWithHits, 8, 32, 0xff888888); + drawString(fontRendererObj, analyzedFilesWithHits, 8, 25, 0xff888888); + } + if (skippedFiles != null) { + drawString(fontRendererObj, skippedFiles, 8, 35, 0xff888888); } if (resultsCount != null) { - drawString(fontRendererObj, resultsCount, 8, 48, 0xff888888); + drawString(fontRendererObj, resultsCount, 8, 50, 0xff888888); } } if (errorMessage != null) { diff --git a/src/main/java/de/cowtipper/cowlection/search/LogFilesSearcher.java b/src/main/java/de/cowtipper/cowlection/search/LogFilesSearcher.java index c6b647e..bbfd0fb 100644 --- a/src/main/java/de/cowtipper/cowlection/search/LogFilesSearcher.java +++ b/src/main/java/de/cowtipper/cowlection/search/LogFilesSearcher.java @@ -2,18 +2,15 @@ package de.cowtipper.cowlection.search; import de.cowtipper.cowlection.config.MooConfig; import net.minecraft.util.EnumChatFormatting; +import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.tuple.ImmutableTriple; import java.io.*; import java.nio.file.Files; import java.nio.file.Path; import java.time.*; import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -32,9 +29,9 @@ class LogFilesSearcher { private static final Pattern LOG4J_PATTERN = Pattern.compile("^\\[(?<timeHours>[\\d]{2}):(?<timeMinutes>[\\d]{2}):(?<timeSeconds>[\\d]{2})] \\[(?<thread>[^/]+)/(?<logLevel>[A-Z]+)]:(?<isChat> \\[CHAT])? (?<message>.*)$"); private int analyzedFilesWithHits = 0; - ImmutableTriple<Integer, Integer, List<LogEntry>> searchFor(String searchQuery, boolean chatOnly, boolean matchCase, boolean removeFormatting, LocalDate dateStart, LocalDate dateEnd) throws IOException { - AtomicInteger foundLogs = new AtomicInteger(); - List<LogEntry> searchResults = Collections.synchronizedList(new ArrayList<>()); + LogSearchResults searchFor(String searchQuery, boolean chatOnly, boolean matchCase, boolean removeFormatting, LocalDate dateStart, LocalDate dateEnd) throws IOException { + LogSearchResults logSearchResults = new LogSearchResults(); + long fileSizeLimit = MooConfig.getMaxLogFileSize(); for (String logsDirPath : MooConfig.logsDirs) { File logsDir = new File(logsDirPath); if (!logsDir.exists() || !logsDir.isDirectory()) { @@ -55,15 +52,25 @@ class LogFilesSearcher { LocalDate fileLocalDate = LocalDate.of(Integer.parseInt(fileNameMatcher.group(1)), Integer.parseInt(fileNameMatcher.group(2)), Integer.parseInt(fileNameMatcher.group(3))); if (!fileLocalDate.isBefore(dateStart) && !fileLocalDate.isAfter(dateEnd)) { - foundLogs.incrementAndGet(); - searchResults.addAll(analyzeFile(path, true, fileLocalDate, searchQuery, chatOnly, matchCase, removeFormatting)); + if (path.toFile().length() > fileSizeLimit) { + // file too large + logSearchResults.addSkippedFile(); + } else { + logSearchResults.addAnalyzedFile(); + logSearchResults.addSearchResults(analyzeFile(path, true, fileLocalDate, searchQuery, chatOnly, matchCase, removeFormatting)); + } } } } else if (fileName.equals("latest.log")) { LocalDate lastModified = Instant.ofEpochMilli(path.toFile().lastModified()).atZone(ZoneId.systemDefault()).toLocalDate(); if (!lastModified.isBefore(dateStart) && !lastModified.isAfter(dateEnd)) { - foundLogs.incrementAndGet(); - searchResults.addAll(analyzeFile(path, false, lastModified, searchQuery, chatOnly, matchCase, removeFormatting)); + if (path.toFile().length() > fileSizeLimit) { + // file too large + logSearchResults.addSkippedFile(); + } else { + logSearchResults.addAnalyzedFile(); + logSearchResults.addSearchResults(analyzeFile(path, false, lastModified, searchQuery, chatOnly, matchCase, removeFormatting)); + } } } }); @@ -73,12 +80,21 @@ class LogFilesSearcher { } } - if (foundLogs.get() == 0) { - throw new FileNotFoundException(EnumChatFormatting.DARK_RED + "ERROR: No Minecraft log files could be found for the selected date range. Please check if the dates as well as the directories of the log files are set correctly (Log Search ➡ Settings)."); + if (logSearchResults.getAnalyzedFiles() == 0) { + // no files were analyzed + int skippedFileCounter = logSearchResults.getSkippedFiles(); + if (skippedFileCounter > 0) { + throw new FileNotFoundException(EnumChatFormatting.DARK_RED + "ERROR: No Minecraft log files could be found for the selected date range.\n" + + EnumChatFormatting.RED + skippedFileCounter + EnumChatFormatting.DARK_RED + " log files were skipped because they are too large ( >" + FileUtils.byteCountToDisplaySize(MooConfig.getMaxLogFileSize()) + ").\n" + + EnumChatFormatting.RED + "Please check if the dates as well as the directories of the log files are set correctly (Log Search ➡ Settings [top right corner]).\n" + + EnumChatFormatting.DARK_RED + "You could also increase the maximum allowed log file size to be searched (Log Search ➡ Settings), but note that each file must be unzipped before it can be analyzed, which can make the log file search take significantly longer for large files."); + } else { + throw new FileNotFoundException(EnumChatFormatting.DARK_RED + "ERROR: No Minecraft log files could be found for the selected date range.\n" + + EnumChatFormatting.RED + "Please check if the dates as well as the directories of the log files are set correctly (Log Search ➡ Settings [top right corner])."); + } } else { - List<LogEntry> sortedSearchResults = searchResults - .stream().sorted(Comparator.comparing(LogEntry::getTime)).collect(Collectors.toList()); - return new ImmutableTriple<>(foundLogs.get(), analyzedFilesWithHits, sortedSearchResults); + logSearchResults.setAnalyzedFilesWithHits(analyzedFilesWithHits); + return logSearchResults; } } diff --git a/src/main/java/de/cowtipper/cowlection/search/LogSearchResults.java b/src/main/java/de/cowtipper/cowlection/search/LogSearchResults.java new file mode 100644 index 0000000..2b7ce80 --- /dev/null +++ b/src/main/java/de/cowtipper/cowlection/search/LogSearchResults.java @@ -0,0 +1,53 @@ +package de.cowtipper.cowlection.search; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +public class LogSearchResults { + private final AtomicInteger analyzedFiles; + private final AtomicInteger skippedFiles; + private final List<LogEntry> searchResults; + private int analyzedFilesWithHits; + + public LogSearchResults() { + this.analyzedFiles = new AtomicInteger(); + this.skippedFiles = new AtomicInteger(); + this.searchResults = Collections.synchronizedList(new ArrayList<>()); + } + + public void addAnalyzedFile() { + analyzedFiles.incrementAndGet(); + } + + public void addSkippedFile() { + skippedFiles.incrementAndGet(); + } + + public void addSearchResults(List<LogEntry> newResults) { + searchResults.addAll(newResults); + } + + public void setAnalyzedFilesWithHits(int analyzedFilesWithHits) { + this.analyzedFilesWithHits = analyzedFilesWithHits; + } + + public int getAnalyzedFiles() { + return analyzedFiles.get(); + } + + public int getSkippedFiles() { + return skippedFiles.get(); + } + + public List<LogEntry> getSortedSearchResults() { + return searchResults.stream().sorted(Comparator.comparing(LogEntry::getTime)).collect(Collectors.toList()); + } + + public int getAnalyzedFilesWithHits() { + return analyzedFilesWithHits; + } +} diff --git a/src/main/java/de/cowtipper/cowlection/util/Utils.java b/src/main/java/de/cowtipper/cowlection/util/Utils.java index dccf911..f7baba2 100644 --- a/src/main/java/de/cowtipper/cowlection/util/Utils.java +++ b/src/main/java/de/cowtipper/cowlection/util/Utils.java @@ -3,7 +3,6 @@ package de.cowtipper.cowlection.util; import com.mojang.realmsclient.util.Pair; import de.cowtipper.cowlection.Cowlection; import de.cowtipper.cowlection.config.MooConfig; -import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiScreen; import net.minecraft.nbt.NBTBase; import net.minecraft.nbt.NBTTagCompound; @@ -405,8 +404,8 @@ public final class Utils { * Based on ScreenShotHelper#getTimestampedPNGFileForDirectory */ static File getTimestampedFileForDirectory(String suffix, String fileType) { - File cowlectionOutPath = new File(Minecraft.getMinecraft().mcDataDir, Cowlection.MODID.toLowerCase() + "_out"); - if (!cowlectionOutPath.exists() && !cowlectionOutPath.mkdirs()) { + File cowlectionOutPath = Cowlection.getInstance().getModOutDirectory(); + if (cowlectionOutPath == null) { // dir didn't exist and couldn't be created return null; } |