From 7d4f2b900254d961b847f573237e3e6f40bff8e9 Mon Sep 17 00:00:00 2001 From: Cow Date: Thu, 24 Sep 2020 17:58:17 +0200 Subject: Config (gui) rework - Completely re-done the config gui (`/moo config`) - Improved SkyBlock dungeon party finder - Improved SkyBlock dungeon performance overlay - Improved handling of invalid/missing Hypixel API key - minor text fixes --- .../java/de/cowtipper/cowlection/Cowlection.java | 10 +- .../cowtipper/cowlection/command/MooCommand.java | 65 +- .../command/exception/ApiContactException.java | 5 + .../cowlection/config/DungeonOverlayGuiConfig.java | 129 ---- .../de/cowtipper/cowlection/config/MooConfig.java | 614 +++++++++++---- .../cowtipper/cowlection/config/MooGuiConfig.java | 85 -- .../cowtipper/cowlection/config/MooGuiFactory.java | 29 - .../config/gui/MooConfigCategoryScrolling.java | 856 +++++++++++++++++++++ .../cowlection/config/gui/MooConfigGui.java | 206 +++++ .../cowlection/config/gui/MooConfigMenuList.java | 70 ++ .../cowlection/config/gui/MooConfigPreview.java | 175 +++++ .../de/cowtipper/cowlection/data/DataHelper.java | 22 + .../de/cowtipper/cowlection/data/HyApiKey.java | 20 + .../cowlection/handler/FriendsHandler.java | 6 +- .../cowlection/listener/ChatListener.java | 11 +- .../cowlection/listener/PlayerListener.java | 29 +- .../listener/skyblock/DungeonsListener.java | 130 ++-- .../listener/skyblock/SkyBlockListener.java | 41 +- .../de/cowtipper/cowlection/search/GuiSearch.java | 45 +- .../cowlection/search/LogFilesSearcher.java | 4 +- .../de/cowtipper/cowlection/util/ApiUtils.java | 16 + .../java/de/cowtipper/cowlection/util/Utils.java | 2 +- 22 files changed, 2035 insertions(+), 535 deletions(-) delete mode 100644 src/main/java/de/cowtipper/cowlection/config/DungeonOverlayGuiConfig.java delete mode 100644 src/main/java/de/cowtipper/cowlection/config/MooGuiConfig.java delete mode 100644 src/main/java/de/cowtipper/cowlection/config/MooGuiFactory.java create mode 100644 src/main/java/de/cowtipper/cowlection/config/gui/MooConfigCategoryScrolling.java create mode 100644 src/main/java/de/cowtipper/cowlection/config/gui/MooConfigGui.java create mode 100644 src/main/java/de/cowtipper/cowlection/config/gui/MooConfigMenuList.java create mode 100644 src/main/java/de/cowtipper/cowlection/config/gui/MooConfigPreview.java create mode 100644 src/main/java/de/cowtipper/cowlection/data/HyApiKey.java (limited to 'src/main/java/de') diff --git a/src/main/java/de/cowtipper/cowlection/Cowlection.java b/src/main/java/de/cowtipper/cowlection/Cowlection.java index 50df539..4aefd5b 100644 --- a/src/main/java/de/cowtipper/cowlection/Cowlection.java +++ b/src/main/java/de/cowtipper/cowlection/Cowlection.java @@ -29,7 +29,6 @@ import java.io.File; @Mod(modid = Cowlection.MODID, name = Cowlection.MODNAME, version = Cowlection.VERSION, clientSideOnly = true, - guiFactory = "@PACKAGE@.config.MooGuiFactory", updateJSON = "https://raw.githubusercontent.com/cow-mc/Cowlection/master/update.json") public class Cowlection { public static final String MODID = "@MODID@"; @@ -54,15 +53,16 @@ public class Cowlection { logger = e.getModLog(); modsDir = e.getSourceFile().getParentFile(); + chatHelper = new ChatHelper(); + this.configDir = new File(e.getModConfigurationDirectory(), MODID + File.separatorChar); if (!configDir.exists()) { configDir.mkdirs(); } friendsHandler = new FriendsHandler(this, new File(configDir, "friends.json")); - config = new MooConfig(this, new Configuration(new File(configDir, MODID + ".cfg"))); - - chatHelper = new ChatHelper(); + moo = new CredentialStorage(new Configuration(new File(configDir, "do-not-share-me-with-other-players.cfg"))); + config = new MooConfig(this, new Configuration(new File(configDir, MODID + ".cfg"), "1")); } @EventHandler @@ -77,7 +77,7 @@ public class Cowlection { } // key bindings keyBindings = new KeyBinding[1]; - keyBindings[0] = new KeyBinding("key.cowlection.moo.desc", Keyboard.KEY_M, "key.cowlection.category"); + keyBindings[0] = new KeyBinding("key.cowlection.moo", Keyboard.KEY_M, "key.cowlection.category"); for (KeyBinding keyBinding : keyBindings) { ClientRegistry.registerKeyBinding(keyBinding); diff --git a/src/main/java/de/cowtipper/cowlection/command/MooCommand.java b/src/main/java/de/cowtipper/cowlection/command/MooCommand.java index 6be1a6c..881a446 100644 --- a/src/main/java/de/cowtipper/cowlection/command/MooCommand.java +++ b/src/main/java/de/cowtipper/cowlection/command/MooCommand.java @@ -5,9 +5,9 @@ import de.cowtipper.cowlection.Cowlection; import de.cowtipper.cowlection.command.exception.ApiContactException; import de.cowtipper.cowlection.command.exception.InvalidPlayerNameException; import de.cowtipper.cowlection.command.exception.MooCommandException; -import de.cowtipper.cowlection.config.DungeonOverlayGuiConfig; +import de.cowtipper.cowlection.config.CredentialStorage; import de.cowtipper.cowlection.config.MooConfig; -import de.cowtipper.cowlection.config.MooGuiConfig; +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; @@ -15,6 +15,7 @@ import de.cowtipper.cowlection.search.GuiSearch; import de.cowtipper.cowlection.util.*; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.settings.GameSettings; import net.minecraft.command.*; import net.minecraft.entity.Entity; import net.minecraft.entity.item.EntityArmorStand; @@ -79,12 +80,7 @@ public class MooCommand extends CommandBase { } else if (args[0].equalsIgnoreCase("list")) { handleListBestFriends(); } else if (args[0].equalsIgnoreCase("online")) { - if (main.getFriendsHandler().getBestFriends().size() > 0) { - main.getChatHelper().sendMessage(EnumChatFormatting.GRAY, "Checking online status of " + EnumChatFormatting.WHITE + main.getFriendsHandler().getBestFriends().size() + EnumChatFormatting.GRAY + " best friends. This may take a few seconds."); - main.getFriendsHandler().runBestFriendsOnlineCheck(true); - } else { - main.getChatHelper().sendMessage(EnumChatFormatting.RED, "You haven't added anyone to your best friends list yet. Do so with " + EnumChatFormatting.WHITE + "/moo add "); - } + handleBestFriendsOnlineCheck(); } else if (args[0].equalsIgnoreCase("nameChangeCheck")) { handleNameChangeCheck(args); } @@ -100,14 +96,11 @@ public class MooCommand extends CommandBase { handleAnalyzeIsland(sender); } else if (args[0].equalsIgnoreCase("dungeon") || args[0].equalsIgnoreCase("dung")) { handleDungeon(args); - } else if (args[0].equalsIgnoreCase("dungeonGui") || args[0].equalsIgnoreCase("guiDungeon") - || args[0].equalsIgnoreCase("guiDung") || args[0].equalsIgnoreCase("dungGui")) { - displayGuiScreen(new DungeonOverlayGuiConfig(main)); } //endregion //region sub-commands: miscellaneous - else if (args[0].equalsIgnoreCase("config") || args[0].equalsIgnoreCase("toggle")) { - displayGuiScreen(new MooGuiConfig(null)); + else if (args[0].equalsIgnoreCase("config")) { + displayGuiScreen(new MooConfigGui()); } else if (args[0].equalsIgnoreCase("search")) { displayGuiScreen(new GuiSearch(main.getConfigDirectory(), CommandBase.buildString(args, 1))); } else if (args[0].equalsIgnoreCase("guiscale")) { @@ -278,6 +271,18 @@ public class MooCommand extends CommandBase { : EnumChatFormatting.DARK_GREEN + String.join(EnumChatFormatting.GREEN + ", " + EnumChatFormatting.DARK_GREEN, bestFriends))); } + private void handleBestFriendsOnlineCheck() throws MooCommandException { + if (!CredentialStorage.isMooValid) { + throw new MooCommandException("You haven't set your Hypixel API key yet or the API key is invalid. Use " + EnumChatFormatting.DARK_RED + "/api new" + EnumChatFormatting.RED + " to request a new API key from Hypixel or use " + EnumChatFormatting.DARK_RED + "/" + this.getCommandName() + " apikey " + EnumChatFormatting.RED + " to manually set your existing API key."); + } + if (main.getFriendsHandler().getBestFriends().size() > 0) { + main.getChatHelper().sendMessage(EnumChatFormatting.GRAY, "Checking online status of " + EnumChatFormatting.WHITE + main.getFriendsHandler().getBestFriends().size() + EnumChatFormatting.GRAY + " best friends. This may take a few seconds."); + main.getFriendsHandler().runBestFriendsOnlineCheck(true); + } else { + main.getChatHelper().sendMessage(EnumChatFormatting.RED, "You haven't added anyone to your best friends list yet. Do so with " + EnumChatFormatting.WHITE + "/moo add "); + } + } + private void handleNameChangeCheck(String[] args) throws CommandException { if (args.length != 2) { throw new WrongUsageException("/" + getCommandName() + " nameChangeCheck "); @@ -562,20 +567,24 @@ public class MooCommand extends CommandBase { private void handleDungeon(String[] args) throws MooCommandException { DungeonCache dungeonCache = main.getDungeonCache(); - if (args.length == 2 && args[1].equalsIgnoreCase("gui")) { - // edit dungeon gui - displayGuiScreen(new DungeonOverlayGuiConfig(main)); + if (args.length == 2 && args[1].equalsIgnoreCase("enter")) { + // enter dungeon in case for some reason it wasn't detected automatically + dungeonCache.onDungeonEnterOrLeave(true); + } else if (args.length == 2 && args[1].equalsIgnoreCase("leave")) { + // leave dungeon in case for some reason it wasn't detected automatically + dungeonCache.onDungeonEnterOrLeave(false); } else if (dungeonCache.isInDungeon()) { dungeonCache.sendDungeonPerformance(); } else { - throw new MooCommandException(EnumChatFormatting.DARK_RED + "Looks like you're not in a dungeon... However, you can edit the Dungeon Performance overlay with " + EnumChatFormatting.RED + "/" + getCommandName() + " dungeon gui"); + throw new MooCommandException(EnumChatFormatting.DARK_RED + "Looks like you're not in a dungeon... However, you can manually enable the Dungeon Performance overlay with " + EnumChatFormatting.RED + "/" + getCommandName() + " dungeon enter" + EnumChatFormatting.DARK_RED + ". You can also force-leave a dungeon with " + EnumChatFormatting.RED + "/" + getCommandName() + " leave"); } } //endregion //region sub-commands: miscellaneous private void handleGuiScale(String[] args) throws CommandException { - int currentGuiScale = (Minecraft.getMinecraft()).gameSettings.guiScale; + GameSettings gameSettings = Minecraft.getMinecraft().gameSettings; + int currentGuiScale = gameSettings.guiScale; if (args.length == 1) { main.getChatHelper().sendMessage(EnumChatFormatting.GREEN, "\u279C Current GUI scale: " + EnumChatFormatting.DARK_GREEN + currentGuiScale); } else { @@ -583,7 +592,8 @@ public class MooCommand extends CommandBase { if (scale == -1 || scale > 10) { throw new NumberInvalidException(EnumChatFormatting.DARK_RED + args[1] + EnumChatFormatting.RED + " is an invalid GUI scale value. Valid values are integers below 10"); } - Minecraft.getMinecraft().gameSettings.guiScale = scale; + gameSettings.guiScale = scale; + gameSettings.saveOptions(); main.getChatHelper().sendMessage(EnumChatFormatting.GREEN, "\u2714 New GUI scale: " + EnumChatFormatting.DARK_GREEN + scale + EnumChatFormatting.GREEN + " (previous: " + EnumChatFormatting.DARK_GREEN + currentGuiScale + EnumChatFormatting.GREEN + ")"); } } @@ -598,7 +608,7 @@ public class MooCommand extends CommandBase { color = EnumChatFormatting.GREEN; colorSecondary = EnumChatFormatting.DARK_GREEN; } else { - firstSentence = "You haven't set your Hypixel API key yet."; + firstSentence = "You haven't set your Hypixel API key yet or the API key is invalid."; color = EnumChatFormatting.RED; colorSecondary = EnumChatFormatting.DARK_RED; } @@ -659,21 +669,20 @@ public class MooCommand extends CommandBase { private void sendCommandUsage(ICommandSender sender) { IChatComponent usage = new MooChatComponent("\u279C " + Cowlection.MODNAME + " commands:").gold().bold() + .appendSibling(createCmdHelpEntry("config", "Open mod's configuration")) + .appendSibling(new MooChatComponent("\n").reset().gray().appendText(EnumChatFormatting.DARK_GREEN + " ❢" + EnumChatFormatting.GRAY + EnumChatFormatting.ITALIC + " Commands marked with §d§l⚷" + EnumChatFormatting.GRAY + EnumChatFormatting.ITALIC + " require a valid API key")) .appendSibling(createCmdHelpSection(1, "Best friends, friends & other players")) - .appendSibling(createCmdHelpEntry("stalk", "Get info of player's status")) + .appendSibling(createCmdHelpEntry("stalk", "Get info of player's status §d§l⚷")) .appendSibling(createCmdHelpEntry("add", "Add best friends")) .appendSibling(createCmdHelpEntry("remove", "Remove best friends")) .appendSibling(createCmdHelpEntry("list", "View list of best friends")) - .appendSibling(createCmdHelpEntry("online", "View list of best friends that are currently online")) + .appendSibling(createCmdHelpEntry("online", "View list of best friends that are currently online §d§l⚷")) .appendSibling(createCmdHelpEntry("nameChangeCheck", "Force a scan for a changed name of a best friend (is done automatically as well)")) - .appendSibling(createCmdHelpEntry("toggle", "Toggle join/leave notifications")) .appendSibling(createCmdHelpSection(2, "SkyBlock")) - .appendSibling(createCmdHelpEntry("stalkskyblock", "Get info of player's SkyBlock stats")) + .appendSibling(createCmdHelpEntry("stalkskyblock", "Get info of player's SkyBlock stats §d§l⚷")) .appendSibling(createCmdHelpEntry("analyzeIsland", "Analyze a SkyBlock private island")) .appendSibling(createCmdHelpEntry("dungeon", "SkyBlock Dungeons: display current dungeon performance")) - .appendSibling(createCmdHelpEntry("dungeonGui", "SkyBlock Dungeons: edit dungeon performance GUI")) .appendSibling(createCmdHelpSection(3, "Miscellaneous")) - .appendSibling(createCmdHelpEntry("config", "Open mod's configuration")) .appendSibling(createCmdHelpEntry("search", "Open Minecraft log search")) .appendSibling(createCmdHelpEntry("guiScale", "Change GUI scale")) .appendSibling(createCmdHelpEntry("rr", "Alias for /r without auto-replacement to /msg")) @@ -706,8 +715,8 @@ public class MooCommand extends CommandBase { public List addTabCompletionOptions(ICommandSender sender, String[] args, BlockPos pos) { if (args.length == 1) { return getListOfStringsMatchingLastWord(args, - /* Best friends, friends & other players */ "stalk", "add", "remove", "list", "online", "nameChangeCheck", "toggle", - /* SkyBlock */ "stalkskyblock", "skyblockstalk", "analyzeIsland", "dungeon", "dungeonGui", "guiDungeon", + /* Best friends, friends & other players */ "stalk", "add", "remove", "list", "online", "nameChangeCheck", + /* SkyBlock */ "stalkskyblock", "skyblockstalk", "analyzeIsland", "dungeon", /* miscellaneous */ "config", "search", "guiscale", "rr", "shrug", "apikey", /* update mod */ "update", "updateHelp", "version", "directory", /* help */ "help", diff --git a/src/main/java/de/cowtipper/cowlection/command/exception/ApiContactException.java b/src/main/java/de/cowtipper/cowlection/command/exception/ApiContactException.java index 09a04a0..f601e3e 100644 --- a/src/main/java/de/cowtipper/cowlection/command/exception/ApiContactException.java +++ b/src/main/java/de/cowtipper/cowlection/command/exception/ApiContactException.java @@ -1,7 +1,12 @@ package de.cowtipper.cowlection.command.exception; +import de.cowtipper.cowlection.Cowlection; + public class ApiContactException extends MooCommandException { public ApiContactException(String api, String failedAction) { super("Sorry, couldn't contact the " + api + " API and thus " + failedAction); + if (api.equals("Hypixel") && failedAction.contains("Invalid API key")) { + Cowlection.getInstance().getMoo().setMooValidity(false); + } } } diff --git a/src/main/java/de/cowtipper/cowlection/config/DungeonOverlayGuiConfig.java b/src/main/java/de/cowtipper/cowlection/config/DungeonOverlayGuiConfig.java deleted file mode 100644 index 18478f5..0000000 --- a/src/main/java/de/cowtipper/cowlection/config/DungeonOverlayGuiConfig.java +++ /dev/null @@ -1,129 +0,0 @@ -package de.cowtipper.cowlection.config; - -import de.cowtipper.cowlection.Cowlection; -import net.minecraft.client.gui.GuiButton; -import net.minecraft.client.gui.GuiScreen; -import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.util.EnumChatFormatting; -import net.minecraftforge.fml.client.config.GuiButtonExt; -import net.minecraftforge.fml.client.config.GuiCheckBox; -import net.minecraftforge.fml.client.config.GuiSlider; -import org.apache.commons.lang3.StringUtils; -import org.lwjgl.input.Keyboard; - -import java.io.IOException; - -public class DungeonOverlayGuiConfig extends GuiScreen { - private final Cowlection main; - private GuiCheckBox checkBoxShowOverlay; - private GuiSlider sliderX; - private GuiSlider sliderY; - private GuiSlider sliderGuiScale; - private GuiButtonExt buttonCancel; - private GuiButtonExt buttonSave; - private final boolean wasDungOverlayEnabled; - private final int previousPositionX; - private final int previousPositionY; - private final int previousGuiScale; - - public DungeonOverlayGuiConfig(Cowlection main) { - this.main = main; - wasDungOverlayEnabled = MooConfig.dungOverlayEnabled; - previousPositionX = MooConfig.dungOverlayPositionX; - previousPositionY = MooConfig.dungOverlayPositionY; - previousGuiScale = MooConfig.dungOverlayGuiScale; - } - - @Override - public void initGui() { - int maxX = this.width - fontRendererObj.getStringWidth(StringUtils.repeat('#', 15)); - int maxY = this.height - fontRendererObj.FONT_HEIGHT * 5; // 5 = max lines output - int startX = Math.min(maxX, this.previousPositionX); - int startY = Math.min(maxY, this.previousPositionY); - - this.buttonList.add(this.checkBoxShowOverlay = new GuiCheckBox(30, this.width / 2 - 50, this.height / 2 - 30, " Show overlay", MooConfig.dungOverlayEnabled)); - this.buttonList.add(sliderX = new GuiSlider(20, this.width / 2 - 150, this.height / 2 - 12, 300, 20, "x = ", "", 0, maxX, startX, false, true)); - this.buttonList.add(sliderY = new GuiSlider(21, this.width / 2 - 150, this.height / 2 + 12, 300, 20, "y = ", "", 0, maxY, startY, false, true)); - this.buttonList.add(sliderGuiScale = new GuiSlider(22, this.width / 2 - 100, this.height / 2 + 37, 200, 20, "GUI scale: ", "%", 50, 200, MooConfig.dungOverlayGuiScale, false, true)); - this.buttonList.add(this.buttonCancel = new GuiButtonExt(31, this.width / 2 - 150, this.height / 2 + 65, 80, 20, EnumChatFormatting.RED + "Cancel")); - this.buttonList.add(this.buttonSave = new GuiButtonExt(32, this.width / 2 + 70, this.height / 2 + 65, 80, 20, EnumChatFormatting.GREEN + "Save")); - if (!MooConfig.dungOverlayEnabled) { - sliderX.enabled = false; - sliderY.enabled = false; - sliderGuiScale.enabled = false; - } - } - - @Override - public void drawScreen(int mouseX, int mouseY, float partialTicks) { - // draw background - int padding = 20; - this.drawGradientRect(this.width / 2 - 150 - padding, this.height / 2 - 40 - fontRendererObj.FONT_HEIGHT - padding, - this.width / 2 + 150 + padding, this.height / 2 + 65 + 20 + fontRendererObj.FONT_HEIGHT + padding, - -1072689136, -804253680); - - // draw gui elements - String title = "Dungeon Performance Overlay Settings"; - this.drawCenteredString(this.fontRendererObj, EnumChatFormatting.BOLD + title, this.width / 2, this.height / 2 - 40 - fontRendererObj.FONT_HEIGHT, 0x00ffffff); - - GlStateManager.pushMatrix(); - float scaleFactor = 0.75f; - GlStateManager.scale(scaleFactor, scaleFactor, 0); - String hint = "(" + EnumChatFormatting.GOLD + EnumChatFormatting.ITALIC + "Note: " + EnumChatFormatting.RESET + "Destroyed Crypts can only be detected up to ~50 blocks away from the player)"; - this.drawCenteredString(this.fontRendererObj, hint, (int) ((this.width / 2) * (1 / scaleFactor)), (int) ((this.height / 2 + 95) * (1 / scaleFactor)), 0x00cccccc); - GlStateManager.popMatrix(); - - super.drawScreen(mouseX, mouseY, partialTicks); - - if (checkBoxShowOverlay.enabled) { - MooConfig.dungOverlayPositionX = sliderX.getValueInt(); - MooConfig.dungOverlayPositionY = sliderY.getValueInt(); - MooConfig.dungOverlayGuiScale = sliderGuiScale.getValueInt(); - } - } - - @Override - protected void keyTyped(char typedChar, int keyCode) throws IOException { - if (keyCode == Keyboard.KEY_ESCAPE) { - resetDungeonOverlayPosition(); - } - super.keyTyped(typedChar, keyCode); - } - - @Override - protected void actionPerformed(GuiButton button) throws IOException { - if (button == buttonCancel) { - resetDungeonOverlayPosition(); - closeGui(); - } else if (button == buttonSave) { - if (wasDungOverlayEnabled != checkBoxShowOverlay.isChecked() || previousPositionX != sliderX.getValueInt() || previousPositionY != sliderY.getValueInt() || previousGuiScale != sliderGuiScale.getValueInt()) { - main.getConfig().syncFromFields(); - if (wasDungOverlayEnabled != checkBoxShowOverlay.isChecked()) { - main.getChatHelper().sendMessage(EnumChatFormatting.GREEN, "The dungeon performance overlay is now " + (checkBoxShowOverlay.isChecked() ? EnumChatFormatting.DARK_GREEN + "enabled" : EnumChatFormatting.DARK_RED + "disabled")); - } else { - main.getChatHelper().sendMessage(EnumChatFormatting.GREEN, "Saved new size and position of the dungeon performance overlay!"); - } - } - closeGui(); - } else if (button == checkBoxShowOverlay) { - sliderX.enabled = checkBoxShowOverlay.isChecked(); - sliderY.enabled = checkBoxShowOverlay.isChecked(); - sliderGuiScale.enabled = checkBoxShowOverlay.isChecked(); - MooConfig.dungOverlayEnabled = checkBoxShowOverlay.isChecked(); - } - } - - private void resetDungeonOverlayPosition() { - MooConfig.dungOverlayEnabled = wasDungOverlayEnabled; - MooConfig.dungOverlayPositionX = previousPositionX; - MooConfig.dungOverlayPositionY = previousPositionY; - MooConfig.dungOverlayGuiScale = previousGuiScale; - } - - private void closeGui() { - this.mc.displayGuiScreen(null); - if (this.mc.currentScreen == null) { - this.mc.setIngameFocus(); - } - } -} diff --git a/src/main/java/de/cowtipper/cowlection/config/MooConfig.java b/src/main/java/de/cowtipper/cowlection/config/MooConfig.java index 0a498dd..1d8b4ee 100644 --- a/src/main/java/de/cowtipper/cowlection/config/MooConfig.java +++ b/src/main/java/de/cowtipper/cowlection/config/MooConfig.java @@ -2,78 +2,122 @@ package de.cowtipper.cowlection.config; import de.cowtipper.cowlection.Cowlection; import de.cowtipper.cowlection.command.TabCompletableCommand; +import de.cowtipper.cowlection.config.gui.MooConfigGui; +import de.cowtipper.cowlection.config.gui.MooConfigPreview; +import de.cowtipper.cowlection.data.DataHelper; +import de.cowtipper.cowlection.util.MooChatComponent; import de.cowtipper.cowlection.util.Utils; import net.minecraft.client.Minecraft; import net.minecraft.command.ICommand; +import net.minecraft.nbt.NBTBase; +import net.minecraft.nbt.NBTTagInt; +import net.minecraft.nbt.NBTTagString; +import net.minecraft.util.ChatComponentText; import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.IChatComponent; import net.minecraft.util.Util; import net.minecraftforge.client.ClientCommandHandler; import net.minecraftforge.common.ForgeModContainer; import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.common.config.ConfigCategory; import net.minecraftforge.common.config.Configuration; import net.minecraftforge.common.config.Property; -import net.minecraftforge.fml.client.FMLConfigGuiFactory; import net.minecraftforge.fml.client.event.ConfigChangedEvent; import net.minecraftforge.fml.common.eventhandler.EventPriority; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.StringUtils; +import org.lwjgl.input.Keyboard; import java.io.File; import java.time.LocalDate; import java.time.format.DateTimeParseException; import java.time.temporal.ChronoUnit; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.regex.Pattern; /** - * Mod configuration via ingame gui + * Mod configuration *

* Based on TheGreyGhost's MinecraftByExample * * @see ForgeModContainer - * @see FMLConfigGuiFactory */ public class MooConfig { - static final String CATEGORY_LOGS_SEARCH = "logssearch"; - // main config + // Category: General + private static String configGuiExplanations; + public static String[] tabCompletableNamesCommands; + private static final String CATEGORY_LOGS_SEARCH = "logssearch"; + public static String[] logsDirs; + private static String defaultStartDate; + // Category: Notifications public static boolean doUpdateCheck; public static boolean showBestFriendNotifications; public static boolean showFriendNotifications; public static boolean showGuildNotifications; public static boolean doBestFriendsOnlineCheck; - public static boolean showAdvancedTooltips; - public static String[] tabCompletableNamesCommands; + // Category: SkyBlock + public static int tooltipToggleKeyBinding; + private static String tooltipAuctionHousePriceEach; + private static String tooltipItemAge; + public static boolean tooltipItemAgeShortened; + private static String tooltipItemTimestamp; private static String numeralSystem; - // SkyBlock dungeon - public static int[] dungClassRange; - public static boolean dungFilterPartiesWithDupes; - public static String dungPartyFinderArmorLookup; - public static String dungItemQualityPos; + // Category: SkyBlock Dungeons + public static int dungItemToolTipToggleKeyBinding; + private static String dungItemQualityPos; public static boolean dungOverlayEnabled; - public static int dungOverlayGuiScale; public static int dungOverlayPositionX; public static int dungOverlayPositionY; - // logs search config - public static String[] logsDirs; - private static String defaultStartDate; - // other stuff - public static String moo; + public static int dungOverlayGuiScale; + public static boolean dungOverlayTextShadow; + public static int dungClassMin; + public static boolean dungFilterPartiesWithArcherDupes; + public static boolean dungFilterPartiesWithBerserkDupes; + public static boolean dungFilterPartiesWithHealerDupes; + public static boolean dungFilterPartiesWithMageDupes; + public static boolean dungFilterPartiesWithTankDupes; + private static String dungPartyFinderArmorLookup; + private static Configuration cfg = null; + private static final List configCategories = new ArrayList<>(); private final Cowlection main; - private List propOrderGeneral; - private List propOrderLogsSearch; + private Property propTabCompletableNamesCommands; + private List logSearchProperties; public MooConfig(Cowlection main, Configuration configuration) { this.main = main; cfg = configuration; + + if (cfg.getLoadedConfigVersion() == null || !cfg.getLoadedConfigVersion().equals(cfg.getDefinedConfigVersion())) { + updateConfig(cfg.getLoadedConfigVersion()); + } + initConfig(); } - static Configuration getConfig() { - return cfg; + private void updateConfig(String oldVersion) { + if (oldVersion == null) { + // config of Cowlection v1.8.9-0.10.2 and older + + // leave log search settings as is + + if (cfg.hasCategory(Configuration.CATEGORY_CLIENT)) { + // copy old 'moo' value to new, separate config + if (cfg.hasKey(Configuration.CATEGORY_CLIENT, "moo")) { + String oldMoo = cfg.getString("moo", Configuration.CATEGORY_CLIENT, "00000000-0000-0000-0000-000000000000", "Temporary config entry, should be deleted automatically.", Utils.VALID_UUID_PATTERN); + if (StringUtils.isNotEmpty(oldMoo) && Utils.isValidUuid(oldMoo)) { + // save into new cfg: + main.getMoo().setMooIfValid(oldMoo, false); + } + } + + // delete client category (no longer used) + ConfigCategory oldClientCategory = cfg.getCategory(Configuration.CATEGORY_CLIENT); + cfg.removeCategory(oldClientCategory); + } + cfg.save(); + } } private void initConfig() { @@ -85,37 +129,28 @@ public class MooConfig { * Load the configuration values from the configuration file */ private void syncFromFile() { - syncConfig(true, true); + syncConfig(true, true, true); } /** * Save the GUI-altered values to disk */ - private void syncFromGui() { - syncConfig(false, true); + public void syncFromGui() { + syncConfig(false, true, true); } /** - * Save the Configuration variables (fields) to disk + * Save the GUI-altered values to the properties; don't save to disk - only memory */ - public void syncFromFields() { - syncConfig(false, false); + public void syncFromGuiWithoutSaving() { + syncConfig(false, true, false); } - public static LocalDate calculateStartDate() { - try { - // date format: yyyy-mm-dd - return LocalDate.parse(defaultStartDate); - } catch (DateTimeParseException e) { - // fallthrough - } - try { - int months = Integer.parseInt(defaultStartDate); - return LocalDate.now().minus(months, ChronoUnit.MONTHS); - } catch (NumberFormatException e) { - // default: 1 month - return LocalDate.now().minus(1, ChronoUnit.MONTHS); - } + /** + * Save the Configuration variables (fields) to disk + */ + public void syncFromFields() { + syncConfig(false, false, true); } /** @@ -126,127 +161,321 @@ public class MooConfig { * * @param loadConfigFromFile if true, load the config field from the configuration file on disk * @param readFieldsFromConfig if true, reload the member variables from the config field + * @param saveToFile if true, save changes to config file */ - private void syncConfig(boolean loadConfigFromFile, boolean readFieldsFromConfig) { + @SuppressWarnings("DuplicatedCode") + private void syncConfig(boolean loadConfigFromFile, boolean readFieldsFromConfig, boolean saveToFile) { if (loadConfigFromFile) { cfg.load(); } - // config section: main configuration - propOrderGeneral = new ArrayList<>(); - - Property propDoUpdateCheck = addConfigEntry(cfg.get(Configuration.CATEGORY_CLIENT, - "doUpdateCheck", true, "Check for mod updates?"), true); - Property propShowBestFriendNotifications = addConfigEntry(cfg.get(Configuration.CATEGORY_CLIENT, - "showBestFriendNotifications", true, "Set to true to receive best friends' login/logout messages, set to false hide them."), true); - Property propShowFriendNotifications = addConfigEntry(cfg.get(Configuration.CATEGORY_CLIENT, - "showFriendNotifications", true, "Set to true to receive friends' login/logout messages, set to false hide them."), true); - Property propShowGuildNotifications = addConfigEntry(cfg.get(Configuration.CATEGORY_CLIENT, - "showGuildNotifications", true, "Set to true to receive guild members' login/logout messages, set to false hide them."), true); - Property propDoBestFriendsOnlineCheck = addConfigEntry(cfg.get(Configuration.CATEGORY_CLIENT, - "doBestFriendsOnlineCheck", true, "Set to true to check best friends' online status when joining a server, set to false to disable."), true); - Property propShowAdvancedTooltips = addConfigEntry(cfg.get(Configuration.CATEGORY_CLIENT, - "showAdvancedTooltips", true, "Set to true to show advanced tooltips, set to false show default tooltips."), true); - Property propNumeralSystem = addConfigEntry(cfg.get(Configuration.CATEGORY_CLIENT, - "numeralSystem", "Arabic numerals: 1, 4, 10", "Use Roman or Arabic numeral system?", new String[]{"Arabic numerals: 1, 4, 10", "Roman numerals: I, IV, X"}), true); - Property propTabCompletableNamesCommands = addConfigEntry(cfg.get(Configuration.CATEGORY_CLIENT, - "tabCompletableNamesCommands", new String[]{"party", "p", "invite", "visit", "ah", "ignore", "msg", "tell", "w", "boop", "profile", "friend", "friends", "f"}, "List of commands with a Tab-completable username argument."), true) - .setValidationPattern(Pattern.compile("^[A-Za-z]+$")); - Property propMoo = addConfigEntry(cfg.get(Configuration.CATEGORY_CLIENT, - "moo", "", "The answer to life the universe and everything. Don't edit this entry manually!", Utils.VALID_UUID_PATTERN), false); - - // SkyBlock dungeon - Property propDungClassRange = addConfigEntry(cfg.get(Configuration.CATEGORY_CLIENT, - "dungClassRange", new int[]{-1, -1}, "Accepted level range for the dungeon party finder. Set to -1 to disable"), true) - .setMinValue(-1).setIsListLengthFixed(true); - Property propDungFilterPartiesWithDupes = addConfigEntry(cfg.get(Configuration.CATEGORY_CLIENT, - "dungFilterPartiesWithDupes", false, "Mark parties with duplicated classes?"), true); - Property propDungPartyFinderArmorLookup = addConfigEntry(cfg.get(Configuration.CATEGORY_CLIENT, - "dungPartyFinderArmorLookup", "as a tooltip", "Show armor of player joining via party finder as a tooltip or in chat?", new String[]{"as a tooltip", "in chat", "disabled"}), true); - Property propDungItemQualityPos = addConfigEntry(cfg.get(Configuration.CATEGORY_CLIENT, - "dungItemQualityPos", "top", "Position of item quality in tooltip", new String[]{"top", "bottom"}), true); - Property propDungOverlayEnabled = addConfigEntry(cfg.get(Configuration.CATEGORY_CLIENT, - "dungOverlayEnabled", true, "Enable Dungeon performance overlay?"), false); - Property propDungOverlayPositionX = addConfigEntry(cfg.get(Configuration.CATEGORY_CLIENT, - "dungGuiPositionX", 5, "Dungeon performance overlay position: x value", -1, 10000), false); - Property propDungOverlayPositionY = addConfigEntry(cfg.get(Configuration.CATEGORY_CLIENT, - "dungGuiPositionY", 5, "Dungeon performance overlay position: y value", -1, 5000), false); - Property propDungOverlayGuiScale = addConfigEntry(cfg.get(Configuration.CATEGORY_CLIENT, - "dungOverlayGuiScale", 100, "Dungeon performance overlay GUI scale", 50, 200), false); - cfg.setCategoryPropertyOrder(Configuration.CATEGORY_CLIENT, propOrderGeneral); - - // config section: log files search - propOrderLogsSearch = new ArrayList<>(); - - Property propLogsDirs = addConfigEntry(cfg.get(CATEGORY_LOGS_SEARCH, + // reset previous entries + configCategories.clear(); + + // Category: General + MooConfigCategory configCat = new MooConfigCategory("General", "general"); + configCategories.add(configCat); + + // Sub-Category: Cowlection config gui + MooConfigCategory.SubCategory subCat = configCat.addSubCategory("Cowlection config gui"); + subCat.addExplanations("Display of the explanations for each sub-section:", + " ‣ " + EnumChatFormatting.YELLOW + "as tooltip ①" + EnumChatFormatting.DARK_GRAY + "⬛" + EnumChatFormatting.RESET + " = tooltip when hovering over sub-category heading (with darkened background)", + " ‣ " + EnumChatFormatting.YELLOW + "as tooltip ②" + EnumChatFormatting.WHITE + "⬛" + EnumChatFormatting.RESET + " = tooltip when hovering over sub-category heading (no extra background)", + " ‣ " + EnumChatFormatting.YELLOW + "as text" + EnumChatFormatting.RESET + " = below each sub-category heading", + " ‣ " + EnumChatFormatting.YELLOW + "hidden" + EnumChatFormatting.RESET + " = "); + Property propConfigGuiExplanations = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), + "configGuiExplanations", "tooltip ① §0⬛", "Display config settings explanations", + new String[]{"as tooltip ①§0⬛", "as tooltip ②§f⬛", "as text", "hidden"})); + + // Sub-Category: API settings + subCat = configCat.addSubCategory("API settings"); + subCat.addExplanations("Some features use the official Hypixel API and therefore require your API key.", + "Use " + EnumChatFormatting.YELLOW + "/moo apikey " + EnumChatFormatting.RESET + "to see how to request a new API key from Hypixel", + "The API key is stored " + EnumChatFormatting.ITALIC + "locally " + EnumChatFormatting.ITALIC + "on your computer."); + subCat.addConfigEntry(main.getMoo().getPropIsMooValid()); + + // Sub-Category: Tab-completable names in commands + subCat = configCat.addSubCategory("Tab-completable usernames"); + subCat.addExplanations("For certain commands you can use " + EnumChatFormatting.YELLOW + "TAB " + EnumChatFormatting.RESET + "to autocomplete player names", + EnumChatFormatting.UNDERLINE + "Uses player names from:", + " ‣ Guild and Party chat", + " ‣ Party and game (duels) invites", + " ‣ SkyBlock Dungeon party finder: when a player joins the group", + " ‣ Online best friends (if the best friend online checker is enabled)"); + + propTabCompletableNamesCommands = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), + "tabCompletableNamesCommands", new String[]{"party", "p", "invite", "visit", "ah", "ignore", "msg", "tell", "w", "boop", "profile", "friend", "friends"}, "List of commands with a Tab-completable username argument.") + .setValidationPattern(Pattern.compile("^[A-Za-z]+$"))); + + // Sub-Category: Other settings + subCat = configCat.addSubCategory("Other settings"); + subCat.addExplanations("Other settings that are located in other GUIs"); + + Property propLogsDirs = subCat.addConfigEntry(cfg.get(CATEGORY_LOGS_SEARCH, "logsDirs", resolveDefaultLogsDirs(), - "Directories with Minecraft log files"), true, CATEGORY_LOGS_SEARCH); - Property propDefaultStartDate = 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)"), true) + "Directories with Minecraft log files")); + 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]))$")); + logSearchProperties = new ArrayList<>(); + logSearchProperties.add(propLogsDirs); + logSearchProperties.add(propDefaultStartDate); + + // Category: Notifications + configCat = new MooConfigCategory("Notifications", "notifications"); + configCategories.add(configCat); + + // Sub-Category: Mod update checker + subCat = configCat.addSubCategory("Mod update checker"); + Property propDoUpdateCheck = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), + "doUpdateCheck", true, "Check for mod updates?")); + + // Sub-Category: Login & Logout + subCat = configCat.addSubCategory("Login & Logout"); + subCat.addExplanations("Hides selected login/logout notifications ", + "while still showing notifications of best friends (if enabled).", + "Add someone to the best friends list with " + EnumChatFormatting.YELLOW + "/moo add " + EnumChatFormatting.RESET); + + Property propShowBestFriendNotifications = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), + "showBestFriendNotifications", true, "Set to true to receive best friends' login/logout messages, set to false hide them."), + new MooConfigPreview(new ChatComponentText("§a§lBest friend §a> §6Cow §r§ejoined."))); + Property propShowFriendNotifications = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), + "showFriendNotifications", true, "Set to true to receive friends' login/logout messages, set to false hide them."), + new MooConfigPreview(new ChatComponentText("§aFriend > §r§aBob §ejoined."))); + Property propShowGuildNotifications = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), + "showGuildNotifications", true, "Set to true to receive guild members' login/logout messages, set to false hide them."), + new MooConfigPreview(new ChatComponentText("§2Guild > §r§7Herobrian §eleft."))); + + + // Sub-Category: Best friends online status + subCat = configCat.addSubCategory("Best friend online checker"); + subCat.addExplanations("Check which best friends are online when you join the server.", + "About once a day, a check for new name changes is also performed automatically."); + + IChatComponent spacer = new MooChatComponent(", ").green(); + Property propDoBestFriendsOnlineCheck = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), + "doBestFriendsOnlineCheck", true, "Set to true to check best friends' online status when joining a server, set to false to disable."), + new MooConfigPreview(new MooChatComponent("§a⬤ Online best friends (§24§a/§216§a): ") + .appendSibling(MooConfigPreview.createDemoOnline("Alice", "Housing", "1 hour 13 minutes 37 seconds")).appendSibling(spacer) + .appendSibling(MooConfigPreview.createDemoOnline("Bob", "Build Battle", "2 hours 13 minutes 37 seconds")).appendSibling(spacer) + .appendSibling(MooConfigPreview.createDemoOnline("Cow", "SkyBlock", "13 minutes 37 seconds")).appendSibling(spacer) + .appendSibling(MooConfigPreview.createDemoOnline("Herobrian", "Murder Mystery", "13 hours 33 minutes 37 seconds")))); + + + // Category: SkyBlock + configCat = new MooConfigCategory("SkyBlock", "skyblock"); + configCategories.add(configCat); + + // Sub-Category: Tooltip enhancements + subCat = configCat.addSubCategory("Tooltip enhancements"); + + Property propTooltipToggleKeyBinding = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), + "tooltipToggleKeyBinding", Keyboard.KEY_LSHIFT, "Key to toggle tooltip")); + + Property propTooltipAuctionHousePriceEach = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), + "tooltipAuctionHousePriceEach", "always", "Add price per item if multiple items are bought or sold", new String[]{"always", "key press", "never"})); + + Map demoItemExtraAttributes = new HashMap<>(); + demoItemExtraAttributes.put("new_years_cake", new NBTTagInt(1)); + demoItemExtraAttributes.put("originTag", new NBTTagString("REWARD_NEW_YEARS_CAKE_NPC")); + demoItemExtraAttributes.put("id", new NBTTagString("NEW_YEAR_CAKE")); + demoItemExtraAttributes.put("uuid", new NBTTagString("64b3a60b-74f2-4ebd-818d-d019c5b7f3e0")); + demoItemExtraAttributes.put("timestamp", new NBTTagString("6/16/19 5:05 PM")); + MooConfigPreview nonStackableItemPreview = new MooConfigPreview(MooConfigPreview.createDemoItem("cake", "§dNew Year Cake", new String[]{"§7Given to every player as a", "§7celebration for the 1st SkyBlock", "§7year!", "", "§d§lSPECIAL"}, demoItemExtraAttributes)); + + Property propTooltipItemAge = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), + "tooltipItemAge", "always", "Show item age", new String[]{"always", "key press", "never"}), + nonStackableItemPreview); + + Property propTooltipItemAgeShortened = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), + "tooltipItemAgeShortened", true, "Shorten item age?")); + + Property propTooltipItemTimestamp = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), + "tooltipItemTimestamp", "key press", "Show item creation date", new String[]{"always", "key press", "never"})); + + 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"})); + + + // Category: SkyBlock Dungeons + configCat = new MooConfigCategory("SkyBlock Dungeons", "skyblockdungeons"); + configCat.setMenuDisplayName("SB Dungeons"); + configCategories.add(configCat); + + // Sub-Category: Tooltip enhancements + subCat = configCat.addSubCategory("Dungeon item tooltip enhancements"); + subCat.addExplanations("Hold left " + EnumChatFormatting.YELLOW + "SHIFT " + EnumChatFormatting.RESET + "while hovering over a dungeon item.", + "Shows " + EnumChatFormatting.YELLOW + "item quality " + EnumChatFormatting.RESET + "and " + EnumChatFormatting.YELLOW + "dungeon floor" + EnumChatFormatting.RESET + ", also remove stats from reforges and essences (✪)", + "which normally makes the comparison of dungeon items difficult.", + "Instead, the tooltip shows...", + " ‣ base/default stats " + EnumChatFormatting.GRAY + "(outside dungeons; 1st value - usually red or green)", + " ‣ stats inside dungeons " + EnumChatFormatting.GRAY + "(including dungeon level stat boost, but without essences [₀ₓ✪])", + " ‣ stats inside dungeons with 5x essence upgrades " + EnumChatFormatting.GRAY + "(₅ₓ✪)"); + + Property propDungItemToolTipToggleKeyBinding = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), + "dungItemToolTipToggleKeyBinding", Keyboard.KEY_LSHIFT, "Key to toggle dungeon item tooltip")); + + Property propDungItemQualityPos = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), + "dungItemQualityPos", "top", "Position of item quality in tooltip", new String[]{"top", "bottom"}), + new MooConfigPreview( + 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"))); + + // Sub-Category: Performance Overlay + subCat = configCat.addSubCategory("Performance Overlay"); + subCat.addExplanations(EnumChatFormatting.UNDERLINE + "Keeps track of:", + " ‣ skill score " + EnumChatFormatting.GRAY + "(reduced by deaths and failed puzzles)", + " ‣ speed score " + EnumChatFormatting.GRAY + "(-2.2 points when over 20 minutes)", + " ‣ bonus score " + EnumChatFormatting.GRAY + "(+1 [max 5] for each destroyed crypt; can only be detected up to ~50 blocks away from the player)", + "Does " + EnumChatFormatting.ITALIC + "not" + EnumChatFormatting.RESET + " track explorer score " + EnumChatFormatting.GRAY + "(explored rooms, secrets, ...)"); + + Property propDungOverlayEnabled = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), + "dungOverlayEnabled", true, "Enable Dungeon performance overlay?")); + + Property propDungOverlayPositionX = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), + "dungOverlayPositionX", 1, "Dungeon performance overlay position: x value", 0, 1000), + null, "‰", // per mille + (slider) -> { + MooConfig.dungOverlayPositionX = slider.getValueInt(); + MooConfigGui.showDungeonPerformanceOverlayUntil = System.currentTimeMillis() + 500; + }); + + Property propDungOverlayPositionY = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), + "dungOverlayPositionY", 1, "Dungeon performance overlay position: y value", 0, 1000), + null, "‰", // per mille + (slider) -> { + MooConfig.dungOverlayPositionY = slider.getValueInt(); + MooConfigGui.showDungeonPerformanceOverlayUntil = System.currentTimeMillis() + 500; + }); + + Property propDungOverlayGuiScale = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), + "dungOverlayGuiScale", 100, "Dungeon performance overlay GUI scale", 50, 200), + null, "%", + (slider) -> { + MooConfig.dungOverlayGuiScale = slider.getValueInt(); + MooConfigGui.showDungeonPerformanceOverlayUntil = System.currentTimeMillis() + 500; + }); + + Property propDungOverlayTextShadow = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), + "dungOverlayTextShadow", true, "Dungeon performance overlay GUI scale")); + + // Sub-Category: Party Finder + subCat = configCat.addSubCategory("Dungeon Party Finder"); + subCat.addExplanations("Adds various indicators to the dungeon party finder", + "to make it easier to find the perfect party:", + "", + "Marks parties...", + " ‣ you cannot join: " + EnumChatFormatting.RED + "⬛" + EnumChatFormatting.RESET + " (red carpet)", + " ‣ with someone below a certain class level: " + EnumChatFormatting.RED + EnumChatFormatting.BOLD + "ᐯ" + EnumChatFormatting.RESET, + " ‣ with duplicated roles you specify below: " + EnumChatFormatting.GOLD + "²⁺", + " ‣ that match your criteria: " + EnumChatFormatting.GREEN + "⬛" + EnumChatFormatting.RESET + " (green carpet)"); + + Property propDungClassMin = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), + "dungClassMin", 0, "Marks parties with members with lower class level than this value") + .setMinValue(0).setMaxValue(50), + new MooConfigPreview(new MooChatComponent("Marked with: " + EnumChatFormatting.RED + EnumChatFormatting.BOLD + "ᐯ").gray())); + + Property propDungFilterPartiesWithArcherDupes = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), + "dungFilterPartiesWithArcherDupes", true, "Mark parties with duplicated Archer class?"), + new MooConfigPreview(new MooChatComponent("Marked with: " + EnumChatFormatting.GOLD + "²⁺A").gray())); + + Property propDungFilterPartiesWithBerserkDupes = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), + "dungFilterPartiesWithBerserkDupes", false, "Mark parties with duplicated Berserk class?"), + new MooConfigPreview(new MooChatComponent("Marked with: " + EnumChatFormatting.GOLD + "²⁺B").gray())); + + Property propDungFilterPartiesWithHealerDupes = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), + "dungFilterPartiesWithHealerDupes", false, "Mark parties with duplicated Healer class?"), + new MooConfigPreview(new MooChatComponent("Marked with: " + EnumChatFormatting.GOLD + "²⁺H").gray())); + + Property propDungFilterPartiesWithMageDupes = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), + "dungFilterPartiesWithMageDupes", false, "Mark parties with duplicated Mage class?"), + new MooConfigPreview(new MooChatComponent("Marked with: " + EnumChatFormatting.GOLD + "²⁺M").gray())); + + Property propDungFilterPartiesWithTankDupes = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), + "dungFilterPartiesWithTankDupes", false, "Mark parties with duplicated Tank class?"), + new MooConfigPreview(new MooChatComponent("Marked with: " + EnumChatFormatting.GOLD + "²⁺T").gray())); + + Property propDungPartyFinderArmorLookup = subCat.addConfigEntry(cfg.get(configCat.getConfigName(), + "dungPartyFinderArmorLookup", "as a tooltip", "Show armor of player joining via party finder as a tooltip or in chat?", new String[]{"as a tooltip", "in chat", "disabled"})); - cfg.setCategoryPropertyOrder(CATEGORY_LOGS_SEARCH, propOrderLogsSearch); - - // 'manual' replacement for propTabCompletableNamesCommands.hasChanged() boolean modifiedTabCompletableCommandsList = false; String[] tabCompletableCommandsPreChange = tabCompletableNamesCommands != null ? tabCompletableNamesCommands.clone() : null; if (readFieldsFromConfig) { - // main config + // Category: General + configGuiExplanations = propConfigGuiExplanations.getString(); + tabCompletableNamesCommands = propTabCompletableNamesCommands.getStringList(); + logsDirs = propLogsDirs.getStringList(); + defaultStartDate = propDefaultStartDate.getString().trim(); + // Category: Notifications doUpdateCheck = propDoUpdateCheck.getBoolean(); showBestFriendNotifications = propShowBestFriendNotifications.getBoolean(); showFriendNotifications = propShowFriendNotifications.getBoolean(); showGuildNotifications = propShowGuildNotifications.getBoolean(); doBestFriendsOnlineCheck = propDoBestFriendsOnlineCheck.getBoolean(); - showAdvancedTooltips = propShowAdvancedTooltips.getBoolean(); + // Category: SkyBlock + tooltipToggleKeyBinding = propTooltipToggleKeyBinding.getInt(); + tooltipAuctionHousePriceEach = propTooltipAuctionHousePriceEach.getString(); + tooltipItemAge = propTooltipItemAge.getString(); + tooltipItemAgeShortened = propTooltipItemAgeShortened.getBoolean(); + tooltipItemTimestamp = propTooltipItemTimestamp.getString(); numeralSystem = propNumeralSystem.getString(); - tabCompletableNamesCommands = propTabCompletableNamesCommands.getStringList(); - moo = propMoo.getString(); - - // SkyBlock dungeon - dungClassRange = propDungClassRange.getIntList(); - dungFilterPartiesWithDupes = propDungFilterPartiesWithDupes.getBoolean(); - dungPartyFinderArmorLookup = propDungPartyFinderArmorLookup.getString(); + // Category: SkyBlock Dungeons + dungItemToolTipToggleKeyBinding = propDungItemToolTipToggleKeyBinding.getInt(); dungItemQualityPos = propDungItemQualityPos.getString(); dungOverlayEnabled = propDungOverlayEnabled.getBoolean(); dungOverlayPositionX = propDungOverlayPositionX.getInt(); dungOverlayPositionY = propDungOverlayPositionY.getInt(); dungOverlayGuiScale = propDungOverlayGuiScale.getInt(); + dungOverlayTextShadow = propDungOverlayTextShadow.getBoolean(); + dungClassMin = propDungClassMin.getInt(); + dungFilterPartiesWithArcherDupes = propDungFilterPartiesWithArcherDupes.getBoolean(); + dungFilterPartiesWithBerserkDupes = propDungFilterPartiesWithBerserkDupes.getBoolean(); + dungFilterPartiesWithHealerDupes = propDungFilterPartiesWithHealerDupes.getBoolean(); + dungFilterPartiesWithMageDupes = propDungFilterPartiesWithMageDupes.getBoolean(); + dungFilterPartiesWithTankDupes = propDungFilterPartiesWithTankDupes.getBoolean(); + dungPartyFinderArmorLookup = propDungPartyFinderArmorLookup.getString(); - // logs search config - logsDirs = propLogsDirs.getStringList(); - defaultStartDate = propDefaultStartDate.getString().trim(); if (!Arrays.equals(tabCompletableCommandsPreChange, tabCompletableNamesCommands)) { modifiedTabCompletableCommandsList = true; } } - // main config + // Category: General + propConfigGuiExplanations.set(configGuiExplanations); + propTabCompletableNamesCommands.set(tabCompletableNamesCommands); + propLogsDirs.set(logsDirs); + propDefaultStartDate.set(defaultStartDate); + // Category: Notifications propDoUpdateCheck.set(doUpdateCheck); propShowBestFriendNotifications.set(showBestFriendNotifications); propShowFriendNotifications.set(showFriendNotifications); propShowGuildNotifications.set(showGuildNotifications); propDoBestFriendsOnlineCheck.set(doBestFriendsOnlineCheck); - propShowAdvancedTooltips.set(showAdvancedTooltips); + // Category: SkyBlock + propTooltipToggleKeyBinding.set(tooltipToggleKeyBinding); + propTooltipAuctionHousePriceEach.set(tooltipAuctionHousePriceEach); + propTooltipItemAge.set(tooltipItemAge); + propTooltipItemAgeShortened.set(tooltipItemAgeShortened); + propTooltipItemTimestamp.set(tooltipItemTimestamp); propNumeralSystem.set(numeralSystem); - propTabCompletableNamesCommands.set(tabCompletableNamesCommands); - propMoo.set(moo); - - // SkyBlock dungeon - propDungClassRange.set(dungClassRange); - propDungFilterPartiesWithDupes.set(dungFilterPartiesWithDupes); - propDungPartyFinderArmorLookup.set(dungPartyFinderArmorLookup); + // Category: SkyBlock Dungeons + propDungItemToolTipToggleKeyBinding.set(dungItemToolTipToggleKeyBinding); propDungItemQualityPos.set(dungItemQualityPos); propDungOverlayEnabled.set(dungOverlayEnabled); propDungOverlayPositionX.set(dungOverlayPositionX); propDungOverlayPositionY.set(dungOverlayPositionY); propDungOverlayGuiScale.set(dungOverlayGuiScale); + propDungOverlayTextShadow.set(dungOverlayTextShadow); + propDungClassMin.set(dungClassMin); + propDungFilterPartiesWithArcherDupes.set(dungFilterPartiesWithArcherDupes); + propDungFilterPartiesWithBerserkDupes.set(dungFilterPartiesWithBerserkDupes); + propDungFilterPartiesWithHealerDupes.set(dungFilterPartiesWithHealerDupes); + propDungFilterPartiesWithMageDupes.set(dungFilterPartiesWithMageDupes); + propDungFilterPartiesWithTankDupes.set(dungFilterPartiesWithTankDupes); + propDungPartyFinderArmorLookup.set(dungPartyFinderArmorLookup); - // logs search config - propLogsDirs.set(logsDirs); - propDefaultStartDate.set(defaultStartDate); - - if (cfg.hasChanged()) { + if (saveToFile && cfg.hasChanged()) { boolean isPlayerIngame = Minecraft.getMinecraft().thePlayer != null; if (modifiedTabCompletableCommandsList) { if (isPlayerIngame) { @@ -269,31 +498,9 @@ public class MooConfig { propTabCompletableNamesCommands.set(tabCompletableNamesCommands); } } - if (isPlayerIngame && dungClassRange[0] > -1 && dungClassRange[1] > -1 && dungClassRange[0] > dungClassRange[1]) { - main.getChatHelper().sendMessage(EnumChatFormatting.RED, "Dungeon class range minimum value cannot be higher than the maximum value."); - } - cfg.save(); - } - } - private Property addConfigEntry(Property property, boolean showInGui, String category) { - if (showInGui) { - property.setLanguageKey(Cowlection.MODID + ".config." + property.getName()); - } else { - property.setShowInGui(false); - } - - if (CATEGORY_LOGS_SEARCH.equals(category)) { - propOrderLogsSearch.add(property.getName()); - } else { - // == Configuration.CATEGORY_CLIENT: - propOrderGeneral.add(property.getName()); + cfg.save(); } - return property; - } - - private Property addConfigEntry(Property property, boolean showInGui) { - return addConfigEntry(property, showInGui, Configuration.CATEGORY_CLIENT); } /** @@ -329,6 +536,13 @@ public class MooConfig { return logsDirs.toArray(new String[]{}); } + // Category: General + public static Setting getConfigGuiExplanationsDisplay() { + return Setting.get(configGuiExplanations); + } + + // Category: Notifications + /** * Should login/logout notifications be modified and thus monitored? * @@ -338,18 +552,88 @@ public class MooConfig { return showBestFriendNotifications || !showFrien