aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md15
-rw-r--r--README.md7
-rw-r--r--src/main/java/de/cowtipper/cowlection/Cowlection.java10
-rw-r--r--src/main/java/de/cowtipper/cowlection/command/MooCommand.java65
-rw-r--r--src/main/java/de/cowtipper/cowlection/command/exception/ApiContactException.java5
-rw-r--r--src/main/java/de/cowtipper/cowlection/config/DungeonOverlayGuiConfig.java129
-rw-r--r--src/main/java/de/cowtipper/cowlection/config/MooConfig.java614
-rw-r--r--src/main/java/de/cowtipper/cowlection/config/MooGuiConfig.java85
-rw-r--r--src/main/java/de/cowtipper/cowlection/config/MooGuiFactory.java29
-rw-r--r--src/main/java/de/cowtipper/cowlection/config/gui/MooConfigCategoryScrolling.java856
-rw-r--r--src/main/java/de/cowtipper/cowlection/config/gui/MooConfigGui.java206
-rw-r--r--src/main/java/de/cowtipper/cowlection/config/gui/MooConfigMenuList.java70
-rw-r--r--src/main/java/de/cowtipper/cowlection/config/gui/MooConfigPreview.java175
-rw-r--r--src/main/java/de/cowtipper/cowlection/data/DataHelper.java22
-rw-r--r--src/main/java/de/cowtipper/cowlection/data/HyApiKey.java20
-rw-r--r--src/main/java/de/cowtipper/cowlection/handler/FriendsHandler.java6
-rw-r--r--src/main/java/de/cowtipper/cowlection/listener/ChatListener.java11
-rw-r--r--src/main/java/de/cowtipper/cowlection/listener/PlayerListener.java29
-rw-r--r--src/main/java/de/cowtipper/cowlection/listener/skyblock/DungeonsListener.java130
-rw-r--r--src/main/java/de/cowtipper/cowlection/listener/skyblock/SkyBlockListener.java41
-rw-r--r--src/main/java/de/cowtipper/cowlection/search/GuiSearch.java45
-rw-r--r--src/main/java/de/cowtipper/cowlection/search/LogFilesSearcher.java4
-rw-r--r--src/main/java/de/cowtipper/cowlection/util/ApiUtils.java16
-rw-r--r--src/main/java/de/cowtipper/cowlection/util/Utils.java2
-rw-r--r--src/main/resources/assets/cowlection/lang/en_US.lang76
25 files changed, 2110 insertions, 558 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d7e47d0..7c65f95 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,20 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
+## [1.8.9-0.11.0] - unreleased
+### Changed
+- Completely re-done the config gui (`/moo config`)
+ - now separated into sections and sub-sections
+ - added moar configurable things
+ - some config settings have a live-preview next to them
+- Improved SkyBlock dungeon party finder
+ - more config options
+ - marks (non-)joinable parties even better than before
+- Improved SkyBlock dungeon performance overlay
+ - Overlay can be moved more precisely
+ - Dungeons can be "joined" and "left" manually (if the automatic detection fails): `/moo dungeon <enter/leave>`
+- Improved handling of invalid/missing Hypixel API key
+
## [1.8.9-0.10.2] - 15.09.2020
### Added
- Added keybinding (default `M`) to open chat with `/moo ` pre-typed
@@ -195,6 +209,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
*Note:* The 'best friends' list is currently available via <kbd>ESC</kbd> > Mod Options > Cowlection > Config > bestFriends.
+[1.8.9-0.11.0]: https://github.com/cow-mc/Cowlection/compare/v1.8.9-0.10.2...master
[1.8.9-0.10.2]: https://github.com/cow-mc/Cowlection/compare/v1.8.9-0.10.1...v1.8.9-0.10.2
[1.8.9-0.10.1]: https://github.com/cow-mc/Cowlection/compare/v1.8.9-0.10.0...v1.8.9-0.10.1
[1.8.9-0.10.0]: https://github.com/cow-mc/Cowlection/compare/v1.8.9-0.9.0...v1.8.9-0.10.0
diff --git a/README.md b/README.md
index 2687fca..1661b74 100644
--- a/README.md
+++ b/README.md
@@ -6,13 +6,14 @@ It is a collection of different features mainly focused on Hypixel SkyBlock. đŸ
## Current features
➜ Use `/moo help` to see all available commands.
+➜ Use `/moo config` to adjust the features to your needs.
| Feature | Command/Usage |
|-------------------------------------------------------------------------|-----------------------------------------|
| 'Best friends' list to limit the amount of join and leave notifications (always up-to-date names even after player name changes). Also checks best friends' online status automatically | `/moo add/remove/list/online` |
| Search through your Minecraft log files (click the `?` for more info) | `/moo search` |
| Stalk a player (check online status, current game, ...) | `/moo stalk` |
-| Toggle join/leave notifications for friends, guild members or best friends separately | `/moo toggle` |
+| Toggle join/leave notifications for friends, guild members or best friends separately | `/moo config` &rarr; Notifications |
| Copy chat component | <kbd>ALT</kbd> + <kbd>right click</kbd><br>Hold <kbd>shift</kbd> to copy full component |
| Copy inventories to clipboard as JSON | <kbd>CTRL</kbd> + <kbd>C</kbd> |
| Tab-completable usernames for several commands (e.g. `/party`, `/invite`, ...) | `/moo config` &rarr; `Commands with Tab-completable usernames` for full list of commands |
@@ -25,8 +26,8 @@ It is a collection of different features mainly focused on Hypixel SkyBlock. đŸ
|-------------------------------------------------------------------------|-----------------------------------------|
| Stalk SkyBlock stats of a player | `/moo stalkskyblock` |
| Analyze minions on a private island | `/moo analyzeIsland` |
-| Dungeon interfaces enhancements (normalize dungeon item stats, improved party finder) | Hold <kbd>shift</kbd> while viewing a dungeon item tooltip |
-| Dungeon performance tracker: Skill score calculation, class milestone tracker, destroyed crypts tracker, and elapsed time indicator | automatically; or with `/moo dungeon`; Overlay can be edited with `/moo dungeonGui` |
+| Dungeon interfaces enhancements (normalize dungeon item stats, improved party finder) | Hold <kbd>shift</kbd> (configurable) while viewing a dungeon item tooltip |
+| Dungeon performance tracker and overlay: Skill score calculation, class milestone tracker, destroyed crypts tracker, and elapsed time indicator | automatically; or with `/moo dungeon` |
## Download
You can download the compiled .jar files from the [release section](https://github.com/cow-mc/Cowlection/releases).
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 <playerName>");
- }
+ 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 <key>" + 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 <playerName>");
+ }
+ }
+
private void handleNameChangeCheck(String[] args) throws CommandException {
if (args.length != 2) {
throw new WrongUsageException("/" + getCommandName() + " nameChangeCheck <playerName>");
@@ -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<String> 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
* <p>
* Based on <a href="https://github.com/TheGreyGhost/MinecraftByExample/blob/1-8-9final/src/main/java/minecraftbyexample/mbe70_configuration/MBEConfiguration.java">TheGreyGhost's MinecraftByExample</a>
*
* @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<MooConfigCategory> configCategories = new ArrayList<>();
private final Cowlection main;
- private List<String> propOrderGeneral;
- private List<String> propOrderLogsSearch;
+ private Property propTabCompletableNamesCommands;
+ private List<Property> 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 <player>" + 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<String, NBTBase> 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 || !showFriendNotifications || !showGuildNotifications;
}
+ // Category: SkyBlock
+ public static Setting getTooltipAuctionHousePriceEachDisplay() {
+ return Setting.get(tooltipAuctionHousePriceEach);
+ }
+
+ public static Setting getTooltipItemAgeDisplay() {
+ return Setting.get(tooltipItemAge);
+ }
+
+ public static Setting getTooltipItemTimestampDisplay() {
+ return Setting.get(tooltipItemTimestamp);
+ }
+
public static boolean useRomanNumerals() {
return numeralSystem.startsWith("Roman");
}
+ public static boolean isTooltipToggleKeyBindingPressed() {
+ return tooltipToggleKeyBinding > 0 && Keyboard.isKeyDown(MooConfig.tooltipToggleKeyBinding);
+ }
+
+ public static boolean isDungeonItemTooltipToggleKeyBindingPressed() {
+ return dungItemToolTipToggleKeyBinding > 0 && Keyboard.isKeyDown(MooConfig.dungItemToolTipToggleKeyBinding);
+ }
+
+ // Category: SkyBlock Dungeons
public static boolean isDungItemQualityAtTop() {
return dungItemQualityPos.equals("top");
}
- public static boolean showArmorLookupInChat() {
- return "in chat".equals(dungPartyFinderArmorLookup);
+ public static Setting getDungPartyFinderArmorLookupDisplay() {
+ return Setting.get(dungPartyFinderArmorLookup);
+ }
+
+ public static boolean filterDungPartiesWithDupes(DataHelper.DungeonClass dungeonClass) {
+ switch (dungeonClass) {
+ case ARCHER:
+ return dungFilterPartiesWithArcherDupes;
+ case BERSERK:
+ return dungFilterPartiesWithBerserkDupes;
+ case HEALER:
+ return dungFilterPartiesWithHealerDupes;
+ case MAGE:
+ return dungFilterPartiesWithMageDupes;
+ case TANK:
+ return dungFilterPartiesWithTankDupes;
+ default:
+ return false;
+ }
}
+ // MC Log Search:
+ 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);
+ }
+ }
+
+ // other stuff
+ public static List<MooConfigCategory> getConfigCategories() {
+ return configCategories;
+ }
+
+ public Property getTabCompletableNamesCommandsProperty() {
+ return propTabCompletableNamesCommands;
+ }
+
+ public List<Property> getLogSearchProperties() {
+ return logSearchProperties;
+ }
+
+
public class ConfigEventHandler {
@SubscribeEvent(priority = EventPriority.NORMAL)
public void onEvent(ConfigChangedEvent.OnConfigChangedEvent e) {
@@ -358,4 +642,32 @@ public class MooConfig {
}
}
}
+
+ public enum Setting {
+ UNKNOWN, DISABLED, //
+ ALWAYS, TOOLTIP, TEXT, //
+ SPECIAL;
+
+ public static Setting get(String configValue) {
+ switch (configValue) {
+ case "always":
+ return ALWAYS;
+ case "as a tooltip":
+ case "as tooltip ②§f⬛":
+ return TOOLTIP;
+ case "in chat":
+ case "as text":
+ return TEXT;
+ case "hidden":
+ case "never":
+ case "disabled":
+ return DISABLED;
+ case "key press":
+ case "as tooltip ①§0⬛":
+ return SPECIAL;
+ default:
+ return UNKNOWN;
+ }
+ }
+ }
}
diff --git a/src/main/java/de/cowtipper/cowlection/config/MooGuiConfig.java b/src/main/java/de/cowtipper/cowlection/config/MooGuiConfig.java
deleted file mode 100644
index 3db7cf3..0000000
--- a/src/main/java/de/cowtipper/cowlection/config/MooGuiConfig.java
+++ /dev/null
@@ -1,85 +0,0 @@
-package de.cowtipper.cowlection.config;
-
-import de.cowtipper.cowlection.Cowlection;
-import de.cowtipper.cowlection.search.GuiTooltip;
-import net.minecraft.client.gui.GuiButton;
-import net.minecraft.client.gui.GuiScreen;
-import net.minecraft.client.gui.GuiTextField;
-import net.minecraft.client.resources.I18n;
-import net.minecraft.util.EnumChatFormatting;
-import net.minecraftforge.common.config.ConfigElement;
-import net.minecraftforge.common.config.Configuration;
-import net.minecraftforge.fml.client.config.GuiConfig;
-import net.minecraftforge.fml.client.config.GuiConfigEntries;
-import net.minecraftforge.fml.client.config.IConfigElement;
-import org.apache.commons.lang3.reflect.FieldUtils;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-public class MooGuiConfig extends GuiConfig {
- private GuiTooltip defaultStartDateTooltip;
- private GuiTextField textFieldDefaultStartDate;
- private String defaultStartDateTooltipText;
-
- public MooGuiConfig(GuiScreen parent) {
- super(parent,
- getConfigElements(),
- Cowlection.MODID,
- false,
- false,
- EnumChatFormatting.BOLD + "Configuration for " + Cowlection.MODNAME);
- titleLine2 = EnumChatFormatting.GRAY + GuiConfig.getAbridgedConfigPath(MooConfig.getConfig().toString());
- }
-
- private static List<IConfigElement> getConfigElements() {
- List<IConfigElement> list = new ArrayList<>(new ConfigElement(MooConfig.getConfig().getCategory(Configuration.CATEGORY_CLIENT)).getChildElements());
- list.addAll(new ConfigElement(MooConfig.getConfig().getCategory(MooConfig.CATEGORY_LOGS_SEARCH)).getChildElements());
- return list;
- }
-
- @Override
- public void initGui() {
- super.initGui();
- // optional: add buttons and initialize fields
- for (GuiConfigEntries.IConfigEntry configEntry : entryList.listEntries) {
- if ("defaultStartDate".equals(configEntry.getName()) && configEntry instanceof GuiConfigEntries.StringEntry) {
- GuiConfigEntries.StringEntry entry = (GuiConfigEntries.StringEntry) configEntry;
- defaultStartDateTooltipText = I18n.format(configEntry.getConfigElement().getLanguageKey() + ".tooltip");
- try {
- textFieldDefaultStartDate = (GuiTextField) FieldUtils.readField(entry, "textFieldValue", true);
- defaultStartDateTooltip = null;
- } catch (IllegalAccessException e) {
- // wasn't able to access textField, abort drawing tooltip
- return;
- }
- }
- }
- }
-
- @Override
- public void drawScreen(int mouseX, int mouseY, float partialTicks) {
- super.drawScreen(mouseX, mouseY, partialTicks);
- // optional: create animations, draw additional elements, etc.
-
- // add tooltip to defaultStartDate textField
- if (textFieldDefaultStartDate != null) {
- if (defaultStartDateTooltip == null) {
- if (textFieldDefaultStartDate.yPosition == 0) {
- return;
- }
- // create GuiTooltip here instead in initGui because y-position of textField is 0 inside initGui
- defaultStartDateTooltip = new GuiTooltip(textFieldDefaultStartDate, Arrays.asList(defaultStartDateTooltipText.split("\\\\n")));
- } else if (defaultStartDateTooltip.checkHover(mouseX, mouseY)) {
- drawHoveringText(defaultStartDateTooltip.getText(), mouseX, mouseY, fontRendererObj);
- }
- }
- }
-
- @Override
- protected void actionPerformed(GuiButton button) {
- super.actionPerformed(button);
- // optional: process any additional buttons added in initGui
- }
-}
diff --git a/src/main/java/de/cowtipper/cowlection/config/MooGuiFactory.java b/src/main/java/de/cowtipper/cowlection/config/MooGuiFactory.java
deleted file mode 100644
index eedd676..0000000
--- a/src/main/java/de/cowtipper/cowlection/config/MooGuiFactory.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package de.cowtipper.cowlection.config;
-
-import net.minecraft.client.Minecraft;
-import net.minecraft.client.gui.GuiScreen;
-import net.minecraftforge.fml.client.IModGuiFactory;
-
-import java.util.Set;
-
-public class MooGuiFactory implements IModGuiFactory {
- @Override
- public void initialize(Minecraft minecraftInstance) {
-
- }
-
- @Override
- public Class<? extends GuiScreen> mainConfigGuiClass() {
- return MooGuiConfig.class;
- }
-
- @Override
- public Set<RuntimeOptionCategoryElement> runtimeGuiCategories() {
- return null;
- }
-
- @Override
- public RuntimeOptionGuiHandler getHandlerFor(RuntimeOptionCategoryElement element) {
- return null;
- }
-}
diff --git a/src/main/java/de/cowtipper/cowlection/config/gui/MooConfigCategoryScrolling.java b/src/main/java/de/cowtipper/cowlection/config/gui/MooConfigCategoryScrolling.java
new file mode 100644
index 0000000..d362502
--- /dev/null
+++ b/src/main/java/de/cowtipper/cowlection/config/gui/MooConfigCategoryScrolling.java
@@ -0,0 +1,856 @@
+package de.cowtipper.cowlection.config.gui;
+
+import com.google.common.collect.Lists;
+import de.cowtipper.cowlection.Cowlection;
+import de.cowtipper.cowlection.config.MooConfig;
+import de.cowtipper.cowlection.config.MooConfigCategory;
+import de.cowtipper.cowlection.search.GuiSearch;
+import de.cowtipper.cowlection.util.GuiHelper;
+import de.cowtipper.cowlection.util.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.*;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.client.renderer.Tessellator;
+import net.minecraft.client.renderer.WorldRenderer;
+import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
+import net.minecraft.client.resources.I18n;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.MathHelper;
+import net.minecraftforge.common.config.ConfigElement;
+import net.minecraftforge.common.config.Property;
+import net.minecraftforge.fml.client.config.GuiButtonExt;
+import net.minecraftforge.fml.client.config.GuiConfig;
+import net.minecraftforge.fml.client.config.GuiSlider;
+import net.minecraftforge.fml.client.config.HoverChecker;
+import net.minecraftforge.fml.relauncher.Side;
+import net.minecraftforge.fml.relauncher.SideOnly;
+import org.apache.commons.lang3.NotImplementedException;
+import org.apache.commons.lang3.StringUtils;
+import org.lwjgl.input.Keyboard;
+
+import java.util.*;
+
+import static net.minecraftforge.fml.client.config.GuiUtils.RESET_CHAR;
+import static net.minecraftforge.fml.client.config.GuiUtils.UNDO_CHAR;
+
+/**
+ * Based on {@link net.minecraft.client.gui.GuiKeyBindingList}
+ */
+public class MooConfigCategoryScrolling extends GuiListExtended {
+ private final Minecraft mc;
+ private final List<IGuiListEntry> listEntries;
+ private final Map<Integer, List<String>> explanations;
+ private final MooConfigGui parent;
+ private final int marginLeft;
+ private int maxListLabelWidth = 0;
+ private KeyBindingConfigEntry currentKeyBindingConfigEntry = null;
+ /**
+ * listEntryIndex => (sub-category) preview
+ */
+ private final NavigableMap<Integer, MooConfigPreview> listEntriesPreviews;
+
+ public MooConfigCategoryScrolling(MooConfigGui parent, Minecraft mc, MooConfigCategory currentConfigCategory, int marginLeft) {
+ super(mc, parent.width - marginLeft, parent.height, 32, parent.height - 5, 20);
+ this.parent = parent;
+ this.marginLeft = marginLeft;
+ setSlotXBoundsFromLeft(marginLeft);
+ this.mc = mc;
+ listEntriesPreviews = new TreeMap<>();
+ explanations = new HashMap<>();
+
+ this.listEntries = new ArrayList<>();
+ for (MooConfigCategory.SubCategory subCategory : currentConfigCategory.getSubCategories()) {
+ int subCategoryStartIndex = this.listEntries.size();
+ this.listEntries.add(new MooConfigCategoryScrolling.CategoryEntry(subCategory.getDisplayName(), !subCategory.getExplanations().isEmpty()));
+
+ explanations.put(subCategoryStartIndex, subCategory.getExplanations());
+ int explanationsLineCount = 0;
+ if (subCategory.getExplanations().size() > 0 && MooConfig.getConfigGuiExplanationsDisplay() == MooConfig.Setting.TEXT) {
+ Iterator<String> explanationsIterator = subCategory.getExplanations().iterator();
+ explanationsIterator.next(); // skip first entry (= sub category name)
+ while (explanationsIterator.hasNext()) {
+ String msgLine = explanationsIterator.next();
+ if (explanationsIterator.hasNext()) {
+ msgLine += "\n" + explanationsIterator.next();
+ }
+ this.listEntries.add(new ExplanationsEntry(msgLine));
+ ++explanationsLineCount;
+ }
+ }
+
+ // 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(), ""));
+ }));
+ continue; // don't add properties to main config gui
+ }
+
+ // add previews
+ Map<Integer, MooConfigPreview> previews = subCategory.getPreviews();
+ this.listEntriesPreviews.put(subCategoryStartIndex, null);
+ // previews for specific properties
+ for (Map.Entry<Integer, MooConfigPreview> previewEntry : previews.entrySet()) {
+ this.listEntriesPreviews.put(subCategoryStartIndex + explanationsLineCount + previewEntry.getKey(), previewEntry.getValue());
+ }
+
+ // add config elements
+ for (Property configEntry : subCategory.getConfigEntries()) {
+ int labelWidth = mc.fontRendererObj.getStringWidth(I18n.format(configEntry.getLanguageKey()));
+
+ if (labelWidth > this.maxListLabelWidth) {
+ this.maxListLabelWidth = labelWidth;
+ }
+
+ Property.Type type = configEntry.getType();
+ if (configEntry.isList() && type == Property.Type.STRING && configEntry.equals(Cowlection.getInstance().getConfig().getTabCompletableNamesCommandsProperty())) {
+ this.listEntries.add(new GuiSwitchEntry("tabCompletableNamesCommands", "➡ modify", () ->
+ mc.displayGuiScreen(new GuiConfig(MooConfigCategoryScrolling.this.parent,
+ Lists.newArrayList(new ConfigElement(Cowlection.getInstance().getConfig().getTabCompletableNamesCommandsProperty())),
+ Cowlection.MODID, "cowlectionTabCompletableCommands", false, false,
+ EnumChatFormatting.GOLD + "Press 2x Done to save changes. " + EnumChatFormatting.RED + "Requires a game restart to take effect!"))));
+ continue;
+ } else if (type == Property.Type.BOOLEAN) {
+ this.listEntries.add(new BooleanConfigEntry(configEntry));
+ continue;
+ } else if (type == Property.Type.INTEGER) {
+ if (configEntry.getLanguageKey() != null && configEntry.getLanguageKey().endsWith("KeyBinding")) {
+ // special case: key binding
+ this.listEntries.add(new KeyBindingConfigEntry(configEntry));
+ continue;
+ } else if (configEntry.isIntValue() && configEntry.getMinValue() != null && configEntry.getMaxValue() != null) {
+ // generic special case: int value with min & max value
+ this.listEntries.add(new NumberSliderConfigEntry(configEntry,
+ subCategory.getGuiSliderExtra(configEntry.getLanguageKey())));
+ continue;
+ }
+ } else if (type == Property.Type.STRING) {
+ if (configEntry.getLanguageKey().equals(Cowlection.MODID + ".config.isMooValid")) {
+ // special case: moo!
+ this.listEntries.add(new BooleanConfigEntry(configEntry));
+ continue;
+ } else if (configEntry.getValidValues() != null && configEntry.getValidValues().length > 0) {
+ this.listEntries.add(new CycleConfigEntry(configEntry));
+ continue;
+ }
+ }
+ // type == Property.Type.DOUBLE
+ // type == Property.Type.COLOR // => ChatColorEntry#drawEntry
+ // type == Property.Type.MOD_ID
+ // + some other cases
+ throw new NotImplementedException("Unsupported config entry of type " + configEntry.getType() + " (" + configEntry.getName() + ")");
+ }
+ }
+ }
+
+ protected int getSize() {
+ return this.listEntries.size();
+ }
+
+ /**
+ * Gets the IGuiListEntry object for the given index
+ */
+ public GuiListExtended.IGuiListEntry getListEntry(int index) {
+ return this.listEntries.get(index);
+ }
+
+ @Override
+ protected void drawSlot(int slotIndex, int x, int y, int slotHeight, int mouseXIn, int mouseYIn) {
+ if (y >= this.top - 5 && y <= this.bottom) {
+ // entry is visible
+ IGuiListEntry listEntry = this.getListEntry(slotIndex);
+
+ MooConfigPreview preview = listEntriesPreviews.get(slotIndex);
+ boolean enablePreview = true;
+ if (preview != null) {
+ // draw preview
+ if (listEntry instanceof BaseConfigEntry) {
+ Property property = ((BaseConfigEntry) listEntry).property;
+ if (property.isBooleanValue()) {
+ enablePreview = property.getBoolean();
+ }
+ }
+ preview.drawPreview(x + getListWidth(), y, mouseXIn, mouseYIn, enablePreview);
+ }
+
+ listEntry.drawEntry(slotIndex, x, y, this.getListWidth(), slotHeight, mouseXIn, mouseYIn, this.getSlotIndexFromScreenCoords(mouseXIn, mouseYIn) == slotIndex);
+ }
+ }
+
+ protected int getScrollBarX() {
+ return this.left + 5;
+ }
+
+ /**
+ * Gets the width of the list (label + property element [button/textbox] + undo and reset buttons; without preview)
+ */
+ public int getListWidth() {
+ return maxListLabelWidth + 135;
+ }
+
+ private int hoveredSlotIndex = -2;
+
+ @Override
+ public int getSlotIndexFromScreenCoords(int mouseX, int mouseY) {
+ int k = mouseY - this.top - this.headerPadding + (int) this.amountScrolled - 4;
+ int slotIndex = k / this.slotHeight;
+ int result = isMouseYWithinSlotBounds(mouseY) && slotIndex < this.getSize() ? slotIndex : -1;
+ if (result != hoveredSlotIndex) {
+ hoveredSlotIndex = result;
+ }
+ return result;
+ }
+
+ @Override
+ protected void overlayBackground(int startY, int endY, int startAlpha, int endAlpha) {
+ // no overlay needed; entries are not drawn when they're out of the draw area
+ }
+
+ @Override
+ protected void drawContainerBackground(Tessellator tessellator) {
+ // default behavior: draw dirt background
+ }
+
+ @Override
+ public void drawScreen(int mouseX, int mouseY, float p_148128_3_) {
+ if (this.field_178041_q) {
+ this.bindAmountScrolled();
+ this.mouseX = mouseX;
+ this.mouseY = mouseY;
+ this.drawBackground();
+ GlStateManager.disableLighting();
+ GlStateManager.disableFog();
+ Tessellator tessellator = Tessellator.getInstance();
+ WorldRenderer worldrenderer = tessellator.getWorldRenderer();
+ // Forge: background rendering moved into separate method.
+ this.drawContainerBackground(tessellator);
+ int x = this.left + 20; // menu + 20 margin
+ int y = this.top + 4 - (int) this.amountScrolled;
+
+ if (this.hasListHeader) {
+ this.drawListHeader(x, y, tessellator);
+ }
+
+ this.drawSelectionBox(x, y, mouseX, mouseY);
+ GlStateManager.disableDepth();
+ this.overlayBackground(0, this.top, 255, 255);
+ this.overlayBackground(this.bottom, this.height, 255, 255);
+ GlStateManager.enableBlend();
+ GlStateManager.tryBlendFuncSeparate(770, 771, 0, 1);
+ GlStateManager.disableAlpha();
+ GlStateManager.shadeModel(7425);
+ GlStateManager.disableTexture2D();
+
+ int maxScroll = this.func_148135_f();
+ if (maxScroll > 0) {
+ // draw scrollbars
+ int scrollBarX = this.getScrollBarX();
+ int scrollBarXEnd = scrollBarX + 6;
+
+ int k1 = (this.bottom - this.top) * (this.bottom - this.top) / this.getContentHeight();
+ k1 = MathHelper.clamp_int(k1, 32, this.bottom - this.top - 8);
+ int l1 = (int) this.amountScrolled * (this.bottom - this.top - k1) / maxScroll + this.top;
+
+ if (l1 < this.top) {
+ l1 = this.top;
+ }
+
+ worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR);
+ worldrenderer.pos(scrollBarX, this.bottom, 0.0D).tex(0.0D, 1.0D).color(0, 0, 0, 255).endVertex();
+ worldrenderer.pos(scrollBarXEnd, this.bottom, 0.0D).tex(1.0D, 1.0D).color(0, 0, 0, 255).endVertex();
+ worldrenderer.pos(scrollBarXEnd, this.top, 0.0D).tex(1.0D, 0.0D).color(0, 0, 0, 255).endVertex();
+ worldrenderer.pos(scrollBarX, this.top, 0.0D).tex(0.0D, 0.0D).color(0, 0, 0, 255).endVertex();
+ tessellator.draw();
+ worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR);
+ worldrenderer.pos(scrollBarX, l1 + k1, 0.0D).tex(0.0D, 1.0D).color(128, 128, 128, 255).endVertex();
+ worldrenderer.pos(scrollBarXEnd, l1 + k1, 0.0D).tex(1.0D, 1.0D).color(128, 128, 128, 255).endVertex();
+ worldrenderer.pos(scrollBarXEnd, l1, 0.0D).tex(1.0D, 0.0D).color(128, 128, 128, 255).endVertex();
+ worldrenderer.pos(scrollBarX, l1, 0.0D).tex(0.0D, 0.0D).color(128, 128, 128, 255).endVertex();
+ tessellator.draw();
+ worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR);
+ worldrenderer.pos(scrollBarX, l1 + k1 - 1, 0.0D).tex(0.0D, 1.0D).color(192, 192, 192, 255).endVertex();
+ worldrenderer.pos(scrollBarXEnd - 1, l1 + k1 - 1, 0.0D).tex(1.0D, 1.0D).color(192, 192, 192, 255).endVertex();
+ worldrenderer.pos(scrollBarXEnd - 1, l1, 0.0D).tex(1.0D, 0.0D).color(192, 192, 192, 255).endVertex();
+ worldrenderer.pos(scrollBarX, l1, 0.0D).tex(0.0D, 0.0D).color(192, 192, 192, 255).endVertex();
+ tessellator.draw();
+ }
+
+ this.func_148142_b(mouseX, mouseY); // GuiSlot#renderDecorations
+ GlStateManager.enableTexture2D();
+ GlStateManager.shadeModel(7424);
+ GlStateManager.enableAlpha();
+ GlStateManager.disableBlend();
+
+ // draw tooltips:
+ if (hoveredSlotIndex >= 0) {
+ // draw tooltip for category heading
+ List<String> explanations = this.explanations.get(hoveredSlotIndex);
+ MooConfig.Setting configGuiExplanationsDisplay = MooConfig.getConfigGuiExplanationsDisplay();
+ if (explanations != null && !explanations.isEmpty() && (configGuiExplanationsDisplay == MooConfig.Setting.TOOLTIP || configGuiExplanationsDisplay == MooConfig.Setting.SPECIAL)) {
+ if (configGuiExplanationsDisplay == MooConfig.Setting.SPECIAL) {
+ Gui.drawRect(0, 0, this.right, this.bottom + 20, 0x99111111);
+ }
+ GuiHelper.drawHoveringText(explanations, this.getScrollBarX(), mouseY, parent.width, parent.height, parent.width - this.getScrollBarX() - 30);
+ GlStateManager.disableLighting();
+ }
+ IGuiListEntry hoveredEntry = this.listEntries.get(hoveredSlotIndex);
+ if (hoveredEntry instanceof BaseConfigEntry) {
+ // draw tooltip
+ ((BaseConfigEntry) hoveredEntry).checkHover(mouseX, mouseY);
+
+ MooConfigPreview.drawPreviewHover(mouseX, mouseY);
+ }
+ }
+ }
+ }
+
+ public void keyTyped(char typedChar, int keyCode) {
+ if (currentKeyBindingConfigEntry != null) {
+ // change key binding
+ if (keyCode == Keyboard.KEY_ESCAPE) {
+ currentKeyBindingConfigEntry.setKeyBinding(-1);
+ } else if (keyCode != 0) {
+ currentKeyBindingConfigEntry.setKeyBinding(keyCode);
+ }
+ } else if (this.hoveredSlotIndex >= 0) {
+ // move GuiSlider by +/- 1 with left/right arrow key:
+ int direction;
+ if (keyCode == Keyboard.KEY_LEFT) {
+ direction = -1;
+ } else if (keyCode == Keyboard.KEY_RIGHT) {
+ direction = 1;
+ } else {
+ // abort!
+ return;
+ }
+ IGuiListEntry listEntry = this.getListEntry(this.hoveredSlotIndex);
+ if (listEntry instanceof NumberSliderConfigEntry) {
+ NumberSliderConfigEntry configEntry = (NumberSliderConfigEntry) listEntry;
+ if (configEntry.btnChangeConfigEntry.enabled && configEntry.btnChangeConfigEntry instanceof GuiSlider) {
+ GuiSlider slider = (GuiSlider) configEntry.btnChangeConfigEntry;
+ slider.setValue(slider.getValue() + direction);
+ configEntry.updateConfigEntryButtonText();
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean mouseClicked(int mouseX, int mouseY, int mouseEvent) {
+ if (currentKeyBindingConfigEntry != null) {
+ currentKeyBindingConfigEntry.undoChanges();
+ }
+ return super.mouseClicked(mouseX, mouseY, mouseEvent);
+ }
+
+ public boolean isModifyingKeyBind() {
+ return currentKeyBindingConfigEntry != null;
+ }
+
+ @SideOnly(Side.CLIENT)
+ public class CategoryEntry implements GuiListExtended.IGuiListEntry {
+ private final String labelText;
+ private final int labelWidth;
+ private final boolean hasExplanations;
+
+ public CategoryEntry(String labelText, boolean hasExplanations) {
+ this.labelText = "" + EnumChatFormatting.GOLD + EnumChatFormatting.BOLD + I18n.format(labelText);
+ this.labelWidth = MooConfigCategoryScrolling.this.mc.fontRendererObj.getStringWidth(this.labelText);
+ this.hasExplanations = hasExplanations;
+ }
+
+ public void drawEntry(int slotIndex, int x, int y, int listWidth, int slotHeight, int mouseX, int mouseY, boolean isSelected) {
+ GuiHelper.drawThinHorizontalLine(x, MooConfigCategoryScrolling.this.right, y + (slotHeight - MooConfigCategoryScrolling.this.mc.fontRendererObj.FONT_HEIGHT) / 2, 0x99ffffff);
+
+ int yTextPos = y + slotHeight - MooConfigCategoryScrolling.this.mc.fontRendererObj.FONT_HEIGHT + 3;
+ if (hasExplanations && MooConfig.getConfigGuiExplanationsDisplay() != MooConfig.Setting.DISABLED) {
+ // draw "!" to indicate a sub-category has additional info
+ MooConfigCategoryScrolling.this.mc.fontRendererObj.drawString(EnumChatFormatting.DARK_GREEN + "❢", x + 2, yTextPos, 0xffffff);
+ }
+ // draw sub category label
+ int labelX = (int) (x + MooConfigCategoryScrolling.this.maxListLabelWidth * 0.75 - this.labelWidth / 2);
+ MooConfigCategoryScrolling.this.mc.fontRendererObj.drawString(this.labelText, labelX, yTextPos, 0xffffff);
+ }
+
+ /**
+ * Returns true if the mouse has been pressed on this control.
+ */
+ public boolean mousePressed(int slotIndex, int p_148278_2_, int p_148278_3_, int p_148278_4_, int p_148278_5_, int p_148278_6_) {
+ return false;
+ }
+
+ /**
+ * Fired when the mouse button is released. Arguments: index, x, y, mouseEvent, relativeX, relativeY
+ */
+ public void mouseReleased(int slotIndex, int x, int y, int mouseEvent, int relativeX, int relativeY) {
+ }
+
+ public void setSelected(int p_178011_1_, int p_178011_2_, int p_178011_3_) {
+ }
+ }
+
+ @SideOnly(Side.CLIENT)
+ public class ExplanationsEntry implements IGuiListEntry {
+ private final String msgLine;
+ private final String msgLine2;
+
+ public ExplanationsEntry(String msgLine) {
+ EnumChatFormatting prefix = EnumChatFormatting.YELLOW;
+ msgLine = StringUtils.replaceEach(msgLine,
+ new String[]{EnumChatFormatting.YELLOW.toString(), EnumChatFormatting.RESET.toString()},
+ new String[]{EnumChatFormatting.WHITE.toString(), EnumChatFormatting.YELLOW.toString()});
+ if (msgLine.contains("\n")) {
+ String[] msgLines = msgLine.split("\n", 2);
+ this.msgLine = prefix + msgLines[0];
+ this.msgLine2 = prefix + msgLines[1];
+ } else {
+ this.msgLine = prefix + msgLine;
+ this.msgLine2 = null;
+ }
+ }
+
+ @Override
+ public void drawEntry(int slotIndex, int x, int y, int listWidth, int slotHeight, int mouseX, int mouseY, boolean isSelected) {
+ FontRenderer fontRendererObj = MooConfigCategoryScrolling.this.mc.fontRendererObj;
+ fontRendererObj.drawString(msgLine, x, y, 16777215);
+ if (msgLine2 != null) {
+ fontRendererObj.drawString(msgLine2, x, y + 1 + fontRendererObj.FONT_HEIGHT, 16777215);
+ }
+ }
+
+ @Override
+ public void setSelected(int p_178011_1_, int p_178011_2_, int p_178011_3_) {
+ }
+
+
+ @Override
+ public boolean mousePressed(int slotIndex, int p_148278_2_, int p_148278_3_, int p_148278_4_, int p_148278_5_, int p_148278_6_) {
+ return false;
+ }
+
+ @Override
+ public void mouseReleased(int slotIndex, int x, int y, int mouseEvent, int relativeX, int relativeY) {
+ }
+ }
+
+ /**
+ * Based on {@link net.minecraftforge.fml.client.config.GuiConfigEntries.ListEntryBase} and its subclasses
+ */
+ @SideOnly(Side.CLIENT)
+ public abstract class BaseConfigEntry implements GuiListExtended.IGuiListEntry {
+ /**
+ * The property specified for this ConfigEntry
+ */
+ protected final Property property;
+ protected final GuiButtonExt btnUndoChanges;
+ protected final GuiButtonExt btnDefault;
+ protected HoverChecker undoHoverChecker;
+ protected HoverChecker defaultHoverChecker;
+ protected final String name;
+ /**
+ * The localized key description for this ConfigEntry
+ */
+ private final List<String> tooltip;
+
+ private BaseConfigEntry(Property property) {
+ this.property = property;
+ this.name = I18n.format(property.getLanguageKey());
+ this.tooltip = Arrays.asList(I18n.format(property.getLanguageKey() + ".tooltip").split("\\\\n"));
+
+ this.btnUndoChanges = new GuiButtonExt(0, 0, 0, 18, 18, UNDO_CHAR);
+ this.btnDefault = new GuiButtonExt(0, 0, 0, 18, 18, RESET_CHAR);
+
+ this.undoHoverChecker = new HoverChecker(this.btnUndoChanges, 250);
+ this.defaultHoverChecker = new HoverChecker(this.btnDefault, 500);
+ }
+
+ public void drawEntry(int slotIndex, int x, int y, int listWidth, int slotHeight, int mouseX, int mouseY, boolean isSelected) {
+ MooConfigCategoryScrolling.this.mc.fontRendererObj.drawString(this.name, x, y + slotHeight / 2 - MooConfigCategoryScrolling.this.mc.fontRendererObj.FONT_HEIGHT / 2 + 2, 16777215);
+
+ this.btnUndoChanges.xPosition = x + MooConfigCategoryScrolling.this.maxListLabelWidth + 88;
+ this.btnUndoChanges.yPosition = y + 1;
+ this.btnUndoChanges.enabled = this.isChanged();
+ this.btnUndoChanges.drawButton(MooConfigCategoryScrolling.this.mc, mouseX, mouseY);
+
+ this.btnDefault.xPosition = x + MooConfigCategoryScrolling.this.maxListLabelWidth + 88 + 20;
+ this.btnDefault.yPosition = y + 1;
+ this.btnDefault.enabled = !isDefault();
+ this.btnDefault.drawButton(MooConfigCategoryScrolling.this.mc, mouseX, mouseY);
+
+ if (mouseX >= x && mouseX < x + maxListLabelWidth && mouseY >= y && mouseY < y + slotHeight) {
+ // mouse is over entry
+ GuiHelper.drawHoveringText(Lists.newArrayList(tooltip), mouseX, mouseY, width, height, 300);
+ GlStateManager.disableLighting();
+ }
+ }
+
+ public void checkHover(int mouseX, int mouseY) {
+ if (undoHoverChecker != null && undoHoverChecker.checkHover(mouseX, mouseY)) {
+ GuiHelper.drawHoveringText(Collections.singletonList(I18n.format("fml.configgui.tooltip.undoChanges")), mouseX, mouseY, parent.width, parent.height, 300);
+ } else if (defaultHoverChecker != null && defaultHoverChecker.checkHover(mouseX, mouseY)) {
+ GuiHelper.drawHoveringText(Collections.singletonList(I18n.format("fml.configgui.tooltip.resetToDefault")), mouseX, mouseY, parent.width, parent.height, 300);
+ }
+ }
+
+ /**
+ * Returns true if the mouse has been pressed on this control.
+ */
+ public boolean mousePressed(int slotIndex, int mouseX, int mouseY, int mouseEvent, int relativeX, int relativeY) {
+ if (currentKeyBindingConfigEntry != null && currentKeyBindingConfigEntry != this) {
+ // clicked on another undo/reset button while editing a key binding => abort changing key bind
+ currentKeyBindingConfigEntry.undoChanges();
+ }
+ if (this.btnDefault.mousePressed(mc, mouseX, mouseY)) {
+ btnDefault.playPressSound(mc.getSoundHandler());
+ setToDefault();
+ return true;
+ } else if (this.btnUndoChanges.mousePressed(mc, mouseX, mouseY)) {
+ btnUndoChanges.playPressSound(mc.getSoundHandler());
+ undoChanges();
+ return true;
+ }
+ return false;
+ }
+
+
+ /**
+ * Fired when the mouse button is released. Arguments: index, x, y, mouseEvent, relativeX, relativeY
+ */
+ public void mouseReleased(int slotIndex, int x, int y, int mouseEvent, int relativeX, int relativeY) {
+ this.btnUndoChanges.mouseReleased(x, y);
+ this.btnDefault.mouseReleased(x, y);
+
+ Cowlection.getInstance().getConfig().syncFromGuiWithoutSaving();
+ }
+
+ public void setSelected(int p_178011_1_, int p_178011_2_, int p_178011_3_) {
+ }
+
+ public boolean isDefault() {
+ return property.isDefault();
+ }
+
+ public abstract boolean isChanged();
+
+ public void setToDefault() {
+ property.setToDefault();
+ }
+
+ public abstract void undoChanges();
+ }
+
+ public abstract class ButtonConfigEntry extends BaseConfigEntry {
+ protected GuiButton btnChangeConfigEntry;
+
+ private ButtonConfigEntry(Property property) {
+ super(property);
+ this.btnChangeConfigEntry = new GuiButton(0, 0, 0, 78, 20, "Loading...");
+
+ if (property.getLanguageKey().equals(Cowlection.MODID + ".config.isMooValid")) {
+ btnChangeConfigEntry.enabled = false;
+ btnUndoChanges.enabled = false;
+ btnUndoChanges.visible = false;
+ btnDefault.enabled = false;
+ btnDefault.visible = false;
+ defaultHoverChecker = null;
+ undoHoverChecker = null;
+ }
+ }
+
+ @Override
+ public void drawEntry(int slotIndex, int x, int y, int listWidth, int slotHeight, int mouseX, int mouseY, boolean isSelected) {
+ this.btnChangeConfigEntry.xPosition = x + MooConfigCategoryScrolling.this.maxListLabelWidth + 5;
+ this.btnChangeConfigEntry.yPosition = y;
+ this.btnChangeConfigEntry.drawButton(MooConfigCategoryScrolling.this.mc, mouseX, mouseY);
+ super.drawEntry(slotIndex, x, y, listWidth, slotHeight, mouseX, mouseY, isSelected);
+ }
+
+ @Override
+ public boolean mousePressed(int slotIndex, int mouseX, int mouseY, int mouseEvent, int relativeX, int relativeY) {
+ if (this.btnChangeConfigEntry.mousePressed(mc, mouseX, mouseY)) {
+ btnChangeConfigEntry.playPressSound(mc.getSoundHandler());
+ changeConfigEntryButtonPressed();
+ return true;
+ } else {
+ return super.mousePressed(slotIndex, mouseX, mouseY, mouseEvent, relativeX, relativeY);
+ }
+ }
+
+ @Override
+ public void mouseReleased(int slotIndex, int x, int y, int mouseEvent, int relativeX, int relativeY) {
+ super.mouseReleased(slotIndex, x, y, mouseEvent, relativeX, relativeY);
+ this.btnChangeConfigEntry.mouseReleased(x, y);
+ }
+
+ protected abstract void changeConfigEntryButtonPressed();
+
+ @SuppressWarnings("unused")
+ protected abstract void updateConfigEntryButtonText();
+ }
+
+ private class BooleanConfigEntry extends ButtonConfigEntry {
+ protected final boolean beforeValue;
+
+ public BooleanConfigEntry(Property property) {
+ super(property);
+ beforeValue = property.getBoolean();
+
+ updateConfigEntryButtonText();
+ }
+
+ @Override
+ protected void changeConfigEntryButtonPressed() {
+ property.set(!property.getBoolean());
+ updateConfigEntryButtonText();
+ }
+
+ @Override
+ public boolean isChanged() {
+ return property.getBoolean() != beforeValue;
+ }
+
+ @Override
+ public void setToDefault() {
+ super.setToDefault();
+ updateConfigEntryButtonText();
+ }
+
+ @Override
+ public void undoChanges() {
+ property.set(beforeValue);
+ updateConfigEntryButtonText();
+ }
+
+ @Override
+ protected void updateConfigEntryButtonText() {
+ btnChangeConfigEntry.displayString = Utils.booleanToSymbol(property.getBoolean());
+ }
+ }
+
+ private class GuiSwitchEntry extends ButtonConfigEntry {
+ private final Runnable runnable;
+
+ private GuiSwitchEntry(String langKey, String buttonText, Runnable runnable) {
+ super(new Property("fakeProperty", "fakeValue", Property.Type.STRING, Cowlection.MODID + ".config." + langKey));
+ btnChangeConfigEntry.displayString = buttonText;
+ this.runnable = runnable;
+
+ this.btnDefault.visible = false;
+ this.btnUndoChanges.visible = false;
+ }
+
+ @Override
+ public boolean isChanged() {
+ return false;
+ }
+
+ @Override
+ public void undoChanges() {
+ }
+
+ @Override
+ protected void changeConfigEntryButtonPressed() {
+ runnable.run();
+ }
+
+ @Override
+ protected void updateConfigEntryButtonText() {
+ }
+ }
+
+ private class CycleConfigEntry extends ButtonConfigEntry {
+ protected final int beforeIndex;
+ protected final int defaultIndex;
+ protected int currentIndex;
+ /**
+ * Work-around to avoid infinite loop: updateConfigEntryButtonText <> switchDisplayedConfigCategory
+ */
+ private boolean hasBeenModified = false;
+
+ private CycleConfigEntry(Property property) {
+ super(property);
+ beforeIndex = getIndex(property.getString());
+ defaultIndex = getIndex(property.getDefault());
+ currentIndex = beforeIndex;
+ updateConfigEntryButtonText();
+ }
+
+ private int getIndex(String s) {
+ for (int i = 0; i < property.getValidValues().length; i++) {
+ if (property.getValidValues()[i].equals(s)) {
+ return i;
+ }
+ }
+ return 0;
+ }
+
+ @Override
+ public boolean isDefault() {
+ return currentIndex == defaultIndex;
+ }
+
+ @Override
+ public boolean isChanged() {
+ return currentIndex != beforeIndex;
+ }
+
+ @Override
+ public void setToDefault() {
+ currentIndex = defaultIndex;
+ updateConfigEntryButtonText();
+ }
+
+ @Override
+ public void undoChanges() {
+ currentIndex = beforeIndex;
+ updateConfigEntryButtonText();
+ }
+
+ @Override
+ protected void changeConfigEntryButtonPressed() {
+ if (++this.currentIndex >= property.getValidValues().length) {
+ this.currentIndex = 0;
+ }
+
+ updateConfigEntryButtonText();
+ }
+
+ @Override
+ protected void updateConfigEntryButtonText() {
+ String newValue = property.getValidValues()[currentIndex];
+ property.setValue(newValue);
+ this.btnChangeConfigEntry.displayString = newValue;
+
+ if (hasBeenModified && (Cowlection.MODID + ".config.configGuiExplanations").equals(property.getLanguageKey())) {
+ // save properties and re-draw category
+ Cowlection.getInstance().getConfig().syncFromGuiWithoutSaving();
+ parent.switchDisplayedConfigCategory();
+ }
+ hasBeenModified = true;
+ }
+ }
+
+ private class NumberSliderConfigEntry extends ButtonConfigEntry {
+ protected final int beforeValue;
+
+ private NumberSliderConfigEntry(Property property, MooConfigCategory.SubCategory.GuiSliderExtra guiSliderExtra) {
+ super(property);
+
+ beforeValue = property.getInt();
+
+ int minVal = Integer.parseInt(property.getMinValue());
+ int maxVal = Integer.parseInt(property.getMaxValue());
+
+ String prefix = "";
+ String suffix = "";
+ GuiSlider.ISlider onChangeSliderValue = null;
+ if (guiSliderExtra != null) {
+ onChangeSliderValue = guiSliderExtra.getOnChangeSliderValue();
+ prefix = guiSliderExtra.getPrefix();
+ suffix = guiSliderExtra.getSuffix();
+ }
+
+ this.btnChangeConfigEntry = new GuiSlider(0, 0, 0, 78, 20, prefix, suffix, minVal, maxVal, beforeValue, false, true, onChangeSliderValue);
+ updateConfigEntryButtonText();
+ MooConfigGui.showDungeonPerformanceOverlayUntil = 0;
+ }
+
+ @Override
+ public boolean isDefault() {
+ return ((GuiSlider) this.btnChangeConfigEntry).getValueInt() == Integer.parseInt(property.getDefault());
+ }
+
+ @Override
+ public boolean isChanged() {
+ return ((GuiSlider) this.btnChangeConfigEntry).getValueInt() != beforeValue;
+ }
+
+ @Override
+ public void setToDefault() {
+ ((GuiSlider) this.btnChangeConfigEntry).setValue(Double.parseDouble(property.getDefault()));
+ updateConfigEntryButtonText();
+ }
+
+ @Override
+ public void undoChanges() {
+ ((GuiSlider) this.btnChangeConfigEntry).setValue(beforeValue);
+ updateConfigEntryButtonText();
+ }
+
+ @Override
+ protected void changeConfigEntryButtonPressed() {
+ }
+
+ @Override
+ public void mouseReleased(int slotIndex, int x, int y, int mouseEvent, int relativeX, int relativeY) {
+ if (((GuiSlider) btnChangeConfigEntry).dragging) {
+ updateConfigEntryButtonText();
+ }
+ super.mouseReleased(slotIndex, x, y, mouseEvent, relativeX, relativeY);
+ }
+
+ @Override
+ protected void updateConfigEntryButtonText() {
+ property.setValue(((GuiSlider) this.btnChangeConfigEntry).getValueInt());
+
+ ((GuiSlider) this.btnChangeConfigEntry).updateSlider();
+ }
+ }
+
+ private class KeyBindingConfigEntry extends ButtonConfigEntry {
+ private final int beforeValue;
+
+ public KeyBindingConfigEntry(Property configEntry) {
+ super(configEntry);
+ beforeValue = property.getInt();
+
+ updateConfigEntryButtonText();
+ }
+
+ @Override
+ protected void changeConfigEntryButtonPressed() {
+ currentKeyBindingConfigEntry = this;
+ updateConfigEntryButtonText();
+ }
+
+ @Override
+ protected void updateConfigEntryButtonText() {
+ int keyCode = property.getInt();
+ String keyName = keyCode > 1 && keyCode < 256 ? Keyboard.getKeyName(keyCode) : EnumChatFormatting.ITALIC + "none";
+ if (currentKeyBindingConfigEntry == this) {
+ // key is is currently being modified
+ keyName = EnumChatFormatting.WHITE + "> " + EnumChatFormatting.YELLOW + (keyName != null ? keyName : "Key #" + keyCode) + EnumChatFormatting.WHITE + " <";
+ }
+ btnChangeConfigEntry.displayString = keyName;
+ }
+
+ @Override
+ public boolean isChanged() {
+ return property.getInt() != beforeValue;
+ }
+
+ @Override
+ public void undoChanges() {
+ property.set(beforeValue);
+ currentKeyBindingConfigEntry = null;
+ Cowlection.getInstance().getConfig().syncFromGuiWithoutSaving();
+ updateConfigEntryButtonText();
+ }
+
+ @Override
+ public void setToDefault() {
+ super.setToDefault();
+ currentKeyBindingConfigEntry = null;
+ Cowlection.getInstance().getConfig().syncFromGuiWithoutSaving();
+ updateConfigEntryButtonText();
+ }
+
+ public void setKeyBinding(int keyCode) {
+ property.set(Math.min(keyCode, 255));
+ currentKeyBindingConfigEntry = null;
+ Cowlection.getInstance().getConfig().syncFromGuiWithoutSaving();
+ updateConfigEntryButtonText();
+ }
+ }
+}
diff --git a/src/main/java/de/cowtipper/cowlection/config/gui/MooConfigGui.java b/src/main/java/de/cowtipper/cowlection/config/gui/MooConfigGui.java
new file mode 100644
index 0000000..e9af52c
--- /dev/null
+++ b/src/main/java/de/cowtipper/cowlection/config/gui/MooConfigGui.java
@@ -0,0 +1,206 @@
+package de.cowtipper.cowlection.config.gui;
+
+import de.cowtipper.cowlection.Cowlection;
+import de.cowtipper.cowlection.config.MooConfig;
+import de.cowtipper.cowlection.config.MooConfigCategory;
+import de.cowtipper.cowlection.listener.PlayerListener;
+import de.cowtipper.cowlection.util.GuiHelper;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.IChatComponent;
+import org.lwjgl.input.Keyboard;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+/**
+ * Main config gui containing:
+ * <ul>
+ * <li>menu ({@link MooConfigMenuList}) with list of config categories ({@link MooConfigCategory})</li>
+ * <li>the current opened config category with its sub-categories ({@link MooConfigCategoryScrolling})</li>
+ * </ul>
+ * Based on {@link net.minecraft.client.gui.GuiControls}
+ */
+public class MooConfigGui extends GuiScreen {
+ public static long showDungeonPerformanceOverlayUntil;
+ public int menuWidth;
+ private MooConfigMenuList menu;
+ private int selectedMenuIndex = -1;
+ private MooConfigCategory currentConfigCategory;
+ private final boolean isOutsideOfSkyBlock;
+ /**
+ * equivalent of GuiModList.keyBindingList
+ */
+ private MooConfigCategoryScrolling currentConfigCategoryGui;
+ private GuiButton btnClose;
+
+ public MooConfigGui() {
+ isOutsideOfSkyBlock = PlayerListener.registerSkyBlockListeners();
+ }
+
+ /**
+ * Adds the buttons (and other controls) to the screen in question. Called when the GUI is displayed and when the
+ * window resizes, the buttonList is cleared beforehand.
+ */
+ @Override
+ public void initGui() {
+ Keyboard.enableRepeatEvents(true);
+ MooConfigPreview.parent = this;
+
+ // re-register SkyBlock listeners if necessary (mainly so that previews function correctly outside of SkyBlock)
+ PlayerListener.registerSkyBlockListeners();
+
+ for (MooConfigCategory configCategory : MooConfig.getConfigCategories()) {
+ menuWidth = Math.max(menuWidth, fontRendererObj.getStringWidth(configCategory.getMenuDisplayName()) + 10 + 2);
+ }
+ menuWidth = Math.min(menuWidth, 150);
+ this.menu = new MooConfigMenuList(this, menuWidth);
+
+ this.buttonList.add(this.btnClose = new GuiButton(6, this.width - 25, 3, 22, 20, EnumChatFormatting.RED + "X"));
+
+ if (selectedMenuIndex < 0) {
+ // switch to 1st category if none is selected
+ selectConfigCategory(0);
+ }
+ }
+
+ @Override
+ public void handleMouseInput() throws IOException {
+ super.handleMouseInput();
+ if (currentConfigCategoryGui != null) {
+ this.currentConfigCategoryGui.handleMouseInput();
+ }
+ }
+
+ /**
+ * Called by the controls from the buttonList when activated. (Mouse pressed for buttons)
+ */
+ @Override
+ protected void actionPerformed(GuiButton button) throws IOException {
+ if (button.enabled) {
+ if (button.id == 6) { // close gui
+ this.mc.displayGuiScreen(null);
+ }
+ }
+ }
+
+ /**
+ * Called when the mouse is clicked. Args : mouseX, mouseY, clickedButton
+ */
+ @Override
+ protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException {
+ if (mouseButton != 0 || (currentConfigCategoryGui != null && !this.currentConfigCategoryGui.mouseClicked(mouseX, mouseY, mouseButton))) {
+ super.mouseClicked(mouseX, mouseY, mouseButton);
+ }
+ }
+
+ /**
+ * Called when a mouse button is released. Args : mouseX, mouseY, releaseButton
+ */
+ protected void mouseReleased(int mouseX, int mouseY, int state) {
+ if (state != 0 || currentConfigCategoryGui != null && !this.currentConfigCategoryGui.mouseReleased(mouseX, mouseY, state)) {
+ super.mouseReleased(mouseX, mouseY, state);
+ }
+ }
+
+ /**
+ * Fired when a key is typed (except F11 which toggles full screen). This is the equivalent of
+ * KeyListener.keyTyped(KeyEvent e). Args : character (character on the key), keyCode (lwjgl Keyboard key code)
+ */
+ @Override
+ protected void keyTyped(char typedChar, int keyCode) throws IOException {
+ if (keyCode == Keyboard.KEY_ESCAPE && (currentConfigCategoryGui == null || !currentConfigCategoryGui.isModifyingKeyBind())) {
+ super.keyTyped(typedChar, keyCode);
+ } else if (this.currentConfigCategoryGui != null) {
+ this.currentConfigCategoryGui.keyTyped(typedChar, keyCode);
+ }
+ }
+
+ /**
+ * Draws the screen and all the components in it. Args : mouseX, mouseY, renderPartialTicks
+ */
+ @Override
+ public void drawScreen(int mouseX, int mouseY, float partialTicks) {
+ if (!showDungeonPerformanceOverlay()) {
+ this.menu.drawScreen(mouseX, mouseY, partialTicks);
+ }
+
+ String guiTitle = "" + EnumChatFormatting.BOLD + EnumChatFormatting.UNDERLINE + Cowlection.MODNAME + " config" + (currentConfigCategory != null ? ":" + EnumChatFormatting.RESET + " " + currentConfigCategory.getDisplayName() : "");
+ int guiTitleX = ((menu.getRight() + this.width) / 2) - this.fontRendererObj.getStringWidth(guiTitle) / 2;
+ this.drawCenteredString(this.fontRendererObj, guiTitle, guiTitleX, 16, 0xFFFFFF);
+ super.drawScreen(mouseX, mouseY, partialTicks);
+
+ if (currentConfigCategoryGui != null) {
+ currentConfigCategoryGui.drawScreen(mouseX, mouseY, partialTicks);
+ }
+ if (btnClose.isMouseOver()) {
+ GuiHelper.drawHoveringText(Arrays.asList(EnumChatFormatting.RED + "Save & close settings", "" + EnumChatFormatting.GRAY + EnumChatFormatting.ITALIC + "Hint:" + EnumChatFormatting.RESET + " alternatively press ESC"), mouseX, mouseY, width, height, 300);
+ }
+ }
+
+ @Override
+ public void drawDefaultBackground() {
+ if (!MooConfigGui.showDungeonPerformanceOverlay()) {
+ super.drawDefaultBackground();
+ }
+ }
+
+ // config category menu methods:
+
+ /**
+ * Select a config category via the menu
+ */
+ public void selectConfigCategory(int index) {
+ if (index == this.selectedMenuIndex) {
+ return;
+ }
+ this.selectedMenuIndex = index;
+ this.currentConfigCategory = (index >= 0 && index <= MooConfig.getConfigCategories().size()) ? MooConfig.getConfigCategories().get(selectedMenuIndex) : null;
+
+ switchDisplayedConfigCategory();
+ Cowlection.getInstance().getConfig().syncFromGui();
+ }
+
+ /**
+ * Helper method for menu: is config category selected?
+ */
+ public boolean isConfigCategorySelected(int index) {
+ return index == selectedMenuIndex;
+ }
+
+ public void switchDisplayedConfigCategory() {
+ if (currentConfigCategory == null) {
+ return;
+ }
+ currentConfigCategoryGui = new MooConfigCategoryScrolling(this, mc, currentConfigCategory, menu.getRight() + 3);
+ }
+
+ @Override
+ public void renderToolTip(ItemStack stack, int x, int y) {
+ super.renderToolTip(stack, x, y);
+ }
+
+ @Override
+ public void handleComponentHover(IChatComponent component, int x, int y) {
+ super.handleComponentHover(component, x, y);
+ }
+
+ @Override
+ public void onGuiClosed() {
+ Keyboard.enableRepeatEvents(false);
+ Cowlection.getInstance().getConfig().syncFromGui();
+
+ if (isOutsideOfSkyBlock) {
+ PlayerListener.unregisterSkyBlockListeners();
+ }
+ if (MooConfigPreview.parent != null) {
+ MooConfigPreview.parent = null;
+ }
+ }
+
+ public static boolean showDungeonPerformanceOverlay() {
+ return showDungeonPerformanceOverlayUntil > System.currentTimeMillis();
+ }
+}
diff --git a/src/main/java/de/cowtipper/cowlection/config/gui/MooConfigMenuList.java b/src/main/java/de/cowtipper/cowlection/config/gui/MooConfigMenuList.java
new file mode 100644
index 0000000..310e09e
--- /dev/null
+++ b/src/main/java/de/cowtipper/cowlection/config/gui/MooConfigMenuList.java
@@ -0,0 +1,70 @@
+package de.cowtipper.cowlection.config.gui;
+
+import de.cowtipper.cowlection.config.MooConfig;
+import de.cowtipper.cowlection.config.MooConfigCategory;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.FontRenderer;
+import net.minecraft.client.renderer.Tessellator;
+import net.minecraft.util.StringUtils;
+import net.minecraftforge.fml.client.GuiScrollingList;
+
+/**
+ * Config menu displaying a list of config categories
+ * <p>
+ * Based on {@link net.minecraftforge.fml.client.GuiSlotModList}
+ */
+public class MooConfigMenuList extends GuiScrollingList {
+ private final MooConfigGui parent;
+
+ public MooConfigMenuList(MooConfigGui parent, int listWidth) {
+ super(Minecraft.getMinecraft(), listWidth, parent.height, 32, parent.height - 5, 5, 15, parent.width, parent.height);
+ this.parent = parent;
+ }
+
+ @Override
+ protected int getSize() {
+ return MooConfig.getConfigCategories().size();
+ }
+
+ @Override
+ protected void elementClicked(int index, boolean doubleClick) {
+ this.parent.selectConfigCategory(index);
+ }
+
+ @Override
+ protected boolean isSelected(int index) {
+ return this.parent.isConfigCategorySelected(index);
+ }
+
+ @Override
+ protected void drawBackground() {
+ this.parent.drawDefaultBackground();
+ }
+
+ @Override
+ protected int getContentHeight() {
+ return (this.getSize()) * 15 + 1;
+ }
+
+ @Override
+ protected void drawScreen(int mouseX, int mouseY) {
+ super.drawScreen(mouseX, mouseY);
+ }
+
+ @Override
+ protected void drawSlot(int idx, int right, int top, int height, Tessellator tess) {
+ MooConfigCategory configCategory = MooConfig.getConfigCategories().get(idx);
+ String name = StringUtils.stripControlCodes(configCategory.getMenuDisplayName());
+ FontRenderer font = Minecraft.getMinecraft().fontRendererObj;
+
+ font.drawString(font.trimStringToWidth(name, listWidth - 10), this.left + 3, top + 2, 0xFFFFFF);
+ }
+
+ protected int getRight() {
+ return this.right;
+ }
+
+ public int getLeft() {
+ return this.left;
+ }
+}
diff --git a/src/main/java/de/cowtipper/cowlection/config/gui/MooConfigPreview.java b/src/main/java/de/cowtipper/cowlection/config/gui/MooConfigPreview.java
new file mode 100644
index 0000000..3499fdd
--- /dev/null
+++ b/src/main/java/de/cowtipper/cowlection/config/gui/MooConfigPreview.java
@@ -0,0 +1,175 @@
+package de.cowtipper.cowlection.config.gui;
+
+import de.cowtipper.cowlection.util.MooChatComponent;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.FontRenderer;
+import net.minecraft.client.gui.Gui;
+import net.minecraft.client.gui.GuiUtilRenderComponents;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.client.renderer.RenderHelper;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.*;
+import net.minecraft.util.ChatComponentText;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.IChatComponent;
+import net.minecraft.util.ResourceLocation;
+import net.minecraftforge.fml.client.config.GuiUtils;
+import org.apache.commons.lang3.text.WordUtils;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class MooConfigPreview {
+ private final Type type;
+ private ItemStack[] items;
+ private IChatComponent chatComponent;
+ public static ItemStack hoveredItem;
+ public static IChatComponent hoveredChatComponent;
+ public static MooConfigGui parent;
+
+ public MooConfigPreview(IChatComponent chatComponent) {
+ this.type = Type.CHAT;
+ this.chatComponent = chatComponent;
+ }
+
+ public MooConfigPreview(ItemStack... items) {
+ this.type = Type.ITEM;
+ this.items = items;
+ }
+
+ public void drawPreview(int x, int y, int mouseX, int mouseY, boolean enablePreview) {
+ switch (type) {
+ case ITEM:
+ drawItemsPreview(x, y, mouseX, mouseY, enablePreview);
+ break;
+ case CHAT:
+ drawChatPreview(x, y, mouseX, mouseY, enablePreview);
+ }
+ }
+
+ public static void drawPreviewHover(int mouseX, int mouseY) {
+ if (hoveredItem != null) {
+ // draw preview item tool tip
+ parent.renderToolTip(hoveredItem, mouseX, mouseY);
+ hoveredItem = null;
+ } else if (hoveredChatComponent != null) {
+ // draw hover event of hovered chat component
+ parent.handleComponentHover(hoveredChatComponent, mouseX, mouseY);
+ hoveredChatComponent = null;
+ }
+ }
+
+ private void drawItemsPreview(int x, int yFakeHotbar, int mouseX, int mouseY, boolean enablePreview) {
+ int xFakeHotbar = x + 15;
+ GlStateManager.pushMatrix();
+ GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
+ Minecraft.getMinecraft().getTextureManager().bindTexture(new ResourceLocation("textures/gui/container/inventory.png"));
+
+ GuiUtils.drawTexturedModalRect(xFakeHotbar, yFakeHotbar, 87, 25, 18 * items.length, 18, 0);
+
+ GlStateManager.enableRescaleNormal();
+ GlStateManager.enableBlend();
+ GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0);
+ RenderHelper.enableGUIStandardItemLighting();
+
+ int xItem = xFakeHotbar + 1;
+ int yItem = yFakeHotbar + 1;
+ for (ItemStack item : items) {
+ Minecraft.getMinecraft().getRenderItem().renderItemAndEffectIntoGUI(item, xItem, yItem);
+
+ // check mouse hover to draw item tooltip
+ if (enablePreview && mouseX >= xItem - 1 && mouseX < xItem + 18 - 1 && mouseY >= yItem - 1 && mouseY < yItem + 18 - 1) {
+ hoveredItem = item;
+ GlStateManager.disableLighting();
+ GlStateManager.disableDepth();
+ GlStateManager.colorMask(true, true, true, false);
+ // draw white slot hover
+ Gui.drawRect(xItem, yItem, xItem + 16, yItem + 16, 0x80FFFFFF);
+ GlStateManager.colorMask(true, true, true, true);
+ GlStateManager.enableDepth();
+ GlStateManager.enableLighting();
+ }
+ xItem += 18;
+ }
+ RenderHelper.disableStandardItemLighting();
+ GlStateManager.disableRescaleNormal();
+ GlStateManager.disableBlend();
+ GlStateManager.popMatrix();
+ }
+
+ public static ItemStack createDemoItem(String itemId, String itemName, String[] lore, Map<String, NBTBase> extraAttributes) {
+ return createDemoItem(itemId, itemName, lore, extraAttributes, -1);
+ }
+
+ public static ItemStack createDemoItem(String itemId, String itemName, String[] lore, Map<String, NBTBase> extraAttributes, int color) {
+ ItemStack demoItem = new ItemStack(Item.getByNameOrId(itemId));
+
+ // lore
+ NBTTagCompound display = new NBTTagCompound();
+ demoItem.setTagInfo("display", display);
+ NBTTagList loreTag = new NBTTagList();
+ display.setTag("Lore", loreTag);
+ for (String loreEntry : lore) {
+ loreTag.appendTag(new NBTTagString(loreEntry));
+ }
+ // color
+ if (color >= 0) {
+ display.setInteger("color", color);
+ }
+ // SkyBlock extra attributes
+ NBTTagCompound extraAttributesTag = new NBTTagCompound();
+ demoItem.setTagInfo("ExtraAttributes", extraAttributesTag);
+ for (Map.Entry<String, NBTBase> extraAttribute : extraAttributes.entrySet()) {
+ extraAttributesTag.setTag(extraAttribute.getKey(), extraAttribute.getValue());
+ }
+ demoItem.setStackDisplayName(itemName);
+
+ return demoItem;
+ }
+
+ public static ItemStack createDungeonItem(String modifier, String timestamp, String... lore) {
+ Map<String, NBTBase> extraAttributes = new HashMap<>();
+ extraAttributes.put("modifier", new NBTTagString(modifier));
+ extraAttributes.put("baseStatBoostPercentage", new NBTTagInt(48));
+ extraAttributes.put("item_tier", new NBTTagInt(1));
+ extraAttributes.put("id", new NBTTagString("SKELETON_SOLDIER_LEGGINGS"));
+ extraAttributes.put("timestamp", new NBTTagString(timestamp));
+
+
+ return createDemoItem("leather_leggings", EnumChatFormatting.DARK_PURPLE + WordUtils.capitalize(modifier) + " Skeleton Soldier Leggings",
+ lore, extraAttributes, 16759819);
+ }
+
+ private void drawChatPreview(int x, int y, int mouseX, int mouseY, boolean enablePreview) {
+ FontRenderer fontRenderer = Minecraft.getMinecraft().fontRendererObj;
+ int currentX = x + 15;
+ int chatY = y + 20 / 2 - fontRenderer.FONT_HEIGHT / 2;
+
+ fontRenderer.drawStringWithShadow(this.chatComponent.getFormattedText(), currentX, chatY, 0xffffffff);
+ if (!enablePreview) {
+ Gui.drawRect(currentX - 2, chatY - 2, currentX + fontRenderer.getStringWidth(chatComponent.getUnformattedText()) + 1, chatY + fontRenderer.FONT_HEIGHT + 1, 0xdd444444);
+ }
+
+ // hover checker for online best friends (partially taken from GuiNewChat#getChatComponent)
+ if (enablePreview && mouseY >= chatY && mouseY <= chatY + fontRenderer.FONT_HEIGHT) {
+ for (IChatComponent chatComponent : chatComponent) {
+ if (chatComponent instanceof ChatComponentText) {
+ currentX += fontRenderer.getStringWidth(GuiUtilRenderComponents.func_178909_a(chatComponent.getUnformattedTextForChat(), false));
+ if (currentX > mouseX) {
+ hoveredChatComponent = chatComponent;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ public static IChatComponent createDemoOnline(String name, String gameMode, String onlineTime) {
+ return new MooChatComponent(name).darkGreen().setHover(new MooChatComponent(gameMode).yellow().appendFreshSibling(new MooChatComponent("Online for " + onlineTime).white()));
+ }
+
+ private enum Type {
+ CHAT, ITEM
+ }
+}
diff --git a/src/main/java/de/cowtipper/cowlection/data/DataHelper.java b/src/main/java/de/cowtipper/cowlection/data/DataHelper.java
index 9af613f..37dd4a3 100644
--- a/src/main/java/de/cowtipper/cowlection/data/DataHelper.java
+++ b/src/main/java/de/cowtipper/cowlection/data/DataHelper.java
@@ -91,6 +91,28 @@ public final class DataHelper {
}
}
+ public enum DungeonClass {
+ ARCHER('A'), BERSERK('B'), HEALER('H'), MAGE('M'), TANK('T'), UNKNOWN('U');
+ private final char shortName;
+
+ DungeonClass(char shortName) {
+ this.shortName = shortName;
+ }
+
+ public static DungeonClass get(String className) {
+ try {
+ return valueOf(className.toUpperCase());
+ } catch (IllegalArgumentException e) {
+ // invalid class name
+ return UNKNOWN;
+ }
+ }
+
+ public char getShortName() {
+ return shortName;
+ }
+ }
+
public static Map<String, String> getMinions() {
// key = skin id, value = minion type and tier
Map<String, String> minions = new HashMap<>();
diff --git a/src/main/java/de/cowtipper/cowlection/data/HyApiKey.java b/src/main/java/de/cowtipper/cowlection/data/HyApiKey.java
new file mode 100644
index 0000000..96b391a
--- /dev/null
+++ b/src/main/java/de/cowtipper/cowlection/data/HyApiKey.java
@@ -0,0 +1,20 @@
+package de.cowtipper.cowlection.data;
+
+public class HyApiKey {
+ private boolean success;
+ private String cause;
+
+ /**
+ * No-args constructor for GSON
+ */
+ private HyApiKey() {
+ }
+
+ public boolean isSuccess() {
+ return success;
+ }
+
+ public String getCause() {
+ return cause;
+ }
+}
diff --git a/src/main/java/de/cowtipper/cowlection/handler/FriendsHandler.java b/src/main/java/de/cowtipper/cowlection/handler/FriendsHandler.java
index bb4d916..c2c6837 100644
--- a/src/main/java/de/cowtipper/cowlection/handler/FriendsHandler.java
+++ b/src/main/java/de/cowtipper/cowlection/handler/FriendsHandler.java
@@ -118,7 +118,7 @@ public class FriendsHandler {
if (!bestFriend.equals(Friend.FRIEND_NOT_FOUND)) {
bestFriend.setLastChecked(System.currentTimeMillis());
if (isCommandTriggered) {
- throw new MooCommandException(friend.getName() + " hasn't changed his name");
+ throw new MooCommandException(friend.getName() + " hasn't changed their name");
}
}
} else {
@@ -202,8 +202,8 @@ public class FriendsHandler {
});
}
} else {
- new TickDelay(() -> main.getChatHelper().sendMessage(EnumChatFormatting.RED, "Couldn't check best friends online status because it has not been long enough since the last check. Next check via " + EnumChatFormatting.WHITE + "/moo online" + EnumChatFormatting.RED + " available in " + DurationFormatUtils.formatDurationWords(nextBestFriendOnlineCheck - System.currentTimeMillis(), true, true))
- , isCommandTriggered ? 1 : 100);
+ new TickDelay(() -> main.getChatHelper().sendMessage(EnumChatFormatting.RED, "Couldn't check best friends online status because it has not been long enough since the last check. Next check via " + EnumChatFormatting.WHITE + "/moo online" + EnumChatFormatting.RED + " available in " + DurationFormatUtils.formatDurationWords(nextBestFriendOnlineCheck - System.currentTimeMillis(), true, true)),
+ isCommandTriggered ? 1 : 100);
}
}
diff --git a/src/main/java/de/cowtipper/cowlection/listener/ChatListener.java b/src/main/java/de/cowtipper/cowlection/listener/ChatListener.java
index a936888..e2d2316 100644
--- a/src/main/java/de/cowtipper/cowlection/listener/ChatListener.java
+++ b/src/main/java/de/cowtipper/cowlection/listener/ChatListener.java
@@ -167,7 +167,7 @@ public class ChatListener {
messageSender = partyOrGameInviteMatcher.group(1);
} else if (dungeonPartyFinderJoinedMatcher.find()) {
messageSender = dungeonPartyFinderJoinedMatcher.group(1);
- if (!"disabled".equals(MooConfig.dungPartyFinderArmorLookup) && !messageSender.equals(Minecraft.getMinecraft().thePlayer.getName())) {
+ if (MooConfig.getDungPartyFinderArmorLookupDisplay() != MooConfig.Setting.DISABLED && !messageSender.equals(Minecraft.getMinecraft().thePlayer.getName())) {
String dungeonClass = dungeonPartyFinderJoinedMatcher.group(2) + " Lvl " + dungeonPartyFinderJoinedMatcher.group(3);
getDungeonPartyMemberDetails(messageSender, dungeonClass);
}
@@ -192,16 +192,17 @@ public class ChatListener {
HySkyBlockStats.Profile.Member member = activeProfile.getMember(stalkedPlayer.getUuid());
MooChatComponent armorLookupComponent;
String armorLookupPrefix = " ❈ " + EnumChatFormatting.DARK_GREEN + playerName;
- String delimiter = "\n" + (MooConfig.showArmorLookupInChat() ? " " : "");
+ MooConfig.Setting dungPartyFinderArmorLookupDisplay = MooConfig.getDungPartyFinderArmorLookupDisplay();
+ String delimiter = "\n" + (dungPartyFinderArmorLookupDisplay == MooConfig.Setting.TEXT ? " " : "");
String armorLookupResult = EnumChatFormatting.LIGHT_PURPLE + " ➜ " + EnumChatFormatting.GRAY + dungeonClass + delimiter + String.join(delimiter, member.getArmor());
- if (MooConfig.showArmorLookupInChat()) {
+ if (dungPartyFinderArmorLookupDisplay == MooConfig.Setting.TEXT) {
armorLookupComponent = new MooChatComponent(armorLookupPrefix + armorLookupResult).green();
} else {
- // as a tooltip
+ // as a tooltip: == MooConfig.Setting.TOOLTIP
armorLookupComponent = new MooChatComponent(armorLookupPrefix + EnumChatFormatting.GREEN + (playerName.endsWith("s") ? "" : "'s") + " armor (hover me)").green()
.setHover(new MooChatComponent(EnumChatFormatting.BOLD + playerName + armorLookupResult));
}
- main.getChatHelper().sendMessage(armorLookupComponent.setSuggestCommand("/p kick " + playerName, MooConfig.showArmorLookupInChat()));
+ main.getChatHelper().sendMessage(armorLookupComponent.setSuggestCommand("/p kick " + playerName, dungPartyFinderArmorLookupDisplay == MooConfig.Setting.TEXT));
}
});
}
diff --git a/src/main/java/de/cowtipper/cowlection/listener/PlayerListener.java b/src/main/java/de/cowtipper/cowlection/listener/PlayerListener.java
index a990ad4..0925d38 100644
--- a/src/main/java/de/cowtipper/cowlection/listener/PlayerListener.java
+++ b/src/main/java/de/cowtipper/cowlection/listener/PlayerListener.java
@@ -1,6 +1,7 @@
package de.cowtipper.cowlection.listener;
import de.cowtipper.cowlection.Cowlection;
+import de.cowtipper.cowlection.config.CredentialStorage;
import de.cowtipper.cowlection.config.MooConfig;
import de.cowtipper.cowlection.event.ApiErrorEvent;
import de.cowtipper.cowlection.listener.skyblock.DungeonsListener;
@@ -31,8 +32,8 @@ import org.lwjgl.input.Keyboard;
public class PlayerListener {
private final Cowlection main;
- private DungeonsListener dungeonsListener;
- private SkyBlockListener skyBlockListener;
+ private static DungeonsListener dungeonsListener;
+ private static SkyBlockListener skyBlockListener;
private boolean isOnSkyBlock;
public PlayerListener(Cowlection main) {
@@ -90,7 +91,7 @@ public class PlayerListener {
public void onServerJoin(FMLNetworkEvent.ClientConnectedToServerEvent e) {
main.getVersionChecker().runUpdateCheck(false);
new TickDelay(() -> main.getChatHelper().sendOfflineMessages(), 6 * 20);
- if (MooConfig.doBestFriendsOnlineCheck && main.getFriendsHandler().getBestFriends().size() > 0) {
+ if (MooConfig.doBestFriendsOnlineCheck && CredentialStorage.isMooValid && main.getFriendsHandler().getBestFriends().size() > 0) {
main.getFriendsHandler().runBestFriendsOnlineCheck(false);
}
isOnSkyBlock = false;
@@ -122,25 +123,23 @@ public class PlayerListener {
}, 40); // 2 second delay, making sure scoreboard got sent
}
- private void registerSkyBlockListeners() {
- if (dungeonsListener == null) {
- MinecraftForge.EVENT_BUS.register(dungeonsListener = new DungeonsListener(main));
- }
- if (skyBlockListener == null) {
- MinecraftForge.EVENT_BUS.register(skyBlockListener = new SkyBlockListener(main));
+ public static boolean registerSkyBlockListeners() {
+ if (dungeonsListener == null && skyBlockListener == null) {
+ MinecraftForge.EVENT_BUS.register(dungeonsListener = new DungeonsListener(Cowlection.getInstance()));
+ MinecraftForge.EVENT_BUS.register(skyBlockListener = new SkyBlockListener(Cowlection.getInstance()));
+ return true;
}
+ return false;
}
- private void unregisterSkyBlockListeners() {
- main.getDungeonCache().onDungeonLeft();
- if (dungeonsListener != null) {
+ public static void unregisterSkyBlockListeners() {
+ Cowlection.getInstance().getDungeonCache().onDungeonLeft();
+ if (dungeonsListener != null && skyBlockListener != null) {
MinecraftForge.EVENT_BUS.unregister(dungeonsListener);
dungeonsListener = null;
- }
- if (skyBlockListener != null) {
MinecraftForge.EVENT_BUS.unregister(skyBlockListener);
skyBlockListener = null;
- main.getLogger().info("Left SkyBlock");
+ Cowlection.getInstance().getLogger().info("Left SkyBlock");
}
}
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 b6bb2d0..1098f1e 100644
--- a/src/main/java/de/cowtipper/cowlection/listener/skyblock/DungeonsListener.java
+++ b/src/main/java/de/cowtipper/cowlection/listener/skyblock/DungeonsListener.java
@@ -1,8 +1,9 @@
package de.cowtipper.cowlection.listener.skyblock;
import de.cowtipper.cowlection.Cowlection;
-import de.cowtipper.cowlection.config.DungeonOverlayGuiConfig;
import de.cowtipper.cowlection.config.MooConfig;
+import de.cowtipper.cowlection.config.gui.MooConfigGui;
+import de.cowtipper.cowlection.data.DataHelper.DungeonClass;
import de.cowtipper.cowlection.handler.DungeonCache;
import de.cowtipper.cowlection.util.TickDelay;
import net.minecraft.client.Minecraft;
@@ -10,9 +11,13 @@ import net.minecraft.client.audio.SoundCategory;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.inventory.GuiChest;
import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.client.renderer.RenderHelper;
+import net.minecraft.init.Blocks;
+import net.minecraft.init.Items;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.Slot;
+import net.minecraft.item.EnumDyeColor;
import net.minecraft.item.ItemSkull;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
@@ -33,12 +38,12 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import net.minecraftforge.fml.relauncher.Side;
import org.apache.commons.lang3.StringUtils;
-import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import java.awt.*;
import java.util.List;
import java.util.*;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -95,11 +100,11 @@ public class DungeonsListener {
*/
private final Pattern DUNGEON_CLASS_MILESTONE_PATTERN = Pattern.compile("^[A-Za-z]+ Milestone (.): ");
- private String activeDungeonClass;
+ private DungeonClass activeDungeonClass;
public DungeonsListener(Cowlection main) {
this.main = main;
- activeDungeonClass = "unknown";
+ activeDungeonClass = DungeonClass.UNKNOWN;
}
@SubscribeEvent(priority = EventPriority.HIGH)
@@ -107,7 +112,7 @@ public class DungeonsListener {
if (e.itemStack == null || e.toolTip == null) {
return;
}
- if (Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) && isDungeonItem(e.toolTip)) {
+ if (MooConfig.isDungeonItemTooltipToggleKeyBindingPressed() && isDungeonItem(e.toolTip)) {
// simplify dungeon armor stats
String originalItemName = e.itemStack.getDisplayName();
NBTTagCompound extraAttributes = e.itemStack.getSubCompound("ExtraAttributes", false);
@@ -275,8 +280,9 @@ public class DungeonsListener {
for (String toolTipLine : dungeonClassIndicator.getTooltip(Minecraft.getMinecraft().thePlayer, false)) {
String line = EnumChatFormatting.getTextWithoutFormattingCodes(toolTipLine);
if (line.startsWith("Currently Selected: ")) {
- String selectedClass = line.substring(line.lastIndexOf(' ') + 1);
- if (!selectedClass.equals(activeDungeonClass)) {
+ String selectedClassName = line.substring(line.lastIndexOf(' ') + 1);
+ DungeonClass selectedClass = DungeonClass.get(selectedClassName);
+ if (!selectedClass.equals(activeDungeonClass) || selectedClass == DungeonClass.UNKNOWN) {
activeDungeonClass = selectedClass;
}
}
@@ -289,11 +295,7 @@ public class DungeonsListener {
int inventoryRows = inventory.getSizeInventory() / 9;
int ySize = 222 - 108 + inventoryRows * 18;
int guiTop = (guiChest.height - ySize) / 2;
- GlStateManager.pushMatrix();
- GlStateManager.translate(0, 0, 280);
- float scaleFactor = 0.8f;
- GlStateManager.scale(scaleFactor, scaleFactor, 0);
for (Slot inventorySlot : inventorySlots.inventorySlots) {
if (inventorySlot.getHasStack()) {
int slotRow = inventorySlot.slotNumber / 9;
@@ -301,13 +303,12 @@ public class DungeonsListener {
// check if slot is one of the middle slots with parties
int maxRow = inventoryRows - 2;
if (slotRow > 0 && slotRow < maxRow && slotColumn > 0 && slotColumn < 8) {
- int slotX = (int) ((guiLeft + inventorySlot.xDisplayPosition) / scaleFactor);
- int slotY = (int) ((guiTop + inventorySlot.yDisplayPosition) / scaleFactor);
+ int slotX = guiLeft + inventorySlot.xDisplayPosition;
+ int slotY = guiTop + inventorySlot.yDisplayPosition;
renderPartyStatus(inventorySlot.getStack(), slotX, slotY);
}
}
}
- GlStateManager.popMatrix();
}
}
}
@@ -317,51 +318,76 @@ public class DungeonsListener {
// not a player skull, don't draw party status indicator
return;
}
- String status = "⬛"; // ok
- Color color = new Color(20, 200, 20, 255);
+ ItemStack indicatorItem = null;
List<String> itemTooltip = item.getTooltip(Minecraft.getMinecraft().thePlayer, false);
if (itemTooltip.size() < 5) {
// not a valid dungeon party tooltip
return;
}
- if (itemTooltip.get(itemTooltip.size() - 1).endsWith("Complete previous floor first!")) {
+ String lastToolTipLine = EnumChatFormatting.getTextWithoutFormattingCodes(itemTooltip.get(itemTooltip.size() - 1));
+ if (lastToolTipLine.endsWith("Complete previous floor first!")
+ || lastToolTipLine.startsWith("Requires a Class at Level")
+ || lastToolTipLine.startsWith("Requires Catacombs Level")) {
// cannot enter dungeon
- status = "✗";
- color = new Color(220, 20, 20, 255);
- } else if (itemTooltip.get(itemTooltip.size() - 1).endsWith("You are in this party!")) {
- status = EnumChatFormatting.OBFUSCATED + "#";
+ indicatorItem = new ItemStack(Blocks.carpet, 1, EnumDyeColor.RED.getMetadata());
+ } else if (lastToolTipLine.endsWith("You are in this party!")) {
+ indicatorItem = new ItemStack(Items.leather, 1);
} else {
- int dungClassMin = MooConfig.dungClassRange[0];
- int dungClassMax = MooConfig.dungClassRange[1];
- Set<String> dungClassesInParty = new HashSet<>();
- dungClassesInParty.add(activeDungeonClass); // add our own class
+ Map<DungeonClass, AtomicInteger> dungClassesInParty = new LinkedHashMap<>();
+ AtomicInteger classCounter = new AtomicInteger();
+ classCounter.incrementAndGet();
+ dungClassesInParty.put(activeDungeonClass, classCounter); // add our own class
+
+ boolean memberTooLowLevel = false;
for (String toolTipLine : itemTooltip) {
Matcher playerDetailMatcher = DUNGEON_PARTY_FINDER_PLAYER.matcher(EnumChatFormatting.getTextWithoutFormattingCodes(toolTipLine));
if (playerDetailMatcher.matches()) {
- String clazz = playerDetailMatcher.group(1);
- int classLevel = MathHelper.parseIntWithDefault(playerDetailMatcher.group(2), -1);
- if (MooConfig.dungFilterPartiesWithDupes && !dungClassesInParty.add(clazz)) {
- // duped class!
- status = "²⁺"; // 2+
- color = new Color(220, 120, 20, 255);
- break;
- } else if (dungClassMin > -1 && classLevel < dungClassMin) {
- // party member too low level
- status = EnumChatFormatting.BOLD + "ᐯ";
- color = new Color(200, 20, 20, 255);
- break;
- } else if (dungClassMax > -1 && classLevel > dungClassMax) {
- // party member too high level
- status = EnumChatFormatting.BOLD + "ᐹ";
- color = new Color(20, 120, 230, 255);
- break;
+ String className = playerDetailMatcher.group(1);
+ DungeonClass clazz = DungeonClass.get(className);
+ dungClassesInParty.putIfAbsent(clazz, new AtomicInteger(0));
+ dungClassesInParty.get(clazz).incrementAndGet();
+
+ int classLevel = MathHelper.parseIntWithDefault(playerDetailMatcher.group(2), 100);
+ if (classLevel < MooConfig.dungClassMin) {
+ memberTooLowLevel = true;
}
}
}
+ if (memberTooLowLevel) {
+ GlStateManager.pushMatrix();
+ GlStateManager.translate(0, 0, 280);
+ Minecraft.getMinecraft().fontRendererObj.drawStringWithShadow(EnumChatFormatting.BOLD + "ᐯ", x + 1, y + 8, new Color(220, 20, 20, 255).getRGB());
+ GlStateManager.popMatrix();
+ }
+ StringBuilder dupedClasses = new StringBuilder();
+ for (Map.Entry<DungeonClass, AtomicInteger> partyClassInfo : dungClassesInParty.entrySet()) {
+ if (partyClassInfo.getValue().get() > 1 && MooConfig.filterDungPartiesWithDupes(partyClassInfo.getKey())) {
+ dupedClasses.append(partyClassInfo.getKey().getShortName());
+ }
+ }
+ if (dupedClasses.length() > 0) {
+ dupedClasses.insert(0, EnumChatFormatting.RED).insert(0, "²⁺");
+
+ GlStateManager.pushMatrix();
+ GlStateManager.translate(0, 0, 280);
+ double scaleFactor = 0.8;
+ GlStateManager.scale(scaleFactor, scaleFactor, 0);
+ Minecraft.getMinecraft().fontRendererObj.drawStringWithShadow(dupedClasses.toString(), (float) (x / scaleFactor), (float) (y / scaleFactor), new Color(255, 170, 0, 255).getRGB());
+ GlStateManager.popMatrix();
+ } else if (!memberTooLowLevel) {
+ // party matches our criteria!
+ indicatorItem = new ItemStack(Blocks.carpet, 1, EnumDyeColor.LIME.getMetadata());
+ }
+ }
+ if (indicatorItem != null) {
+ GlStateManager.enableRescaleNormal();
+ RenderHelper.enableGUIStandardItemLighting();
+ Minecraft.getMinecraft().getRenderItem().renderItemIntoGUI(indicatorItem, x, y);
+ RenderHelper.disableStandardItemLighting();
+ GlStateManager.disableRescaleNormal();
}
- Minecraft.getMinecraft().fontRendererObj.drawStringWithShadow(status, x, y, color.getRGB());
}
// Events inside dungeons
@@ -543,8 +569,8 @@ public class DungeonsListener {
dungeonCache.updateElapsedMinutesFromScoreboard();
}
- boolean isConfigGui = Minecraft.getMinecraft().currentScreen instanceof DungeonOverlayGuiConfig;
- if (MooConfig.dungOverlayEnabled && dungeonCache.isInDungeon() || isConfigGui) {
+ boolean isEditingDungeonOverlaySettings = MooConfigGui.showDungeonPerformanceOverlay();
+ if (MooConfig.dungOverlayEnabled && dungeonCache.isInDungeon() || isEditingDungeonOverlaySettings) {
ArrayList<String> dungeonPerformanceEntries = new ArrayList<>();
int maxSkillScore = dungeonCache.getMaxSkillScore();
int totalDeaths = dungeonCache.getTotalDeaths();
@@ -554,10 +580,10 @@ public class DungeonsListener {
int elapsedMinutes = dungeonCache.getElapsedMinutes();
dungeonPerformanceEntries.add("Max Skill score: " + (maxSkillScore == 100 ? EnumChatFormatting.GREEN : EnumChatFormatting.YELLOW) + maxSkillScore + " / 100");
- if (totalDeaths > 0 || isConfigGui) {
+ if (totalDeaths > 0 || isEditingDungeonOverlaySettings) {
dungeonPerformanceEntries.add(" Deaths: " + EnumChatFormatting.RED + totalDeaths);
}
- if (failedPuzzles > 0 || isConfigGui) {
+ if (failedPuzzles > 0 || isEditingDungeonOverlaySettings) {
dungeonPerformanceEntries.add(" Failed Puzzles: " + EnumChatFormatting.RED + failedPuzzles);
}
dungeonPerformanceEntries.add("Class Milestone: " + (classMilestone < 3 ? EnumChatFormatting.RED : EnumChatFormatting.GREEN) + classMilestone);
@@ -579,12 +605,18 @@ public class DungeonsListener {
FontRenderer fontRenderer = Minecraft.getMinecraft().fontRendererObj;
GlStateManager.pushMatrix();
+
float scaleFactor = MooConfig.dungOverlayGuiScale / 100f;
GlStateManager.scale(scaleFactor, scaleFactor, 0);
for (int line = 0; line < dungeonPerformanceEntries.size(); line++) {
String dungeonPerformanceEntry = dungeonPerformanceEntries.get(line);
- int yPos = MooConfig.dungOverlayPositionY + fontRenderer.FONT_HEIGHT * line + 2;
- fontRenderer.drawString(dungeonPerformanceEntry, MooConfig.dungOverlayPositionX, yPos, 0xffFFAA00);
+ int xPos = (int) ((e.resolution.getScaledWidth() * (MooConfig.dungOverlayPositionX / 1000d)) / scaleFactor);
+ int yPos = (int) ((e.resolution.getScaledHeight() * (MooConfig.dungOverlayPositionY / 1000d) + 2) / scaleFactor + fontRenderer.FONT_HEIGHT * line + 2);
+ if (MooConfig.dungOverlayTextShadow) {
+ fontRenderer.drawStringWithShadow(dungeonPerformanceEntry, xPos, yPos, 0xffFFAA00);
+ } else {
+ fontRenderer.drawString(dungeonPerformanceEntry, xPos, yPos, 0xffFFAA00);
+ }
}
GlStateManager.popMatrix();
}
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 d6b94fc..29b5e51 100644
--- a/src/main/java/de/cowtipper/cowlection/listener/skyblock/SkyBlockListener.java
+++ b/src/main/java/de/cowtipper/cowlection/listener/skyblock/SkyBlockListener.java
@@ -18,7 +18,6 @@ import net.minecraftforge.common.util.Constants;
import net.minecraftforge.event.entity.player.ItemTooltipEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import org.apache.commons.lang3.StringUtils;
-import org.lwjgl.input.Keyboard;
import java.text.NumberFormat;
import java.text.ParseException;
@@ -73,12 +72,13 @@ public class SkyBlockListener {
}
}
- if (!MooConfig.showAdvancedTooltips && !Keyboard.isKeyDown(Keyboard.KEY_LMENU)) {
- return;
- }
+ MooConfig.Setting tooltipItemAgeDisplay = MooConfig.getTooltipItemAgeDisplay();
+ MooConfig.Setting tooltipItemTimestampDisplay = MooConfig.getTooltipItemTimestampDisplay();
+
// add item age to tooltip
NBTTagCompound extraAttributes = e.itemStack.getSubCompound("ExtraAttributes", false);
- if (extraAttributes != null && extraAttributes.hasKey("timestamp")) {
+ if (extraAttributes != null && extraAttributes.hasKey("timestamp")
+ && (tooltipItemAgeDisplay != MooConfig.Setting.DISABLED || tooltipItemTimestampDisplay != MooConfig.Setting.DISABLED)) {
String rawTimestamp = extraAttributes.getString("timestamp");
Matcher sbTimestampMatcher = SB_TIMESTAMP_PATTERN.matcher(rawTimestamp);
if (sbTimestampMatcher.matches()) {
@@ -88,19 +88,29 @@ public class SkyBlockListener {
int index = Math.max(0, e.toolTip.size() - (e.showAdvancedItemTooltips ? /* item name & nbt info */ 2 : 0));
- if (Keyboard.isKeyDown(Keyboard.KEY_LMENU)) {
- // full tooltip
- e.toolTip.add(index, "Timestamp: " + EnumChatFormatting.DARK_GRAY + dateTimeFormatted);
- e.toolTip.add(index, "Item age: " + EnumChatFormatting.DARK_GRAY + Utils.getDurationAsWords(dateTime.toEpochSecond() * 1000).first());
- } else {
- // abbreviated tooltip
- e.toolTip.add(index, "Item age: " + EnumChatFormatting.DARK_GRAY + Utils.getDurationAsWord(dateTime.toEpochSecond() * 1000));
+ switch (tooltipItemTimestampDisplay) {
+ case SPECIAL:
+ if (!MooConfig.isTooltipToggleKeyBindingPressed()) {
+ break;
+ }
+ case ALWAYS:
+ e.toolTip.add(index, "Timestamp: " + EnumChatFormatting.DARK_GRAY + dateTimeFormatted);
+ }
+ switch (tooltipItemAgeDisplay) {
+ case SPECIAL:
+ if (!MooConfig.isTooltipToggleKeyBindingPressed()) {
+ break;
+ }
+ case ALWAYS:
+ e.toolTip.add(index, "Item age: " + EnumChatFormatting.DARK_GRAY + ((MooConfig.tooltipItemAgeShortened) ? Utils.getDurationAsWord(dateTime.toEpochSecond() * 1000) : Utils.getDurationAsWords(dateTime.toEpochSecond() * 1000).first()));
}
}
}
// for auction house: show price for each item if multiple items are sold at once
- if (e.entityPlayer != null && e.entityPlayer.openContainer instanceof ContainerChest) {
+ MooConfig.Setting tooltipAuctionHousePriceEachDisplay = MooConfig.getTooltipAuctionHousePriceEachDisplay();
+ if ((tooltipAuctionHousePriceEachDisplay == MooConfig.Setting.ALWAYS || tooltipAuctionHousePriceEachDisplay == MooConfig.Setting.SPECIAL && MooConfig.isTooltipToggleKeyBindingPressed())
+ && e.entityPlayer != null && e.entityPlayer.openContainer instanceof ContainerChest) {
int stackSize = e.itemStack.stackSize;
if ((stackSize == 1 && !isSubmitBidItem(e.itemStack)) || e.toolTip.size() < 4) {
// only 1 item or irrelevant tooltip - nothing to do here, abort!
@@ -110,11 +120,11 @@ public class SkyBlockListener {
if (isSubmitBidItem(e.itemStack)) {
// special case: "place bid on an item" interface ("Auction View")
ItemStack auctionedItem = e.entityPlayer.openContainer.getInventory().get(13);
- stackSize = auctionedItem.stackSize;
- if (stackSize == 1) {
+ if (auctionedItem == null || auctionedItem.stackSize == 1) {
// still only 1 item, abort!
return;
}
+ stackSize = auctionedItem.stackSize;
}
List<String> toolTip = e.toolTip;
@@ -124,6 +134,7 @@ public class SkyBlockListener {
String toolTipLineUnformatted = EnumChatFormatting.getTextWithoutFormattingCodes(toolTip.get(i));
if (toolTipLineUnformatted.startsWith("Top bid: ")
|| toolTipLineUnformatted.startsWith("Starting bid: ")
+ || toolTipLineUnformatted.startsWith("Create BIN Auction: ")
|| toolTipLineUnformatted.startsWith("Buy it now: ")
|| toolTipLineUnformatted.startsWith("Sold for: ")
|| toolTipLineUnformatted.startsWith("New bid: ") /* special case: 'Submit Bid' item */) {
diff --git a/src/main/java/de/cowtipper/cowlection/search/GuiSearch.java b/src/main/java/de/cowtipper/cowlection/search/GuiSearch.java
index ed1a1d9..f9b68a1 100644
--- a/src/main/java/de/cowtipper/cowlection/search/GuiSearch.java
+++ b/src/main/java/de/cowtipper/cowlection/search/GuiSearch.java
@@ -5,6 +5,7 @@ import com.mojang.realmsclient.util.Pair;
import de.cowtipper.cowlection.Cowlection;
import de.cowtipper.cowlection.config.MooConfig;
import de.cowtipper.cowlection.data.LogEntry;
+import de.cowtipper.cowlection.util.GuiHelper;
import de.cowtipper.cowlection.util.Utils;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.*;
@@ -13,11 +14,13 @@ import net.minecraft.client.renderer.Tessellator;
import net.minecraft.util.ChatComponentText;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.IChatComponent;
-import net.minecraftforge.common.ForgeVersion;
+import net.minecraftforge.common.config.ConfigElement;
+import net.minecraftforge.common.config.Property;
import net.minecraftforge.fml.client.GuiScrollingList;
import net.minecraftforge.fml.client.config.GuiButtonExt;
import net.minecraftforge.fml.client.config.GuiCheckBox;
-import net.minecraftforge.fml.client.config.GuiUtils;
+import net.minecraftforge.fml.client.config.GuiConfig;
+import net.minecraftforge.fml.client.config.IConfigElement;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
@@ -67,6 +70,7 @@ public class GuiSearch extends GuiScreen {
private GuiButton buttonSearch;
private GuiButton buttonClose;
private GuiButton buttonHelp;
+ private GuiButton buttonSettings;
private GuiCheckBox checkboxChatOnly;
private GuiCheckBox checkboxMatchCase;
private GuiCheckBox checkboxRemoveFormatting;
@@ -107,6 +111,9 @@ public class GuiSearch extends GuiScreen {
public void initGui() {
this.guiTooltips = new ArrayList<>();
+ // recalculate start date
+ this.dateStart = MooConfig.calculateStartDate();
+
this.fieldSearchQuery = new GuiTextField(42, this.fontRendererObj, this.width / 2 - 100, 13, 200, 20);
this.fieldSearchQuery.setMaxStringLength(255);
this.fieldSearchQuery.setText(searchQuery);
@@ -131,8 +138,11 @@ public class GuiSearch extends GuiScreen {
this.buttonList.add(this.buttonClose = new GuiButtonExt(0, this.width - 25, 3, 22, 20, EnumChatFormatting.RED + "X"));
addTooltip(buttonClose, Arrays.asList(EnumChatFormatting.RED + "Close search interface", "" + EnumChatFormatting.GRAY + EnumChatFormatting.ITALIC + "Hint:" + EnumChatFormatting.RESET + " alternatively press ESC"));
// help
- this.buttonList.add(this.buttonHelp = new GuiButtonExt(1, this.width - 25 - 25, 3, 22, 20, "?"));
+ this.buttonList.add(this.buttonHelp = new GuiButtonExt(1, this.width - 2 * 25, 3, 22, 20, "?"));
addTooltip(buttonHelp, Collections.singletonList(EnumChatFormatting.YELLOW + "Show help"));
+ // settings
+ this.buttonList.add(this.buttonSettings = new GuiButtonExt(1, this.width - 3 * 25, 3, 22, 20, ""));
+ addTooltip(buttonSettings, Collections.singletonList(EnumChatFormatting.YELLOW + "Open Settings"));
// chatOnly
this.buttonList.add(this.checkboxChatOnly = new GuiCheckBox(21, this.width / 2 - 100, 35, " Chatbox only", chatOnly));
@@ -255,10 +265,11 @@ public class GuiSearch extends GuiScreen {
this.guiSearchResults.drawScreen(mouseX, mouseY, partialTicks);
super.drawScreen(mouseX, mouseY, partialTicks);
+ GuiHelper.drawSprite(this.width - 3 * 25 + 2, 3, 36, 18, 500);
for (GuiTooltip guiTooltip : guiTooltips) {
if (guiTooltip.checkHover(mouseX, mouseY)) {
- drawHoveringText(guiTooltip.getText(), mouseX, mouseY, 300);
+ GuiHelper.drawHoveringText(guiTooltip.getText(), mouseX, mouseY, width, height, 300);
// only one tooltip can be displayed at a time: break!
break;
}
@@ -310,10 +321,10 @@ public class GuiSearch extends GuiScreen {
} else if (button == buttonHelp) {
this.areEntriesSearchResults = false;
this.searchResults.clear();
- this.searchResults.add(new LogEntry("" + EnumChatFormatting.GOLD + EnumChatFormatting.BOLD + "Initial setup/Configuration " + EnumChatFormatting.GRAY + EnumChatFormatting.ITALIC + "/moo config"));
+ 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("" + EnumChatFormatting.GOLD + EnumChatFormatting.BOLD + "Performing a search " + EnumChatFormatting.GRAY + EnumChatFormatting.ITALIC + "/moo search"));
+ 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"));
this.searchResults.add(new LogEntry(EnumChatFormatting.GOLD + " 3) " + EnumChatFormatting.RESET + "Select desired options (match case, ...)"));
@@ -324,6 +335,15 @@ public class GuiSearch extends GuiScreen {
this.searchResults.add(new LogEntry(EnumChatFormatting.GOLD + " - " + EnumChatFormatting.YELLOW + "CTRL + A " + EnumChatFormatting.RESET + "to copy all search results"));
this.searchResults.add(new LogEntry(EnumChatFormatting.GOLD + " - " + EnumChatFormatting.YELLOW + "Double click search result " + EnumChatFormatting.RESET + "to open corresponding log file in default text editor"));
this.guiSearchResults.setResults(searchResults);
+ } else if (button == buttonSettings) {
+ List<IConfigElement> logSearchConfigElements = new ArrayList<>();
+ for (Property configEntry : Cowlection.getInstance().getConfig().getLogSearchProperties()) {
+ logSearchConfigElements.add(new ConfigElement(configEntry));
+ }
+ mc.displayGuiScreen(new GuiConfig(this,
+ logSearchConfigElements,
+ Cowlection.MODID, "cowlectionLogSearchConfig", false, false,
+ EnumChatFormatting.GOLD + "Press Done to save changes."));
}
}
@@ -350,17 +370,6 @@ public class GuiSearch extends GuiScreen {
}
}
- private void drawHoveringText(List<String> textLines, int mouseX, int mouseY, int maxTextWidth) {
- if (ForgeVersion.getBuildVersion() < 1808) {
- // we're running a forge version from before 24 March 2016 (http://files.minecraftforge.net/maven/net/minecraftforge/forge/index_1.8.9.html for reference)
- // using mc built-in method
- drawHoveringText(textLines, mouseX, mouseY, fontRendererObj);
- } else {
- // we're on a newer forge version, so we can use the improved tooltip rendering added in 1.8.9-11.15.1.1808 (released 03/24/16 09:25 PM) in this pull request: https://github.com/MinecraftForge/MinecraftForge/pull/2649
- GuiUtils.drawHoveringText(textLines, mouseX, mouseY, width, height, maxTextWidth, fontRendererObj);
- }
- }
-
/**
* List gui element similar to GuiModList.Info
*/
@@ -454,7 +463,7 @@ public class GuiSearch extends GuiScreen {
int left = width / 2 - stringWidth / 2 - margin;
int top = height / 2 - margin;
drawRect(left, top, left + stringWidth + 2 * margin, top + fontRendererObj.FONT_HEIGHT + 2 * margin, 0xff000000);
- drawCenteredString(fontRendererObj, errorText,/* 2, 30*/width / 2, height / 2, 0xffDD1111);
+ drawCenteredString(fontRendererObj, errorText, width / 2, height / 2, 0xffDD1111);
} else {
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 636a46d..2e811ef 100644
--- a/src/main/java/de/cowtipper/cowlection/search/LogFilesSearcher.java
+++ b/src/main/java/de/cowtipper/cowlection/search/LogFilesSearcher.java
@@ -48,7 +48,7 @@ class LogFilesSearcher {
}
if (files.isEmpty()) {
- throw new FileNotFoundException(EnumChatFormatting.DARK_RED + "ERROR: Couldn't find any Minecraft log files. Please check if the log file directories are set correctly (/moo config).");
+ throw new FileNotFoundException(EnumChatFormatting.DARK_RED + "ERROR: Couldn't find any Minecraft log files. Please check if the log file directories are set correctly (Log Search \u27A1 Settings).");
} else {
List<LogEntry> searchResults = analyzeFiles(files, searchQuery, chatOnly, matchCase, removeFormatting)
.stream().sorted(Comparator.comparing(LogEntry::getTime)).collect(Collectors.toList());
@@ -65,7 +65,7 @@ class LogFilesSearcher {
: new BufferedReader(new InputStreamReader(new GZIPInputStream(new FileInputStream(path.toFile())))))) { // ....log.gz
String fileName = path.getFileName().toString(); // 2020-04-20-3.log.gz
String date = fileName.equals("latest.log")
- ? LocalDate.now().format(DateTimeFormatter.ISO_LOCAL_DATE)
+ ? DateTimeFormatter.ofPattern("yyyy-MM-dd").withZone(ZoneId.systemDefault()).format(Files.getLastModifiedTime(path).toInstant())
: fileName.substring(0, fileName.lastIndexOf('-'));
String content;
LogEntry logEntry = null;
diff --git a/src/main/java/de/cowtipper/cowlection/util/ApiUtils.java b/src/main/java/de/cowtipper/cowlection/util/ApiUtils.java
index 8b37cf7..442c940 100644
--- a/src/main/java/de/cowtipper/cowlection/util/ApiUtils.java
+++ b/src/main/java/de/cowtipper/cowlection/util/ApiUtils.java
@@ -31,6 +31,7 @@ public class ApiUtils {
private static final String ONLINE_STATUS_URL = "https://api.hypixel.net/status?key=%s&uuid=%s";
private static final String SKYBLOCK_STATS_URL = "https://api.hypixel.net/skyblock/profiles?key=%s&uuid=%s";
private static final String PLAYER_URL = "https://api.hypixel.net/player?key=%s&uuid=%s";
+ private static final String API_KEY_URL = "https://api.hypixel.net/key?key=%s";
private static final ExecutorService pool = Executors.newCachedThreadPool();
private ApiUtils() {
@@ -120,6 +121,21 @@ public class ApiUtils {
return null;
}
+ public static void fetchApiKeyInfo(String moo, ThrowingConsumer<HyApiKey> action) {
+ pool.execute(() -> action.accept(getApiKeyInfo(moo)));
+ }
+
+ private static HyApiKey getApiKeyInfo(String moo) {
+ try (BufferedReader reader = makeApiCall(String.format(API_KEY_URL, moo))) {
+ if (reader != null) {
+ return GsonUtils.fromJson(reader, HyApiKey.class);
+ }
+ } catch (IOException | JsonSyntaxException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
private static BufferedReader makeApiCall(String url) throws IOException {
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
connection.setConnectTimeout(5000);
diff --git a/src/main/java/de/cowtipper/cowlection/util/Utils.java b/src/main/java/de/cowtipper/cowlection/util/Utils.java
index e833cf8..24e6b7b 100644
--- a/src/main/java/de/cowtipper/cowlection/util/Utils.java
+++ b/src/main/java/de/cowtipper/cowlection/util/Utils.java
@@ -111,7 +111,7 @@ public final class Utils {
private static String formatNumberWithAbbreviations(double number, int iteration) {
@SuppressWarnings("IntegerDivisionInFloatingPointContext") double d = ((long) number / 100) / 10.0;
- boolean isRound = (d * 10) % 10 == 0; //true if the decimal part is equal to 0 (then it's trimmed anyway)
+ boolean isRound = (d * 10) % 10 == 0; // true if the decimal part is equal to 0 (then it's trimmed anyway)
// this determines the class, i.e. 'k', 'm' etc
// this decides whether to trim the decimals
// (int) d * 10 / 10 drops the decimal
diff --git a/src/main/resources/assets/cowlection/lang/en_US.lang b/src/main/resources/assets/cowlection/lang/en_US.lang
index 0bcad5d..14bb5f7 100644
--- a/src/main/resources/assets/cowlection/lang/en_US.lang
+++ b/src/main/resources/assets/cowlection/lang/en_US.lang
@@ -1,31 +1,67 @@
+cowlection.config.isMooValid=API key valid? §d§l⚷
+cowlection.config.isMooValid.tooltip=You can use /moo apikey to see how to request a new API key from Hypixel\n§eConfig entries marked with §d§l⚷ §erequire a valid API key.
+cowlection.config.configGuiExplanations=Show config categories explanations...
+cowlection.config.configGuiExplanations.tooltip=How should the explanations (introductory words, hints, and tips) of the individual configuration categories be displayed?
+cowlection.config.tabCompletableNamesCommands=Commands with Tab-completable usernames
+cowlection.config.tabCompletableNamesCommands.tooltip=List of commands with a username argument that should be Tab-completable.\n§eRequires game restart to take effect!
+cowlection.config.gotoLogSearchConfig=Search through your Minecraft logs
+cowlection.config.gotoLogSearchConfig.tooltip=Settings can be accessed at the top right corner
+cowlection.config.logsDirs=Directories with Minecraft log files
+cowlection.config.logsDirs.tooltip=List of directories containing Minecraft log files
+cowlection.config.defaultStartDate=Start date for log file search §c[see tooltip!]
+cowlection.config.defaultStartDate.tooltip=§eCan be either a §6number§e (e.g. "§63§e" means "§6start searching 3 months ago§e"),\n§eor alternatively a §6fixed date §e(§6yyyy-mm-dd§e)
+cowlection.config.gotoKeyBindings=Change key bindings
+cowlection.config.gotoKeyBindings.tooltip=Some key bindings can be found in the 'Cowlection' sub-category
cowlection.config.doUpdateCheck=Check for updates
-cowlection.config.doUpdateCheck.tooltip=Check for mod updates?
+cowlection.config.doUpdateCheck.tooltip=Check for mod updates when launching the game?
cowlection.config.showBestFriendNotifications=Show best friend notifications
cowlection.config.showBestFriendNotifications.tooltip=Set to true to receive best friends' login/logout messages, set to false hide them.
cowlection.config.showFriendNotifications=Show friend notifications
cowlection.config.showFriendNotifications.tooltip=Set to true to receive friends' login/logout messages, set to false hide them.
cowlection.config.showGuildNotifications=Show guild notifications
cowlection.config.showGuildNotifications.tooltip=Set to true to receive guild members' login/logout messages, set to false hide them.
-cowlection.config.doBestFriendsOnlineCheck=Do best friends online check
-cowlection.config.doBestFriendsOnlineCheck.tooltip=Set to true to check best friends' online status when joining a server, set to false to disable.\n§fDoes §dnot §fwork for staff members and players hiding their online status.
-cowlection.config.showAdvancedTooltips=Show advanced tooltips
-cowlection.config.showAdvancedTooltips.tooltip=Set to true to show advanced tooltips, set to false show default tooltips.
+cowlection.config.doBestFriendsOnlineCheck=Do best friends online check §d§l⚷
+cowlection.config.doBestFriendsOnlineCheck.tooltip=Set to true to check best friends' online status when joining a server, set to false to disable.\n§fDoes §dnot §fwork for staff members and players hiding their online status.\n§d§l⚷ §eRequires a valid API key!
+cowlection.config.tooltipToggleKeyBinding=Key binding: toggle tooltip
+cowlection.config.tooltipToggleKeyBinding.tooltip=Hold down this key to toggle tooltip if one of the following settings is set to 'key press'
+cowlection.config.tooltipAuctionHousePriceEach=Auction house: price per item
+cowlection.config.tooltipAuctionHousePriceEach.tooltip=Add price per item if multiple items are bought or sold?
+cowlection.config.tooltipItemAge=Show item age
+cowlection.config.tooltipItemAge.tooltip=Show item age? Only works for non-stackable items
+cowlection.config.tooltipItemAgeShortened=Shorten item age?
+cowlection.config.tooltipItemAgeShortened.tooltip=Show shortened (5.8 months) or detailed item age (5 months 24 days)?
+cowlection.config.tooltipItemTimestamp=Show item creation date
+cowlection.config.tooltipItemTimestamp.tooltip=Show item creation date? Only works for non-stackable items
cowlection.config.numeralSystem=Numeral system
-cowlection.config.numeralSystem.tooltip=Use Roman or Arabic numeral system?
-cowlection.config.tabCompletableNamesCommands=Commands with Tab-completable usernames
-cowlection.config.tabCompletableNamesCommands.tooltip=List of commands with a username argument that should be Tab-completable.\nRequires game restart to take effect!
-cowlection.config.dungClassRange=Dungeon Parties: Class level range
-cowlection.config.dungClassRange.tooltip=Accepted level range for the dungeon party finder. Set to -1 to disable
-cowlection.config.dungFilterPartiesWithDupes=Dungeon Parties: Mark duplicated classes?
-cowlection.config.dungFilterPartiesWithDupes.tooltip=Mark parties with duplicated classes?
-cowlection.config.dungPartyFinderArmorLookup=Dungeon Parties: Show armor...
-cowlection.config.dungPartyFinderArmorLookup.tooltip=Show armor of player joining via party finder as a tooltip or in chat?
-cowlection.config.dungItemQualityPos=Dungeon tooltips: Item Quality positon
+cowlection.config.numeralSystem.tooltip=Use Roman or Arabic numeral system?\nThis is currently used to display numbers in the commands /moo stalkSkyBlock and /moo analyzeIsland
+cowlection.config.dungItemToolTipToggleKeyBinding=Key binding: toggle dungeon item tooltip
+cowlection.config.dungItemToolTipToggleKeyBinding.tooltip=Hold down this key to toggle dungeon item tooltip
+cowlection.config.dungItemQualityPos=Item Quality position (hold above keybind)
cowlection.config.dungItemQualityPos.tooltip=Position of item quality in dungeon item tooltips
-cowlection.config.logsDirs=Directories with Minecraft log files
-cowlection.config.logsDirs.tooltip=List of directories containing Minecraft log files
-cowlection.config.defaultStartDate=Start date for log file search
-cowlection.config.defaultStartDate.tooltip=§eCan be either a §6number§e (e.g. "§63§e" means "§6start searching 3 months ago§e"),\n§eor alternatively a §6fixed date §e(§6yyyy-mm-dd§e)
+cowlection.config.dungOverlayEnabled=Show overlay inside dungeons?
+cowlection.config.dungOverlayEnabled.tooltip=Show the performance overlay while inside a dungeon?
+cowlection.config.dungOverlayPositionX=Overlay x position (⇦/⇨ keys to fine-tune)
+cowlection.config.dungOverlayPositionX.tooltip=Use left and right arrow key to increment/decrement the x position by 1
+cowlection.config.dungOverlayPositionY=Overlay y position (⇦/⇨ keys to fine-tune)
+cowlection.config.dungOverlayPositionY.tooltip=Use left and right arrow key to increment/decrement the y position by 1
+cowlection.config.dungOverlayGuiScale=Overlay Gui Scale
+cowlection.config.dungOverlayGuiScale.tooltip=Adjust the size of the dungeon performance overlay (50%%-200%%)
+cowlection.config.dungOverlayTextShadow=Add text shadow
+cowlection.config.dungOverlayTextShadow.tooltip=Enable or disable text shadow
+cowlection.config.dungClassMin=Minimum preferred class level
+cowlection.config.dungClassMin.tooltip=Marks parties with members with lower class level than this value
+cowlection.config.dungFilterPartiesWithArcherDupes=Mark duplicated Archer class?
+cowlection.config.dungFilterPartiesWithArcherDupes.tooltip=Mark parties with duplicated Archer class?
+cowlection.config.dungFilterPartiesWithBerserkDupes=Mark duplicated Berserk class?
+cowlection.config.dungFilterPartiesWithBerserkDupes.tooltip=Mark parties with duplicated Berserk class?
+cowlection.config.dungFilterPartiesWithHealerDupes=Mark duplicated Healer class?
+cowlection.config.dungFilterPartiesWithHealerDupes.tooltip=Mark parties with duplicated Healer class?
+cowlection.config.dungFilterPartiesWithMageDupes=Mark duplicated Mage class?
+cowlection.config.dungFilterPartiesWithMageDupes.tooltip=Mark parties with duplicated Mage class?
+cowlection.config.dungFilterPartiesWithTankDupes=Mark duplicated Tank class?
+cowlection.config.dungFilterPartiesWithTankDupes.tooltip=Mark parties with duplicated Tank class?
+cowlection.config.dungPartyFinderArmorLookup=Show armor of joining player... §d§l⚷
+cowlection.config.dungPartyFinderArmorLookup.tooltip=Show armor of player joining via party finder as a tooltip or in chat?\n§d§l⚷ §eRequires a valid API key!
cowlection.commands.generic.exception=%s
key.cowlection.category=Cowlection
-key.cowlection.moo.desc=Open Command
+key.cowlection.moo=Open Command