aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornea <nea@nea.moe>2023-02-17 20:54:04 +0100
committernea <nea@nea.moe>2023-02-17 20:54:04 +0100
commit1cb9bbc261891b9283c1e4cbd246c6e4d2bd87df (patch)
treed0cd9516c1a9f8ffff4ae314faa79f4badd3ae40
parenta851b80bccac8a190b3f1532bcb3de1b7e1c6a3f (diff)
parent1d75ac44c20fafd9f834dc7c01066a85a74f89e7 (diff)
downloadNotEnoughUpdates-1cb9bbc261891b9283c1e4cbd246c6e4d2bd87df.tar.gz
NotEnoughUpdates-1cb9bbc261891b9283c1e4cbd246c6e4d2bd87df.tar.bz2
NotEnoughUpdates-1cb9bbc261891b9283c1e4cbd246c6e4d2bd87df.zip
Merge remote-tracking branch 'origin/master' into museumthing
-rw-r--r--README.md2
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java9
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java2
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/auction/APIManager.java14
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/dev/DevTestCommand.java34
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/misc/PronounsCommand.java2
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigOption.java1
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/util/ArrowPagesUtils.java2
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/cosmetics/CapeManager.java4
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CookieWarning.java211
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/ItemCooldowns.java9
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/PetInfoOverlay.java61
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/PowerStoneStatsDisplay.java30
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/updater/AutoUpdater.java2
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/world/FrozenTreasuresHighlighter.java56
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscgui/CalendarOverlay.java1
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscgui/minionhelper/loaders/MinionHelperApiLoader.java7
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/NEUConfig.java2
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/customtypes/NEUDebugFlag.java5
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Misc.java9
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/MiscOverlays.java10
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/PetOverlay.java9
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/overlays/TimersOverlay.java16
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/BasicPage.java81
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ProfileViewer.java102
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ProfileViewerUtils.java156
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/LevelPage.java15
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/CoreTaskLevel.java50
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/DungeonTaskLevel.java16
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/EssenceTaskLevel.java20
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/EventTaskLevel.java106
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/MiscTaskLevel.java69
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/SkillRelatedTaskLevel.java90
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/SlayingTaskLevel.java13
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/StoryTaskLevel.java6
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/ApiUtil.java59
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/SBInfo.java7
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java59
-rw-r--r--src/main/kotlin/io/github/moulberry/notenoughupdates/events/ProfileDataLoadedEvent.kt (renamed from src/main/java/io/github/moulberry/notenoughupdates/events/ProfileDataLoadedEvent.java)34
-rw-r--r--src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/OldSkyBlockMenu.kt195
-rw-r--r--src/main/kotlin/io/github/moulberry/notenoughupdates/util/ApiCache.kt215
-rw-r--r--src/main/kotlin/io/github/moulberry/notenoughupdates/util/ErrorUtil.kt43
-rw-r--r--src/main/kotlin/io/github/moulberry/notenoughupdates/util/MinecraftExecutor.kt (renamed from src/main/java/io/github/moulberry/notenoughupdates/util/MinecraftExecutor.java)38
-rw-r--r--src/main/resources/assets/notenoughupdates/pv_levels.pngbin3526 -> 3386 bytes
44 files changed, 1423 insertions, 449 deletions
diff --git a/README.md b/README.md
index 4249abc8..10cd88e5 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
<div align="center">
<!-- release -->
<a href="https://github.com/Moulberry/NotEnoughUpdates/releases/latest" target="_blank">
- <img src="https://img.shields.io/github/v/release/Moulberry/NotEnoughUpdates-REPO?color=informational&include_prereleases&label=release&logo=github&logoColor=white" alt="release">
+ <img src="https://img.shields.io/github/v/release/Moulberry/NotEnoughUpdates?color=informational&include_prereleases&label=release&logo=github&logoColor=white" alt="release">
</a>
<!-- lines -->
<a href="https://github.com/NotEnoughUpdates/NotEnoughUpdates/graphs/code-frequency" target="_blank">
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java
index 7159ef89..927b5e76 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java
@@ -1500,7 +1500,14 @@ public class NEUOverlay extends Gui {
int actualIndex = index + getSlotsXSize() * getSlotsYSize() * page;
List<JsonObject> searchedItems = getSearchedItems();
if (0 <= actualIndex && actualIndex < searchedItems.size()) {
- return searchedItems.get(actualIndex);
+ try {
+ return searchedItems.get(actualIndex);
+ } catch (IndexOutOfBoundsException e) {
+ System.out.println("searchedItems size: " + searchedItems.size());
+ System.out.println("actualIndex: " + actualIndex);
+ e.printStackTrace();
+ return null;
+ }
} else {
return null;
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java
index 94c7cc2b..ac1121ee 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java
@@ -97,7 +97,7 @@ import java.util.Set;
guiFactory = "io.github.moulberry.notenoughupdates.core.config.MoulConfigGuiForgeInterop")
public class NotEnoughUpdates {
public static final String MODID = "notenoughupdates";
- public static final String VERSION = "2.1.0-REL";
+ public static final String VERSION = "2.1.1-PRE";
public static final int VERSION_ID = 20101; //2.1.1 only so update notif works
public static final int PRE_VERSION_ID = 0;
public static final int HOTFIX_VERSION_ID = 0;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/auction/APIManager.java b/src/main/java/io/github/moulberry/notenoughupdates/auction/APIManager.java
index 5ec3724a..ac60ffd9 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/auction/APIManager.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/auction/APIManager.java
@@ -292,7 +292,7 @@ public class APIManager {
.newMoulberryRequest("lowestbin.json.gz")
.gunzip()
.requestJson()
- .thenAccept(jsonObject -> {
+ .thenAcceptAsync(jsonObject -> {
if (lowestBins == null) {
lowestBins = new JsonObject();
}
@@ -465,12 +465,12 @@ public class APIManager {
};
manager.apiUtils.newMoulberryRequest("auctionLast.json.gz")
- .gunzip().requestJson().thenAccept(process);
+ .gunzip().requestJson().thenAcceptAsync(process);
manager.apiUtils
.newMoulberryRequest("auction.json.gz")
.gunzip().requestJson()
- .thenAccept(jsonObject -> {
+ .thenAcceptAsync(jsonObject -> {
if (jsonObject.get("success").getAsBoolean()) {
long apiUpdate = (long) jsonObject.get("time").getAsFloat();
if (lastApiUpdate == apiUpdate) {
@@ -683,7 +683,7 @@ public class APIManager {
manager.apiUtils
.newAnonymousHypixelApiRequest("skyblock/auctions")
.requestJson()
- .thenAccept(jsonObject -> {
+ .thenAcceptAsync(jsonObject -> {
if (jsonObject == null) return;
if (jsonObject.get("success").getAsBoolean()) {
@@ -733,7 +733,7 @@ public class APIManager {
manager.apiUtils
.newAnonymousHypixelApiRequest("skyblock/bazaar")
.requestJson()
- .thenAccept(jsonObject -> {
+ .thenAcceptAsync(jsonObject -> {
if (!jsonObject.get("success").getAsBoolean()) return;
craftCost.clear();
@@ -789,7 +789,7 @@ public class APIManager {
public void updateAvgPrices() {
manager.apiUtils
.newMoulberryRequest("auction_averages/3day.json.gz")
- .gunzip().requestJson().thenAccept((jsonObject) -> {
+ .gunzip().requestJson().thenAcceptAsync((jsonObject) -> {
craftCost.clear();
auctionPricesJson = jsonObject;
lastAuctionAvgUpdate = System.currentTimeMillis();
@@ -797,7 +797,7 @@ public class APIManager {
manager.apiUtils
.newMoulberryRequest("auction_averages_lbin/1day.json.gz")
.gunzip().requestJson()
- .thenAccept((jsonObject) -> {
+ .thenAcceptAsync((jsonObject) -> {
auctionPricesAvgLowestBinJson = jsonObject;
});
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/DevTestCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/DevTestCommand.java
index 0d882358..1a1400ab 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/DevTestCommand.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/DevTestCommand.java
@@ -33,11 +33,13 @@ import io.github.moulberry.notenoughupdates.miscfeatures.customblockzones.Locati
import io.github.moulberry.notenoughupdates.miscfeatures.customblockzones.SpecialBlockZone;
import io.github.moulberry.notenoughupdates.miscgui.GuiPriceGraph;
import io.github.moulberry.notenoughupdates.miscgui.minionhelper.MinionHelperManager;
+import io.github.moulberry.notenoughupdates.util.ApiCache;
import io.github.moulberry.notenoughupdates.util.PronounDB;
import io.github.moulberry.notenoughupdates.util.SBInfo;
import io.github.moulberry.notenoughupdates.util.TabListUtils;
import io.github.moulberry.notenoughupdates.util.Utils;
import io.github.moulberry.notenoughupdates.util.hypixelapi.ProfileCollectionInfo;
+import lombok.var;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.command.CommandException;
@@ -94,6 +96,8 @@ public class DevTestCommand extends ClientCommandBase {
};
private int devFailIndex = 0;
+ public static int testValue = 0;
+
public DevTestCommand() {
super("neudevtest");
}
@@ -126,6 +130,24 @@ public class DevTestCommand extends ClientCommandBase {
Utils.addChatMessage(EnumChatFormatting.RED + DEV_FAIL_STRINGS[devFailIndex++]);
return;
}
+ if (args.length == 1 && args[0].equalsIgnoreCase("dumpapihistogram")) {
+ synchronized (ApiCache.INSTANCE) {
+ Utils.addChatMessage("§e[NEU] API Request Histogram");
+ Utils.addChatMessage("§e[NEU] §bClass Name§e: §aCached§e/§cNonCached§e/§dTotal");
+ ApiCache.INSTANCE.getHistogramTotalRequests().forEach((className, totalRequests) -> {
+ var nonCachedRequests = ApiCache.INSTANCE.getHistogramNonCachedRequests().getOrDefault(className, 0);
+ var cachedRequests = totalRequests - nonCachedRequests;
+ Utils.addChatMessage(
+ String.format(
+ "§e[NEU] §b%s §a%d§e/§c%d§e/§d%d",
+ className,
+ cachedRequests,
+ nonCachedRequests,
+ totalRequests
+ ));
+ });
+ }
+ }
if (args.length == 1 && args[0].equalsIgnoreCase("testprofile")) {
NotEnoughUpdates.INSTANCE.manager.apiUtils.newHypixelApiRequest("skyblock/profiles")
.queryArgument(
@@ -254,5 +276,17 @@ public class DevTestCommand extends ClientCommandBase {
MiscUtils.copyToClipboard(builder.toString());
Utils.addChatMessage("§e[NEU] Copied tablist to clipboard!");
}
+ if (args.length >= 1 && args[0].equalsIgnoreCase("useragent")) {
+ String newUserAgent = args.length == 1 ? null : String.join(" ", Arrays.copyOfRange(args, 1, args.length));
+ Utils.addChatMessage("§e[NEU] Changed user agent override to: " + newUserAgent);
+ NotEnoughUpdates.INSTANCE.config.hidden.customUserAgent = newUserAgent;
+ }
+ if (args.length == 2 && args[0].equalsIgnoreCase("value")) {
+ try {
+ testValue = Integer.parseInt(args[1]);
+ } catch (NumberFormatException e) {
+ Utils.addChatMessage("NumberFormatException!");
+ }
+ }
}
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/PronounsCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/PronounsCommand.java
index 5a4f1400..cf0d0c56 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/PronounsCommand.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/PronounsCommand.java
@@ -88,7 +88,7 @@ public class PronounsCommand extends ClientCommandBase {
"§e[NEU] Pronouns for §b" + user + " §eon §b" + platform + "§e:"), id);
betterPronounChoice.render().forEach(it -> nc.printChatMessage(new ChatComponentText("§e[NEU] §a" + it)));
return null;
- }, MinecraftExecutor.INSTANCE);
+ }, MinecraftExecutor.OnThread);
}
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigOption.java b/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigOption.java
index 920cb326..ddd1e71f 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigOption.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigOption.java
@@ -30,6 +30,7 @@ public @interface ConfigOption {
String name();
String desc();
+
String[] searchTags() default "";
int subcategoryId() default -1;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/util/ArrowPagesUtils.java b/src/main/java/io/github/moulberry/notenoughupdates/core/util/ArrowPagesUtils.java
index 86430804..1e70db7f 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/util/ArrowPagesUtils.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/util/ArrowPagesUtils.java
@@ -173,7 +173,7 @@ public class ArrowPagesUtils {
BUTTON_WIDTH,
BUTTON_HEIGHT
) &&
- currentPage < totalPages) {
+ currentPage < totalPages - 1) {
int newPage = currentPage + 1;
pageChange.accept(MathHelper.clamp_int(newPage, 0, totalPages - 1));
Utils.playPressSound();
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/CapeManager.java b/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/CapeManager.java
index 4a7c1939..984a7931 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/CapeManager.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/CapeManager.java
@@ -150,7 +150,7 @@ public class CapeManager {
NotEnoughUpdates.INSTANCE.manager.apiUtils
.newMoulberryRequest("activecapes.json")
.requestJson()
- .thenAccept(jsonObject -> {
+ .thenAcceptAsync(jsonObject -> {
if (jsonObject.get("success").getAsBoolean()) {
lastJsonSync = jsonObject;
@@ -171,7 +171,7 @@ public class CapeManager {
NotEnoughUpdates.INSTANCE.manager.apiUtils
.newMoulberryRequest("permscapes.json")
.requestJson()
- .thenAccept(jsonObject -> {
+ .thenAcceptAsync(jsonObject -> {
if (!jsonObject.get("success").getAsBoolean()) return;
permSyncTries = 0;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CookieWarning.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CookieWarning.java
index 80751371..f130a993 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CookieWarning.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CookieWarning.java
@@ -31,9 +31,13 @@ public class CookieWarning {
private static boolean hasNotified;
private static boolean hasErrorMessage;
+ private static long cookieEndTime = 0;
+ private static boolean hasCookie = true;
+ private static long lastChecked = 0;
public static void resetNotification() {
hasNotified = false;
+ hasCookie = true;
NotificationHandler.cancelNotification();
}
@@ -41,96 +45,135 @@ public class CookieWarning {
* Checks the tab list for a cookie timer, and sends a notification if the timer is within the tolerance
*/
public static void checkCookie() {
- if (NotEnoughUpdates.INSTANCE.config.notifications.doBoosterNotif &&
- NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard()) {
- String[] lines;
- try {
- lines = ((AccessorGuiPlayerTabOverlay) Minecraft.getMinecraft().ingameGUI.getTabList())
- .getFooter()
- .getUnformattedText()
- .split("\n");
- } catch (NullPointerException e) {
- return; // if the footer is null or somehow doesn't exist, stop
+ if (!NotEnoughUpdates.INSTANCE.config.notifications.doBoosterNotif ||
+ !NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard()) {
+ return;
+ }
+ String timeLine = getTimeLine();
+ if (!hasCookie) {
+ if (!hasNotified) {
+ NotificationHandler.displayNotification(Lists.newArrayList(
+ "§cBooster Cookie Ran Out!",
+ "§7Your Booster Cookie expired!",
+ "§7",
+ "§7Press X on your keyboard to close this notification"
+ ), true, true);
+ hasNotified = true;
}
- boolean hasCookie = true;
- String timeLine = null; // the line that contains the cookie timer
- for (int i = 0; i < lines.length; i++) {
- if (lines[i].startsWith("Cookie Buff")) {
- timeLine = lines[i + 1]; // the line after the "Cookie Buff" line
- }
- if (lines[i].startsWith("Not active! Obtain booster cookies from the")) {
- hasCookie = false;
- }
+ return;
+ }
+ if (timeLine == null) return;
+
+ int minutes = getMinutesRemaining(timeLine);
+ if (minutes < NotEnoughUpdates.INSTANCE.config.notifications.boosterCookieWarningMins && !hasNotified) {
+ NotificationHandler.displayNotification(Lists.newArrayList(
+ "§cBooster Cookie Running Low!",
+ "§7Your Booster Cookie will expire in " + timeLine,
+ "§7",
+ "§7Press X on your keyboard to close this notification"
+ ), true, true);
+ hasNotified = true;
+ }
+ }
+
+ private static int getMinutesRemaining(String timeLine) {
+ String clean = timeLine.replaceAll("(§.)", "");
+ clean = clean.replaceAll("(\\d)([smhdy])", "$1 $2");
+ String[] digits = clean.split(" ");
+ int minutes = 0;
+ try {
+ for (int i = 0; i < digits.length; i++) {
+ if (i % 2 == 1) continue;
+
+ String number = digits[i];
+ String unit = digits[i + 1];
+ long val = Integer.parseInt(number);
+ switch (unit) {
+ case "Years":
+ case "Year":
+ minutes += val * 525600;
+ break;
+ case "Months":
+ case "Month":
+ minutes += val * 43200;
+ break;
+ case "Days":
+ case "Day":
+ minutes += val * 1440;
+ break;
+ case "Hours":
+ case "Hour":
+ case "h":
+ minutes += val * 60;
+ break;
+ case "Minutes":
+ case "Minute":
+ case "m":
+ minutes += val;
+ break;
+ } // ignore seconds
}
- if (!hasCookie) {
- if (!hasNotified) {
- NotificationHandler.displayNotification(Lists.newArrayList(
- "\u00a7cBooster Cookie Ran Out!",
- "\u00a77Your Booster Cookie expired!",
- "\u00a77",
- "\u00a77Press X on your keyboard to close this notification"
- ), true, true);
- hasNotified = true;
- }
- return;
+ } catch (NumberFormatException e) {
+ if (!hasErrorMessage) {
+ e.printStackTrace();
+ Utils.addChatMessage(EnumChatFormatting.RED +
+ "NEU ran into an issue when retrieving the Booster Cookie Timer. Check the logs for details.");
+ hasErrorMessage = true;
}
- if (timeLine != null) {
- String clean = timeLine.replaceAll("(\u00a7.)", "");
- clean = clean.replaceAll("(\\d)([smhdy])", "$1 $2");
- String[] digits = clean.split(" ");
- int minutes = 0;
- try {
- for (int i = 0; i < digits.length; i++) {
- if (i % 2 == 1) continue;
+ hasNotified = true;
+ }
+ return minutes;
+ }
- String number = digits[i];
- String unit = digits[i + 1];
- long val = Integer.parseInt(number);
- switch (unit) {
- case "Years":
- case "Year":
- minutes += val * 525600;
- break;
- case "Months":
- case "Month":
- minutes += val * 43200;
- break;
- case "Days":
- case "Day":
- minutes += val * 1440;
- break;
- case "Hours":
- case "Hour":
- case "h":
- minutes += val * 60;
- break;
- case "Minutes":
- case "Minute":
- case "m":
- minutes += val;
- break;
- } // ignore seconds
- }
- } catch (NumberFormatException e) {
- if (!hasErrorMessage) {
- e.printStackTrace();
- Utils.addChatMessage(EnumChatFormatting.RED +
- "NEU ran into an issue when retrieving the Booster Cookie Timer. Check the logs for details.");
- hasErrorMessage = true;
- }
- hasNotified = true;
- }
- if (minutes < NotEnoughUpdates.INSTANCE.config.notifications.boosterCookieWarningMins && !hasNotified) {
- NotificationHandler.displayNotification(Lists.newArrayList(
- "\u00a7cBooster Cookie Running Low!",
- "\u00a77Your Booster Cookie will expire in " + timeLine,
- "\u00a77",
- "\u00a77Press X on your keyboard to close this notification"
- ), true, true);
- hasNotified = true;
- }
+ private static String getTimeLine() {
+ String[] lines;
+ try {
+ lines = ((AccessorGuiPlayerTabOverlay) Minecraft.getMinecraft().ingameGUI.getTabList())
+ .getFooter()
+ .getUnformattedText()
+ .split("\n");
+ } catch (NullPointerException ignored) {
+ return null;
+ }
+ String timeLine = null; // the line that contains the cookie timer
+ for (int i = 0; i < lines.length; i++) {
+ if (lines[i].startsWith("Cookie Buff")) {
+ timeLine = lines[i + 1]; // the line after the "Cookie Buff" line
+ }
+ if (lines[i].startsWith("Not active! Obtain booster cookies from the")) {
+ hasCookie = false;
}
}
+ return timeLine;
+ }
+
+ public static boolean hasActiveBoosterCookie() {
+ long cookieEndTime = getCookieEndTime();
+ return cookieEndTime > System.currentTimeMillis();
+ }
+
+ private static long getCookieEndTime() {
+ // Only updating every 10 seconds
+// if (System.currentTimeMillis() > lastChecked + 10_000) return cookieEndTime;
+ if (lastChecked + 3_000 > System.currentTimeMillis()) return cookieEndTime;
+
+ String timeLine = getTimeLine();
+ if (hasCookie && timeLine != null) {
+ int minutes = getMinutesRemaining(timeLine);
+ cookieEndTime = System.currentTimeMillis() + (long) minutes * 60 * 1000;
+ } else {
+ cookieEndTime = 0;
+ }
+
+ lastChecked = System.currentTimeMillis();
+ return cookieEndTime;
+ }
+ public static void onProfileSwitch() {
+ resetNotification();
+ hasErrorMessage = false;
+ cookieEndTime = 0;
+ hasCookie = true;
+ lastChecked = 0;
}
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/ItemCooldowns.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/ItemCooldowns.java
index 5651a6ed..2253ca4a 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/ItemCooldowns.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/ItemCooldowns.java
@@ -182,8 +182,7 @@ public class ItemCooldowns {
@SubscribeEvent
public void onChatMessage(ClientChatReceivedEvent event) {
- if (PICKAXE_ABILITY_ACTIVATION.matcher(event.message.getFormattedText()).matches() &&
- NotEnoughUpdates.INSTANCE.config.itemOverlays.pickaxeAbility && pickaxeCooldown != 0) {
+ if (PICKAXE_ABILITY_ACTIVATION.matcher(event.message.getFormattedText()).matches() && pickaxeCooldown != 0) {
findCooldownInTooltip(Item.PICKAXES);
pickaxeUseCooldownMillisRemaining = pickaxeCooldown * 1000;
}
@@ -260,10 +259,12 @@ public class ItemCooldowns {
}
// Pickaxes
- if (isPickaxe(internalname) && NotEnoughUpdates.INSTANCE.config.itemOverlays.pickaxeAbility) {
+ if (isPickaxe(internalname)) {
findCooldownInTooltip(Item.PICKAXES);
- return durabilityOverride(pickaxeUseCooldownMillisRemaining, pickaxeCooldown, stack);
+ if (NotEnoughUpdates.INSTANCE.config.itemOverlays.pickaxeAbility) {
+ return durabilityOverride(pickaxeUseCooldownMillisRemaining, pickaxeCooldown, stack);
+ } else return -1;
}
// Treecapitator / Jungle Axe
if (internalname.equals("TREECAPITATOR_AXE") || internalname.equals("JUNGLE_AXE")) {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/PetInfoOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/PetInfoOverlay.java
index 716fb37d..ceae782b 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/PetInfoOverlay.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/PetInfoOverlay.java
@@ -473,29 +473,44 @@ public class PetInfoOverlay extends TextOverlay {
}
}
JsonObject pets = Constants.PETS;
- if (pets != null && pets.has("custom_pet_leveling") && pets.get("custom_pet_leveling").getAsJsonObject().has(pet.petType.toUpperCase()) &&
- pets.get("custom_pet_leveling").getAsJsonObject().get(pet.petType.toUpperCase()).getAsJsonObject().has("xp_multiplier")) {
- xp *= pets.get("custom_pet_leveling").getAsJsonObject().get(pet.petType.toUpperCase()).getAsJsonObject().get("xp_multiplier").getAsFloat();
+ if (pets != null && pets.has("custom_pet_leveling") &&
+ pets.get("custom_pet_leveling").getAsJsonObject().has(pet.petType.toUpperCase()) &&
+ pets.get("custom_pet_leveling").getAsJsonObject().get(pet.petType.toUpperCase()).getAsJsonObject().has(
+ "xp_multiplier")) {
+ xp *= pets.get("custom_pet_leveling").getAsJsonObject().get(pet.petType.toUpperCase()).getAsJsonObject().get(
+ "xp_multiplier").getAsFloat();
}
return xp;
}
+ private int firstPetLines = 0;
+ private int secondPetLines = 0;
+
@Override
public void updateFrequent() {
Pet currentPet = getCurrentPet();
if (!NotEnoughUpdates.INSTANCE.config.petOverlay.enablePetInfo || currentPet == null) {
overlayStrings = null;
} else {
+ firstPetLines = 0;
+ secondPetLines = 0;
overlayStrings = new ArrayList<>();
overlayStrings.addAll(createStringsForPet(currentPet, false));
+ firstPetLines = overlayStrings.size();
Pet currentPet2 = getCurrentPet2();
if (currentPet2 != null) {
overlayStrings.add("");
+ if (firstPetLines == 1) {
+ overlayStrings.add("");
+ }
overlayStrings.addAll(createStringsForPet(currentPet2, true));
+ secondPetLines = overlayStrings.size() - firstPetLines - 1;
+ if (firstPetLines == 1) {
+ secondPetLines--;
+ }
}
-
}
}
@@ -519,14 +534,20 @@ public class PetInfoOverlay extends TextOverlay {
currentPet.rarity.chatFormatting +
WordUtils.capitalizeFully(currentPet.petType.replace("_", " "));
- String lvlStringShort = EnumChatFormatting.AQUA + "" + roundFloat(levelXp) + "/" +
- roundFloat(currentPet.petLevel.getExpRequiredForNextLevel())
- + EnumChatFormatting.YELLOW + " (" + getLevelPercent(currentPet) + "%)";
+ float levelPercent = getLevelPercent(currentPet);
+ String lvlStringShort = null;
+ String lvlString = null;
+
+ if (levelPercent != 100 || !NotEnoughUpdates.INSTANCE.config.petOverlay.hidePetLevelProgress) {
+ lvlStringShort = EnumChatFormatting.AQUA + "" + roundFloat(levelXp) + "/" +
+ roundFloat(currentPet.petLevel.getExpRequiredForNextLevel())
+ + EnumChatFormatting.YELLOW + " (" + levelPercent + "%)";
- String lvlString = EnumChatFormatting.AQUA + "" +
- Utils.shortNumberFormat(Math.min(levelXp, currentPet.petLevel.getExpRequiredForNextLevel()), 0) + "/" +
- Utils.shortNumberFormat(currentPet.petLevel.getExpRequiredForNextLevel(), 0)
- + EnumChatFormatting.YELLOW + " (" + getLevelPercent(currentPet) + "%)";
+ lvlString = EnumChatFormatting.AQUA + "" +
+ Utils.shortNumberFormat(Math.min(levelXp, currentPet.petLevel.getExpRequiredForNextLevel()), 0) + "/" +
+ Utils.shortNumberFormat(currentPet.petLevel.getExpRequiredForNextLevel(), 0)
+ + EnumChatFormatting.YELLOW + " (" + levelPercent + "%)";
+ }
float xpGain;
if (!secondPet) {
@@ -593,6 +614,8 @@ public class PetInfoOverlay extends TextOverlay {
String finalEtaMaxStr = etaMaxStr;
String finalXpGainString = xpGainString;
String finalPetItemStr = petItemStr;
+ String finalLvlString = lvlString;
+ String finalLvlStringShort = lvlStringShort;
return new ArrayList<String>() {{
for (int index : NotEnoughUpdates.INSTANCE.config.petOverlay.petOverlayText) {
switch (index) {
@@ -600,10 +623,10 @@ public class PetInfoOverlay extends TextOverlay {
add(petName);
break;
case 1:
- add(lvlStringShort);
+ if (finalLvlStringShort != null) add(finalLvlStringShort);
break;
case 2:
- add(lvlString);
+ if (finalLvlString != null) add(finalLvlString);
break;
case 3:
add(finalXpGainString);
@@ -716,6 +739,10 @@ public class PetInfoOverlay extends TextOverlay {
GlStateManager.enableDepth();
GlStateManager.pushMatrix();
Utils.pushGuiScale(NotEnoughUpdates.INSTANCE.config.locationedit.guiScale);
+
+ if (firstPetLines == 1) y -= 9;
+ if (firstPetLines == 2) y -= 3;
+
GlStateManager.translate(x - 2, y - 2, 0);
GlStateManager.scale(2, 2, 1);
Utils.drawItemStack(stack, 0, 0);
@@ -730,12 +757,16 @@ public class PetInfoOverlay extends TextOverlay {
if (petItem2 != null) {
Vector2f position = getPosition(overlayWidth, overlayHeight, true);
int x = (int) position.x;
- int y = (int) position.y + NotEnoughUpdates.INSTANCE.config.petOverlay.petOverlayText.size() * 10;
+ int y = (int) position.y + (overlayStrings.size() - secondPetLines) * 10;
ItemStack stack = NotEnoughUpdates.INSTANCE.manager.jsonToStack(petItem2);
GlStateManager.enableDepth();
GlStateManager.pushMatrix();
Utils.pushGuiScale(NotEnoughUpdates.INSTANCE.config.locationedit.guiScale);
+
+ if (secondPetLines == 1) y -= 9;
+ if (secondPetLines == 2) y -= 3;
+
GlStateManager.translate(x - 2, y - 2, 0);
GlStateManager.scale(2, 2, 1);
Utils.drawItemStack(stack, 0, 0);
@@ -1114,7 +1145,7 @@ public class PetInfoOverlay extends TextOverlay {
PetInfoOverlay.config.selectedPet = -1;
Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
EnumChatFormatting.RED + "[NEU] Can't find pet \u00a7" + petStringMatch +
- EnumChatFormatting.RED + " try revisiting all pages of /pets."));
+ EnumChatFormatting.RED + " try revisiting all pages of /pets."));
}
}
} else if ((chatMessage.toLowerCase().startsWith("you despawned your")) || (chatMessage.toLowerCase().contains(
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/PowerStoneStatsDisplay.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/PowerStoneStatsDisplay.java
index 31dd71eb..907f0f0d 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/PowerStoneStatsDisplay.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/PowerStoneStatsDisplay.java
@@ -19,10 +19,13 @@
package io.github.moulberry.notenoughupdates.miscfeatures;
+import com.google.gson.JsonObject;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import io.github.moulberry.notenoughupdates.autosubscribe.NEUAutoSubscribe;
import io.github.moulberry.notenoughupdates.core.util.StringUtils;
+import io.github.moulberry.notenoughupdates.events.ProfileDataLoadedEvent;
import io.github.moulberry.notenoughupdates.options.NEUConfig;
+import io.github.moulberry.notenoughupdates.profileviewer.ProfileViewerUtils;
import io.github.moulberry.notenoughupdates.util.ItemUtils;
import io.github.moulberry.notenoughupdates.util.Utils;
import net.minecraft.client.Minecraft;
@@ -54,13 +57,25 @@ public class PowerStoneStatsDisplay {
}
@SubscribeEvent
+ public void onProfileDataLoaded(ProfileDataLoadedEvent event) {
+ JsonObject profileInfo = event.getProfileInfo();
+
+ if (profileInfo == null) return;
+
+ JsonObject inventoryInfo = ProfileViewerUtils.readInventoryInfo(profileInfo, "talisman_bag");
+ if (inventoryInfo == null) return;
+
+ NEUConfig.HiddenProfileSpecific configProfileSpecific = NotEnoughUpdates.INSTANCE.config.getProfileSpecific();
+ if (configProfileSpecific == null) return;
+ int powerAmount = ProfileViewerUtils.getMagicalPower(inventoryInfo, profileInfo);
+ configProfileSpecific.magicalPower = powerAmount;
+ }
+
+ @SubscribeEvent
public void onTick(TickEvent event) {
+ if (!NotEnoughUpdates.INSTANCE.config.tooltipTweaks.powerStoneStats) return;
if (!dirty) return;
-
- if (!Utils.getOpenChestName().equals("SkyBlock Menu")) {
- dirty = false;
- return;
- }
+ if (!Utils.getOpenChestName().equals("Your Bags")) return;
EntityPlayerSP p = Minecraft.getMinecraft().thePlayer;
Container openContainer = p.openContainer;
@@ -70,14 +85,15 @@ public class PowerStoneStatsDisplay {
String displayName = stack.getDisplayName();
if (!"§aAccessory Bag".equals(displayName)) continue;
+ dirty = false;
for (String line : ItemUtils.getLore(stack)) {
if (line.startsWith("§7Magical Power: ")) {
String rawNumber = line.split("§6")[1].replace(",", "");
NEUConfig.HiddenProfileSpecific configProfileSpecific = NotEnoughUpdates.INSTANCE.config.getProfileSpecific();
if (configProfileSpecific == null) return;
- configProfileSpecific.magicalPower = Integer.parseInt(rawNumber);
- dirty = false;
+ int magicalPower = Integer.parseInt(rawNumber);
+ configProfileSpecific.magicalPower = magicalPower;
}
}
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/updater/AutoUpdater.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/updater/AutoUpdater.java
index 54fcc204..f41654e7 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/updater/AutoUpdater.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/updater/AutoUpdater.java
@@ -186,7 +186,7 @@ public class AutoUpdater {
int fullReleaseVersion =
o.has("version_id") && o.get("version_id").isJsonPrimitive() ? o.get("version_id").getAsInt() : -1;
int preReleaseVersion =
- o.has("version_id") && o.get("version_id").isJsonPrimitive() ? o.get("version_id").getAsInt() : -1;
+ o.has("pre_version_id") && o.get("pre_version_id").isJsonPrimitive() ? o.get("pre_version_id").getAsInt() : -1;
int hotfixVersion =
o.has("hotfix_id") && o.get("hotfix_id").isJsonPrimitive() ? o.get("hotfix_id").getAsInt() : -1;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/world/FrozenTreasuresHighlighter.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/world/FrozenTreasuresHighlighter.java
index 2f8071a0..1a541433 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/world/FrozenTreasuresHighlighter.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/world/FrozenTreasuresHighlighter.java
@@ -28,11 +28,14 @@ import net.minecraft.client.Minecraft;
import net.minecraft.entity.Entity;
import net.minecraft.entity.item.EntityArmorStand;
import net.minecraft.init.Blocks;
+import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
+import java.util.ArrayList;
+import java.util.Base64;
import java.util.List;
@NEUAutoSubscribe
@@ -40,6 +43,15 @@ public class FrozenTreasuresHighlighter extends GenericBlockHighlighter {
private static final FrozenTreasuresHighlighter INSTANCE = new FrozenTreasuresHighlighter();
+ private static final List<String> rideablePetTextureUrls = new ArrayList<String>() {{
+ // Armadillo
+ add("http://textures.minecraft.net/texture/c1eb6df4736ae24dd12a3d00f91e6e3aa7ade6bbefb0978afef2f0f92461018f");
+ // Rock
+ add("http://textures.minecraft.net/texture/cb2b5d48e57577563aca31735519cb622219bc058b1f34648b67b8e71bc0fa");
+ // Rat
+ add("http://textures.minecraft.net/texture/a8abb471db0ab78703011979dc8b40798a941f3a4dec3ec61cbeec2af8cffe8");
+ }};
+
public static FrozenTreasuresHighlighter getInstance() {return INSTANCE;}
@Override
@@ -62,10 +74,46 @@ public class FrozenTreasuresHighlighter extends GenericBlockHighlighter {
World w = Minecraft.getMinecraft().theWorld;
if (w == null) return;
List<Entity> entities = w.getLoadedEntityList();
- for (Entity e : entities) {
- if ((e instanceof EntityArmorStand) && ((EntityArmorStand) e).getCurrentArmor(3) != null) highlightedBlocks.add(e
- .getPosition()
- .add(0, 1, 0));
+ for (Entity entity : entities) {
+ if ((entity instanceof EntityArmorStand) &&
+ ((EntityArmorStand) entity).getCurrentArmor(3) != null) {
+
+ // If an armor stand has a 'hat' with a NBTTagCompound check if it has a pet texture url
+ if (((EntityArmorStand) entity).getCurrentArmor(3).hasTagCompound()) {
+ NBTTagCompound nbtTagCompound = ((EntityArmorStand) entity).getCurrentArmor(3).getTagCompound();
+
+ // Get Base64 texture value from the tag compound
+ String textureValue = nbtTagCompound
+ .getCompoundTag("SkullOwner")
+ .getCompoundTag("Properties")
+ .getTagList("textures", 10)
+ .getCompoundTagAt(0)
+ .getString("Value");
+
+ // Decode and find texture url from the texture value
+ String trimmedJson = new String(Base64.getDecoder().decode(textureValue)).replace(" ", "");
+
+
+ String textureUrl = "";
+ if (trimmedJson.contains("url")) {
+ textureUrl = trimmedJson.substring(
+ trimmedJson.indexOf("url")+6, // Start of url
+ trimmedJson.substring( // Get the substring from the start of the url to the end of string
+ trimmedJson.indexOf("url")+6).indexOf("\"") // Get index of first " after start of url
+ + trimmedJson.indexOf("url")+6); // Add on the length of numbers up until the start of url to get correct index from overall string
+ }
+
+
+ // If the list of rideable pet texture urls doesn't include the found texture then it is a frozen treasure
+ if (!rideablePetTextureUrls.contains(textureUrl)) {
+ highlightedBlocks.add(entity.getPosition().add(0, 1, 0));
+ }
+ } else {
+ // This is for frozen treasures which are just blocks i.e. Packed Ice, Enchanted Packed Ice etc.
+ // (Since I don't believe the blocks have NBTTagCompound data)
+ highlightedBlocks.add(entity.getPosition().add(0, 1, 0));
+ }
+ }
}
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/CalendarOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/CalendarOverlay.java
index 48d37f2f..87691631 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/CalendarOverlay.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/CalendarOverlay.java
@@ -298,6 +298,7 @@ public class CalendarOverlay {
boolean changed = false;
for (int i = 0; i < 31; i++) {
ItemStack item = cc.getLowerChestInventory().getStackInSlot(1 + (i % 7) + (i / 7) * 9);
+ if (item == null) continue;
JsonArray array = new JsonArray();
if (item.getTagCompound() != null) {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/minionhelper/loaders/MinionHelperApiLoader.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/minionhelper/loaders/MinionHelperApiLoader.java
index aaa398f4..ecf02236 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/minionhelper/loaders/MinionHelperApiLoader.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/minionhelper/loaders/MinionHelperApiLoader.java
@@ -47,7 +47,6 @@ import java.util.Map;
public class MinionHelperApiLoader {
private final MinionHelperManager manager;
private boolean dirty = true;
- private int ticks = 0;
private boolean collectionApiEnabled = true;
private boolean ignoreWorldSwitches = false;
private boolean readyToUse = false;
@@ -72,11 +71,7 @@ public class MinionHelperApiLoader {
if (Minecraft.getMinecraft().thePlayer == null) return;
if (!NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard()) return;
if (!NotEnoughUpdates.INSTANCE.config.minionHelper.gui) return;
- ticks++;
-
- if (ticks % 20 != 0) return;
-
- if (dirty) {
+ if (dirty && "Crafted Minions".equals(Utils.getOpenChestName())) {
load();
} else {
if (System.currentTimeMillis() > lastLoaded + 60_000 * 3) {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/NEUConfig.java b/src/main/java/io/github/moulberry/notenoughupdates/options/NEUConfig.java
index 302b8927..4020a82a 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/NEUConfig.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/NEUConfig.java
@@ -446,6 +446,8 @@ public class NEUConfig extends Config {
@Expose
public int compareMode = 0;
@Expose
+ public String customUserAgent = null;
+ @Expose
public int sortMode = 0;
@Expose
public ArrayList<Boolean> compareAscending = Lists.newArrayList(true, true, true);
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/customtypes/NEUDebugFlag.java b/src/main/java/io/github/moulberry/notenoughupdates/options/customtypes/NEUDebugFlag.java
index 50f459c0..90ef93bb 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/customtypes/NEUDebugFlag.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/customtypes/NEUDebugFlag.java
@@ -31,6 +31,7 @@ public enum NEUDebugFlag {
WISHING("Wishing Compass Solver"),
MAP("Dungeon Map Player Information"),
SEARCH("SearchString Matches"),
+ API_CACHE("Api Cache"),
;
private final String description;
@@ -43,6 +44,10 @@ public enum NEUDebugFlag {
return description;
}
+ public void log(String message) {
+ NEUDebugLogger.log(this, message);
+ }
+
public boolean isSet() {
return NEUDebugLogger.isFlagEnabled(this);
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Misc.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Misc.java
index 47e51eec..affaa68a 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Misc.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Misc.java
@@ -311,4 +311,13 @@ public class Misc {
@ConfigEditorBoolean
public boolean dungeonGroupsPV = true;
+ @Expose
+ @ConfigOption(
+ name = "Old SkyBlock Menu",
+ desc = "Show old buttons in the SkyBlock Menu: Trade, Accessories, Potions, Quiver, Fishing and Sacks. " +
+ "§cOnly works with the booster cookie effect active."
+ )
+ @ConfigEditorBoolean
+ public boolean oldSkyBlockMenu = false;
+
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/MiscOverlays.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/MiscOverlays.java
index 064a9304..53361a26 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/MiscOverlays.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/MiscOverlays.java
@@ -24,7 +24,6 @@ import io.github.moulberry.notenoughupdates.core.config.Position;
import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigAccordionId;
import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorAccordion;
import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean;
-import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorColour;
import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorDraggableList;
import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorDropdown;
import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
@@ -61,6 +60,15 @@ public class MiscOverlays {
@Expose
@ConfigOption(
+ name = "Todo Overlay Hide Bingo",
+ desc = "Hide some tasks from the todo overlay while on a bingo profile: Cookie Buff, Godpot, Heavy Pearls, Crimson Isle Quests"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 0)
+ public boolean todoOverlayHideAtBingo = true;
+
+ @Expose
+ @ConfigOption(
name = "Todo Text",
desc = "\u00a7eDrag text to change the appearance of the overlay\n" +
"\u00a7rIf you want to see the time until something is available, click \"Add\" and then the respective timer"
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/PetOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/PetOverlay.java
index fce1f9af..9d88e8f1 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/PetOverlay.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/PetOverlay.java
@@ -22,7 +22,6 @@ package io.github.moulberry.notenoughupdates.options.seperateSections;
import com.google.gson.annotations.Expose;
import io.github.moulberry.notenoughupdates.core.config.Position;
import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean;
-import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorButton;
import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorDraggableList;
import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorDropdown;
import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
@@ -131,4 +130,12 @@ public class PetOverlay {
)
@ConfigEditorBoolean
public boolean showKatSitting = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Hide Pet Level Progress",
+ desc = "Hide the pet level progress information for maxed out pets."
+ )
+ @ConfigEditorBoolean
+ public boolean hidePetLevelProgress = false;
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/overlays/TimersOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/overlays/TimersOverlay.java
index 419c9785..90aa2984 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/overlays/TimersOverlay.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/overlays/TimersOverlay.java
@@ -898,12 +898,26 @@ public class TimersOverlay extends TextTabOverlay {
overlayStrings = new ArrayList<>();
for (int index : NotEnoughUpdates.INSTANCE.config.miscOverlays.todoText2) {
if (map.containsKey(index)) {
- overlayStrings.add(map.get(index));
+ String text = map.get(index);
+ if (hideBecauseOfBingo(text)) continue;
+ overlayStrings.add(text);
}
}
if (overlayStrings.isEmpty()) overlayStrings = null;
}
+ private boolean hideBecauseOfBingo(String text) {
+ if (!SBInfo.getInstance().bingo) return false;
+ if (!NotEnoughUpdates.INSTANCE.config.miscOverlays.todoOverlayHideAtBingo) return false;
+
+ if (text.contains("Cookie Buff")) return true;
+ if (text.contains("Godpot")) return true;
+ if (text.contains("Heavy Pearls")) return true;
+ if (text.contains("Crimson Isle Quests")) return true;
+
+ return false;
+ }
+
public static int beforePearls = -1;
public static int afterPearls = -1;
public static int availablePearls = -1;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/BasicPage.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/BasicPage.java
index 8a48dd2c..5939e122 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/BasicPage.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/BasicPage.java
@@ -313,17 +313,25 @@ public class BasicPage extends GuiProfileViewerPage {
} else if (networth == -1) {
networth = profile.getNetWorth(profileId);
}
-
+ int fontWidth = fr.getStringWidth("Net Worth: " + GuiProfileViewer.numberFormat.format(networth));
+ int offset = (fontWidth >= 117 ? 63 + (fontWidth - 117) : 63);
if (networth > 0) {
- Utils.drawStringCentered(
- EnumChatFormatting.GREEN + "Net Worth: " + EnumChatFormatting.GOLD +
- GuiProfileViewer.numberFormat.format(networth),
- fr,
- guiLeft + 165,
- guiTop + 38,
- true,
- 0
- );
+ if (fontWidth >= 117) {
+
+ fr.drawString(EnumChatFormatting.GREEN + "Net Worth: " + EnumChatFormatting.GOLD +
+ GuiProfileViewer.numberFormat.format(networth), guiLeft + 8, guiTop + 38 - fr.FONT_HEIGHT / 2f, 0, true);
+
+ } else {
+ Utils.drawStringCentered(
+ EnumChatFormatting.GREEN + "Net Worth: " + EnumChatFormatting.GOLD +
+ GuiProfileViewer.numberFormat.format(networth),
+ fr,
+ guiLeft + 68,
+ guiTop + 38,
+ true,
+ 0
+ );
+ }
if (NotEnoughUpdates.INSTANCE.manager.auctionManager.getBazaarInfo("BOOSTER_COOKIE") != null &&
NotEnoughUpdates.INSTANCE.manager.auctionManager.getBazaarInfo("BOOSTER_COOKIE").has("avg_buy")) {
double networthInCookies =
@@ -337,8 +345,8 @@ public class BasicPage extends GuiProfileViewerPage {
String networthIRLMoney = GuiProfileViewer.numberFormat.format(Math.round(
((networthInCookies * 325) / 675) * 4.99));
- int fontWidth = fr.getStringWidth("Net Worth: " + GuiProfileViewer.numberFormat.format(networth));
- if (mouseX > guiLeft + 165 - fontWidth / 2 && mouseX < guiLeft + 165 + fontWidth / 2) {
+
+ if (mouseX > guiLeft + offset - fontWidth / 2 && mouseX < guiLeft + offset + fontWidth / 2) {
if (mouseY > guiTop + 32 && mouseY < guiTop + 38 + fr.FONT_HEIGHT) {
getInstance().tooltipToDisplay = new ArrayList<>();
getInstance()
@@ -384,14 +392,21 @@ public class BasicPage extends GuiProfileViewerPage {
}
}
} else {
- Utils.drawStringCentered(
- EnumChatFormatting.GREEN + "Net Worth: " + stateStr,
- fr,
- guiLeft + 165,
- guiTop + 38,
- true,
- 0
- );
+ int errFontWidth = fr.getStringWidth("Net Worth: " + stateStr);
+ if (errFontWidth >= 117) {
+ fr.drawString(EnumChatFormatting.GREEN + "Net Worth: " + stateStr,
+ guiLeft + 8, guiTop + 38 - fr.FONT_HEIGHT / 2f, 0, true
+ );
+ } else {
+ Utils.drawStringCentered(
+ EnumChatFormatting.GREEN + "Net Worth: " + stateStr,
+ fr,
+ guiLeft + 63,
+ guiTop + 38,
+ true,
+ 0
+ );
+ }
}
if (status != null) {
@@ -572,7 +587,7 @@ public class BasicPage extends GuiProfileViewerPage {
);
}
- // sb lvlL
+ // sb lvl
int sbLevelX = guiLeft + 162;
int sbLevelY = guiTop + 90;
@@ -585,8 +600,8 @@ public class BasicPage extends GuiProfileViewerPage {
GlStateManager.scale(1.5f, 1.5f, 1);
Utils.drawItemStack(skull, 0, 0);
GlStateManager.popMatrix();
- Utils.drawStringScaled(skyblockLevelColour.toString() + (int) skyblockLevel, fr,
- sbLevelX - 2, sbLevelY - 15, true, 0, 1.5f
+ Utils.drawStringCenteredScaled(skyblockLevelColour.toString() + (int) skyblockLevel, fr,
+ sbLevelX + 9, sbLevelY - 12, true, 1.5f
);
float progress = (float) (skyblockLevel - (long) skyblockLevel);
@@ -596,6 +611,12 @@ public class BasicPage extends GuiProfileViewerPage {
sbLevelX - 30, sbLevelY + 20, true, 0, 0.9f
);
+ if (mouseX >= guiLeft + 128 && mouseX <= guiLeft + 216) {
+ if (mouseY >= guiTop + 69 && mouseY <= guiTop + 131) {
+ if (Mouse.isButtonDown(0)) onSecondPage = true;
+ }
+ }
+
if (skyblockInfo != null) {
int position = 0;
for (Map.Entry<String, ItemStack> entry : ProfileViewer.getSkillToSkillDisplayMap().entrySet()) {
@@ -623,12 +644,6 @@ public class BasicPage extends GuiProfileViewerPage {
getInstance().renderBar(x, y + 6, 80, level.level % 1);
}
- if (mouseX >= guiLeft + 128 && mouseX <= guiLeft + 216) {
- if (mouseY >= guiTop + 69 && mouseY <= guiTop + 131) {
- if (Mouse.isButtonDown(0)) onSecondPage = true;
- }
- }
-
if (mouseX > x && mouseX < x + 80) {
if (mouseY > y - 4 && mouseY < y + 13) {
getInstance().tooltipToDisplay = new ArrayList<>();
@@ -794,7 +809,7 @@ public class BasicPage extends GuiProfileViewerPage {
EnumChatFormatting.GOLD +
GuiProfileViewer.numberFormat.format(roundToNearestInt(senitherWeight.getTotalWeight().getRaw())),
fr,
- guiLeft + 165,
+ guiLeft + 63,
guiTop + 18,
true,
0
@@ -804,7 +819,7 @@ public class BasicPage extends GuiProfileViewerPage {
"Senither Weight: " +
GuiProfileViewer.numberFormat.format(roundToNearestInt(senitherWeight.getTotalWeight().getRaw()))
);
- if (mouseX > guiLeft + 165 - textWidth / 2 && mouseX < guiLeft + 165 + textWidth / 2) {
+ if (mouseX > guiLeft + 63 - textWidth / 2 && mouseX < guiLeft + 63 + textWidth / 2) {
if (mouseY > guiTop + 12 && mouseY < guiTop + 12 + fr.FONT_HEIGHT) {
getInstance().tooltipToDisplay = new ArrayList<>();
getInstance()
@@ -862,7 +877,7 @@ public class BasicPage extends GuiProfileViewerPage {
EnumChatFormatting.GOLD +
GuiProfileViewer.numberFormat.format(roundToNearestInt(lilyWeight.getTotalWeight().getRaw())),
fr,
- guiLeft + 165,
+ guiLeft + 63,
guiTop + 28,
true,
0
@@ -871,7 +886,7 @@ public class BasicPage extends GuiProfileViewerPage {
int fontWidth = fr.getStringWidth(
"Lily Weight: " + GuiProfileViewer.numberFormat.format(roundToNearestInt(lilyWeight.getTotalWeight().getRaw()))
);
- if (mouseX > guiLeft + 165 - fontWidth / 2 && mouseX < guiLeft + 165 + fontWidth / 2) {
+ if (mouseX > guiLeft + 63 - fontWidth / 2 && mouseX < guiLeft + 63 + fontWidth / 2) {
if (mouseY > guiTop + 22 && mouseY < guiTop + 22 + fr.FONT_HEIGHT) {
getInstance().tooltipToDisplay = new ArrayList<>();
getInstance()
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ProfileViewer.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ProfileViewer.java
index 610e4090..6f8427ae 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ProfileViewer.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ProfileViewer.java
@@ -28,7 +28,6 @@ import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import io.github.moulberry.notenoughupdates.profileviewer.bestiary.BestiaryData;
import io.github.moulberry.notenoughupdates.profileviewer.weight.senither.SenitherWeight;
import io.github.moulberry.notenoughupdates.util.Constants;
-import io.github.moulberry.notenoughupdates.util.JsonUtils;
import io.github.moulberry.notenoughupdates.util.Utils;
import io.github.moulberry.notenoughupdates.util.hypixelapi.ProfileCollectionInfo;
import net.minecraft.init.Blocks;
@@ -36,7 +35,6 @@ import net.minecraft.init.Items;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompressedStreamTools;
-import net.minecraft.nbt.JsonToNBT;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.util.EnumChatFormatting;
@@ -44,25 +42,21 @@ import net.minecraft.util.EnumChatFormatting;
import javax.annotation.Nullable;
import java.io.ByteArrayInputStream;
import java.io.IOException;
-import java.util.AbstractMap;
+import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import java.util.regex.Pattern;
-import java.util.stream.Collectors;
public class ProfileViewer {
@@ -544,6 +538,7 @@ public class ProfileViewer {
manager.apiUtils
.newHypixelApiRequest("player")
.queryArgument("name", nameF)
+ .maxCacheAge(Duration.ofSeconds(30))
.requestJson()
.thenAccept(jsonObject -> {
if (
@@ -703,98 +698,7 @@ public class ProfileViewer {
return -1;
}
- Map<String, Integer> accessories = JsonUtils.getJsonArrayAsStream(inventoryInfo
- .get("talisman_bag")
- .getAsJsonArray()).map(o -> {
- try {
- return JsonToNBT.getTagFromJson(o
- .getAsJsonObject()
- .get("nbttag")
- .getAsString());
- } catch (Exception ignored) {
- return null;
- }
- }).filter(Objects::nonNull).map(tag -> {
- NBTTagList loreTagList = tag.getCompoundTag("display").getTagList("Lore", 8);
- String lastElement = loreTagList.getStringTagAt(loreTagList.tagCount() - 1);
- if (lastElement.contains(EnumChatFormatting.OBFUSCATED.toString())) {
- lastElement = lastElement.substring(lastElement.indexOf(' ')).trim().substring(4);
- }
- JsonArray lastElementJsonArray = new JsonArray();
- lastElementJsonArray.add(new JsonPrimitive(lastElement));
- return new AbstractMap.SimpleEntry<>(
- tag.getCompoundTag("ExtraAttributes").getString("id"),
- Utils.getRarityFromLore(lastElementJsonArray)
- );
- }).sorted(Comparator.comparingInt(e -> -e.getValue())).collect(Collectors.toMap(
- Map.Entry::getKey,
- Map.Entry::getValue,
- (v1, v2) -> v1,
- LinkedHashMap::new
- ));
-
- Set<String> ignoredTalismans = new HashSet<>();
- int powerAmount = 0;
- for (Map.Entry<String, Integer> entry : accessories.entrySet()) {
- if (ignoredTalismans.contains(entry.getKey())) {
- continue;
- }
-
- JsonArray children = Utils
- .getElementOrDefault(Constants.PARENTS, entry.getKey(), new JsonArray())
- .getAsJsonArray();
- for (JsonElement child : children) {
- ignoredTalismans.add(child.getAsString());
- }
-
- if (entry.getKey().equals("HEGEMONY_ARTIFACT")) {
- switch (entry.getValue()) {
- case 4:
- powerAmount += 16;
- break;
- case 5:
- powerAmount += 22;
- break;
- }
- }
- if (entry.getKey().equals("ABICASE")) {
- if (profileInfo != null && profileInfo.has("nether_island_player_data") &&
- profileInfo.get("nether_island_player_data").getAsJsonObject().has("abiphone") && profileInfo
- .get(
- "nether_island_player_data")
- .getAsJsonObject()
- .get("abiphone")
- .getAsJsonObject()
- .has("active_contacts")) { // BatChest
- int contact =
- profileInfo.get("nether_island_player_data").getAsJsonObject().get("abiphone").getAsJsonObject().get(
- "active_contacts").getAsJsonArray().size();
- powerAmount += Math.floor(contact / 2);
- }
- }
- switch (entry.getValue()) {
- case 0:
- case 6:
- powerAmount += 3;
- break;
- case 1:
- case 7:
- powerAmount += 5;
- break;
- case 2:
- powerAmount += 8;
- break;
- case 3:
- powerAmount += 12;
- break;
- case 4:
- powerAmount += 16;
- break;
- case 5:
- powerAmount += 22;
- break;
- }
- }
+ int powerAmount = ProfileViewerUtils.getMagicalPower(inventoryInfo, profileInfo);
magicalPower.put(profileId, powerAmount);
return powerAmount;
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ProfileViewerUtils.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ProfileViewerUtils.java
new file mode 100644
index 00000000..66164688
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ProfileViewerUtils.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2023 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.profileviewer;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonPrimitive;
+import io.github.moulberry.notenoughupdates.NEUManager;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.util.Constants;
+import io.github.moulberry.notenoughupdates.util.JsonUtils;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.nbt.CompressedStreamTools;
+import net.minecraft.nbt.JsonToNBT;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.nbt.NBTTagList;
+import net.minecraft.util.EnumChatFormatting;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.AbstractMap;
+import java.util.Base64;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+public class ProfileViewerUtils {
+
+ public static JsonObject readInventoryInfo(JsonObject profileInfo, String bagName) {
+ JsonObject inventoryInfo = new JsonObject();
+ JsonElement element = Utils.getElement(profileInfo, bagName + ".data");
+
+ String bytes = Utils.getElementAsString(element, "Hz8IAAAAAAAAAD9iYD9kYD9kAAMAPwI/Gw0AAAA=");
+ NBTTagCompound inv_contents_nbt;
+ try {
+ inv_contents_nbt = CompressedStreamTools.readCompressed(
+ new ByteArrayInputStream(Base64.getDecoder().decode(bytes))
+ );
+ } catch (IOException e) {
+ e.printStackTrace();
+ return null;
+ }
+ NBTTagList items = inv_contents_nbt.getTagList("i", 10);
+ JsonArray contents = new JsonArray();
+ NEUManager manager = NotEnoughUpdates.INSTANCE.manager;
+ for (int j = 0; j < items.tagCount(); j++) {
+ JsonObject item = manager.getJsonFromNBTEntry(items.getCompoundTagAt(j));
+ contents.add(item);
+ }
+
+ inventoryInfo.add(bagName, contents);
+ return inventoryInfo;
+ }
+
+ public static int getMagicalPower(JsonObject inventoryInfo, JsonObject profileInfo) {
+ JsonArray talismanBag = inventoryInfo.get("talisman_bag").getAsJsonArray();
+ Map<String, Integer> accessories = JsonUtils.getJsonArrayAsStream(talismanBag).map(o -> {
+ try {
+ return JsonToNBT.getTagFromJson(o.getAsJsonObject().get("nbttag").getAsString());
+ } catch (Exception ignored) {
+ return null;
+ }
+ }).filter(Objects::nonNull).map(tag -> {
+ NBTTagList loreTagList = tag.getCompoundTag("display").getTagList("Lore", 8);
+ String lastElement = loreTagList.getStringTagAt(loreTagList.tagCount() - 1);
+ if (lastElement.contains(EnumChatFormatting.OBFUSCATED.toString())) {
+ lastElement = lastElement.substring(lastElement.indexOf(' ')).trim().substring(4);
+ }
+ JsonArray lastElementJsonArray = new JsonArray();
+ lastElementJsonArray.add(new JsonPrimitive(lastElement));
+ return new AbstractMap.SimpleEntry<>(tag.getCompoundTag("ExtraAttributes").getString("id"),
+ Utils.getRarityFromLore(lastElementJsonArray)
+ );
+ }).sorted(Comparator.comparingInt(e -> -e.getValue())).collect(Collectors.toMap(
+ Map.Entry::getKey, Map.Entry::getValue, (v1, v2) -> v1, LinkedHashMap::new
+ ));
+
+ Set<String> ignoredTalismans = new HashSet<>();
+ int powerAmount = 0;
+ for (Map.Entry<String, Integer> entry : accessories.entrySet()) {
+ if (ignoredTalismans.contains(entry.getKey())) continue;
+
+ JsonArray children = Utils
+ .getElementOrDefault(Constants.PARENTS, entry.getKey(), new JsonArray())
+ .getAsJsonArray();
+ for (JsonElement child : children) {
+ ignoredTalismans.add(child.getAsString());
+ }
+
+ if (entry.getKey().equals("HEGEMONY_ARTIFACT")) {
+ switch (entry.getValue()) {
+ case 4:
+ powerAmount += 16;
+ break;
+ case 5:
+ powerAmount += 22;
+ break;
+ }
+ }
+ if (entry.getKey().equals("ABICASE")) {
+ if (profileInfo != null && profileInfo.has("nether_island_player_data")) {
+ JsonObject data = profileInfo.get("nether_island_player_data").getAsJsonObject();
+ if (data.has("abiphone") && data.get("abiphone").getAsJsonObject().has("active_contacts")) { // BatChest
+ int contact = data.get("abiphone").getAsJsonObject().get("active_contacts").getAsJsonArray().size();
+ powerAmount += Math.floor(contact / 2);
+ }
+ }
+ }
+ switch (entry.getValue()) {
+ case 0:
+ case 6:
+ powerAmount += 3;
+ break;
+ case 1:
+ case 7:
+ powerAmount += 5;
+ break;
+ case 2:
+ powerAmount += 8;
+ break;
+ case 3:
+ powerAmount += 12;
+ break;
+ case 4:
+ powerAmount += 16;
+ break;
+ case 5:
+ powerAmount += 22;
+ break;
+ }
+ }
+ return powerAmount;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/LevelPage.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/LevelPage.java
index 16abf251..770b295a 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/LevelPage.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/LevelPage.java
@@ -26,6 +26,7 @@ import io.github.moulberry.notenoughupdates.profileviewer.ProfileViewer;
import io.github.moulberry.notenoughupdates.profileviewer.level.task.CoreTaskLevel;
import io.github.moulberry.notenoughupdates.profileviewer.level.task.DungeonTaskLevel;
import io.github.moulberry.notenoughupdates.profileviewer.level.task.EssenceTaskLevel;
+import io.github.moulberry.notenoughupdates.profileviewer.level.task.EventTaskLevel;
import io.github.moulberry.notenoughupdates.profileviewer.level.task.MiscTaskLevel;
import io.github.moulberry.notenoughupdates.profileviewer.level.task.SkillRelatedTaskLevel;
import io.github.moulberry.notenoughupdates.profileviewer.level.task.SlayingTaskLevel;
@@ -61,6 +62,8 @@ public class LevelPage {
private final SlayingTaskLevel slayingTaskLevel;
private final StoryTaskLevel storyTaskLevel;
+ private final EventTaskLevel eventTaskLevel;
+
private static final ResourceLocation pv_levels = new ResourceLocation("notenoughupdates:pv_levels.png");
public LevelPage(GuiProfileViewer instance, BasicPage basicPage) {
@@ -75,6 +78,7 @@ public class LevelPage {
skillRelatedTaskLevel = new SkillRelatedTaskLevel(this);
slayingTaskLevel = new SlayingTaskLevel(this);
storyTaskLevel = new StoryTaskLevel(this);
+ eventTaskLevel = new EventTaskLevel(this);
}
public void drawPage(int mouseX, int mouseY) {
@@ -97,13 +101,14 @@ public class LevelPage {
JsonObject profileInfo = profile.getProfileInformation(profileId);
drawMainBar(skyblockLevel, mouseX, mouseY, guiLeft, guiTop);
- coreTaskLevel.drawTask(profileInfo, mouseX, mouseY, guiLeft, guiTop);
dungeonTaskLevel.drawTask(profileInfo, mouseX, mouseY, guiLeft, guiTop);
essenceTaskLevel.drawTask(profileInfo, mouseX, mouseY, guiLeft, guiTop);
miscTaskLevel.drawTask(profileInfo, mouseX, mouseY, guiLeft, guiTop);
skillRelatedTaskLevel.drawTask(profileInfo, mouseX, mouseY, guiLeft, guiTop);
slayingTaskLevel.drawTask(profileInfo, mouseX, mouseY, guiLeft, guiTop);
storyTaskLevel.drawTask(profileInfo, mouseX, mouseY, guiLeft, guiTop);
+ eventTaskLevel.drawTask(profileInfo, mouseX, mouseY, guiLeft, guiTop);
+ coreTaskLevel.drawTask(profileInfo, mouseX, mouseY, guiLeft, guiTop);
}
public void renderLevelBar(
@@ -175,14 +180,12 @@ public class LevelPage {
renderLevelBar(
"Level",
BasicPage.skull,
- guiLeft + 163,
- guiTop + 30,
+ guiLeft + 163, guiTop + 30,
110,
skyblockLevel,
- (skyblockLevel - (long) skyblockLevel) * 100,
+ Math.round((skyblockLevel - (long) skyblockLevel) * 100),
100,
- mouseX,
- mouseY,
+ mouseX, mouseY,
false,
Collections.emptyList()
);
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/CoreTaskLevel.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/CoreTaskLevel.java
index be333359..8bb26b09 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/CoreTaskLevel.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/CoreTaskLevel.java
@@ -19,8 +19,9 @@
package io.github.moulberry.notenoughupdates.profileviewer.level.task;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
-import io.github.moulberry.notenoughupdates.profileviewer.PlayerStats;
import io.github.moulberry.notenoughupdates.profileviewer.ProfileViewer;
import io.github.moulberry.notenoughupdates.profileviewer.level.LevelPage;
import io.github.moulberry.notenoughupdates.util.Constants;
@@ -80,11 +81,20 @@ public class CoreTaskLevel {
}
// mp acc
- int sbXpGainedMp = levelPage.getProfile().getMagicalPower(levelPage.getProfileId());
+ int sbXpGainedMp = 0;
+ if (object.has("accessory_bag_storage") &&
+ object.getAsJsonObject("accessory_bag_storage").has("highest_magical_power")) {
+ sbXpGainedMp = object.getAsJsonObject("accessory_bag_storage").get("highest_magical_power").getAsInt();
+ }
// pets
- int petScore = PlayerStats.getPetScore(object);
+ int petScore = 0;
+ if (object.has("leveling") &&
+ object.getAsJsonObject("leveling").has("highest_pet_score")) {
+ petScore = object.getAsJsonObject("leveling").get("highest_pet_score").getAsInt();
+
+ }
int sbXpPetScore = petScore * coreTask.get("pet_score_xp").getAsInt();
// museum is not possible
@@ -116,13 +126,32 @@ public class CoreTaskLevel {
}
}
}
+
+ int sbXpBankUpgrades = 0;
+
+ JsonArray completedTasks = object.getAsJsonObject("leveling").get("completed_tasks").getAsJsonArray();
+ JsonObject bankUpgradesXp = coreTask.getAsJsonObject("bank_upgrades_xp");
+ for (JsonElement completedTask : completedTasks) {
+ String name = completedTask.getAsString();
+ if (bankUpgradesXp.has(name)) {
+ sbXpBankUpgrades += bankUpgradesXp.get(name).getAsInt();
+ }
+ }
+
List<String> lore = new ArrayList<>();
lore.add(levelPage.buildLore("Skill Level Up",
sbXpGainedSkillLVL, coreTask.get("skill_level_up").getAsInt(), false
));
- lore.add(levelPage.buildLore("Museum Progression",
- 0, 0, false
+
+ int totalXp = sbXpGainedSkillLVL + sbXpGainedFairy +
+ sbXpCollection + sbXpMinionTier + sbXpBankUpgrades;
+
+ lore.add(levelPage.buildLore(
+ "Museum Progression",
+ 0,
+ 0,
+ false
));
lore.add(levelPage.buildLore(
"Fairy Soul",
@@ -141,21 +170,18 @@ public class CoreTaskLevel {
sbXpMinionTier, coreTask.get("craft_minions").getAsInt(), false
));
lore.add(levelPage.buildLore("Bank Upgrade",
- 0, 0, false
+ sbXpBankUpgrades, coreTask.get("bank_upgrades").getAsInt(), false
));
levelPage.renderLevelBar(
"Core Task",
new ItemStack(Items.nether_star),
- guiLeft + 23,
- guiTop + 25,
+ guiLeft + 23, guiTop + 25,
110,
0,
- sbXpGainedSkillLVL + sbXpGainedFairy +
- sbXpCollection + sbXpMinionTier,
+ totalXp,
levelPage.getConstant().getAsJsonObject("category_xp").get("core_task").getAsInt(),
- mouseX,
- mouseY,
+ mouseX, mouseY,
true,
lore
);
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/DungeonTaskLevel.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/DungeonTaskLevel.java
index 157c8362..6900cdf3 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/DungeonTaskLevel.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/DungeonTaskLevel.java
@@ -44,9 +44,9 @@ public class DungeonTaskLevel {
Map<String, ProfileViewer.Level> skyblockInfo =
levelPage.getProfile().getSkyblockInfo(levelPage.getProfileId());
- double sbLevelGainedFloor = 0;
- double sbXpGainedClass = 0;
- double sbXpGainedLvl = 0;
+ int sbLevelGainedFloor = 0;
+ int sbXpGainedClass = 0;
+ int sbXpGainedLvl = 0;
int catacombsLvl = 0;
if (skyblockInfo != null && skyblockInfo.containsKey("catacombs")) {
ProfileViewer.Level catacombs = skyblockInfo.get("catacombs");
@@ -105,20 +105,20 @@ public class DungeonTaskLevel {
lore.add(levelPage.buildLore("Class Level Up", sbXpGainedClass, classLevelUp, false));
lore.add(levelPage.buildLore("Complete Dungeons", sbLevelGainedFloor, completeDungeon, false));
+ int totalSbXpGain = sbXpGainedLvl + sbXpGainedClass + sbLevelGainedFloor;
+
levelPage.renderLevelBar(
- "Dungeon",
+ "Dungeon Task",
NotEnoughUpdates.INSTANCE.manager
.createItemResolutionQuery()
.withKnownInternalName("WITHER_RELIC")
.resolveToItemStack(),
- guiLeft + 23,
- guiTop + 55,
+ guiLeft + 23, guiTop + 55,
110,
catacombsLvl,
totalXp,
totalGainful,
- mouseX,
- mouseY,
+ mouseX, mouseY,
true,
lore
);
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/EssenceTaskLevel.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/EssenceTaskLevel.java
index d64f54c1..c6df6fc1 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/EssenceTaskLevel.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/EssenceTaskLevel.java
@@ -25,6 +25,7 @@ import com.google.gson.JsonObject;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import io.github.moulberry.notenoughupdates.profileviewer.level.LevelPage;
import io.github.moulberry.notenoughupdates.util.Constants;
+import io.github.moulberry.notenoughupdates.util.Utils;
import net.minecraft.util.EnumChatFormatting;
import java.util.ArrayList;
@@ -88,13 +89,20 @@ public class EssenceTaskLevel {
for (Map.Entry<String, EssenceShop> stringEssenceShopEntry : loreMap.entrySet()) {
String key = stringEssenceShopEntry.getKey();
EssenceShop value = stringEssenceShopEntry.getValue();
- value.name = NotEnoughUpdates.INSTANCE.manager
+ JsonObject jsonObject = NotEnoughUpdates.INSTANCE.manager
.createItemResolutionQuery()
.withKnownInternalName(key)
- .resolveToItemListJson()
+ .resolveToItemListJson();
+ if (jsonObject == null){
+ Utils.showOutdatedRepoNotification();
+ continue;
+ }
+ value.name = jsonObject
.get("displayname")
.getAsString();
- value.max = essenceShopTask.get(key.toLowerCase() + "_shop").getAsInt();
+ String name = key.toLowerCase() + "_shop";
+ if (!essenceShopTask.has(name)) continue;
+ value.max = essenceShopTask.get(name).getAsInt();
lore.add(levelPage.buildLore(
EnumChatFormatting.getTextWithoutFormattingCodes(value.name),
value.current,
@@ -109,14 +117,12 @@ public class EssenceTaskLevel {
NotEnoughUpdates.INSTANCE.manager.createItemResolutionQuery()
.withKnownInternalName("ESSENCE_WITHER")
.resolveToItemStack(),
- guiLeft + 299,
- guiTop + 25,
+ guiLeft + 299, guiTop + 25,
110,
total,
total,
categoryXp.get("essence_shop_task").getAsInt(),
- mouseX,
- mouseY,
+ mouseX, mouseY,
true,
lore
);
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/EventTaskLevel.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/EventTaskLevel.java
new file mode 100644
index 00000000..04ace872
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/EventTaskLevel.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2023 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.profileviewer.level.task;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import io.github.moulberry.notenoughupdates.profileviewer.level.LevelPage;
+import net.minecraft.init.Items;
+import net.minecraft.item.ItemStack;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class EventTaskLevel {
+
+ private final LevelPage levelPage;
+
+ public EventTaskLevel(LevelPage levelPage) {this.levelPage = levelPage;}
+
+ public void drawTask(JsonObject object, int mouseX, int mouseY, int guiLeft, int guiTop) {
+ List<String> lore = new ArrayList<>();
+
+ int sbXpMiningFiesta = 0;
+ int sbXpFishingFestival = 0;
+ int sbXpSpookyFestival = 0;
+ JsonObject constant = levelPage.getConstant();
+ JsonObject eventTask = constant.getAsJsonObject("event_task");
+
+ if (object.has("leveling")) {
+ JsonObject leveling = object.getAsJsonObject("leveling");
+ int miningFiestaOresMined = 0;
+ int fishingFestivalSharksKilled = 0;
+ if (leveling.has("mining_fiesta_ores_mined"))
+ miningFiestaOresMined = leveling.get("mining_fiesta_ores_mined").getAsInt();
+ if (leveling.has("fishing_festival_sharks_killed")) fishingFestivalSharksKilled = leveling.get(
+ "fishing_festival_sharks_killed").getAsInt();
+
+ sbXpMiningFiesta = getCapOrAmount(miningFiestaOresMined, 1_000_000, 5_000);
+ sbXpFishingFestival = getCapOrAmount(fishingFestivalSharksKilled, 5_000, 50);
+
+ JsonArray completedTasks = leveling.get("completed_tasks").getAsJsonArray();
+ JsonObject spookyFestivalXp = eventTask.getAsJsonObject("spooky_festival_xp");
+ for (JsonElement completedTask : completedTasks) {
+ String name = completedTask.getAsString();
+ if (spookyFestivalXp.has(name)) {
+ sbXpSpookyFestival += spookyFestivalXp.get(name).getAsInt();
+ }
+ }
+ }
+
+ lore.add(levelPage.buildLore("Mining Fiesta", sbXpMiningFiesta, eventTask.get("mining_fiesta").getAsInt(), false));
+ lore.add(levelPage.buildLore(
+ "Fishing Festival",
+ sbXpFishingFestival,
+ eventTask.get("fishing_festival").getAsInt(),
+ false
+ ));
+ lore.add(levelPage.buildLore(
+ "Spooky Festival",
+ sbXpSpookyFestival,
+ eventTask.get("spooky_festival").getAsInt(),
+ false
+ ));
+
+ int totalXp = sbXpMiningFiesta + sbXpSpookyFestival +
+ sbXpFishingFestival;
+ levelPage.renderLevelBar(
+ "Event Task",
+ new ItemStack(Items.clock),
+ guiLeft + 299, guiTop + 115,
+ 110,
+ 0,
+ totalXp,
+ levelPage.getConstant().getAsJsonObject("category_xp").get("event_task").getAsInt(),
+ mouseX, mouseY,
+ true,
+ lore
+ );
+ }
+
+ private int getCapOrAmount(int miningFiestaOresMined, int cap, int per) {
+ if (miningFiestaOresMined == 0) return 0;
+ if (miningFiestaOresMined > cap) {
+ return cap / per;
+ }
+ return miningFiestaOresMined / per;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/MiscTaskLevel.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/MiscTaskLevel.java
index a717664d..8b7b9d2b 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/MiscTaskLevel.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/MiscTaskLevel.java
@@ -27,12 +27,13 @@ import io.github.moulberry.notenoughupdates.profileviewer.level.LevelPage;
import io.github.moulberry.notenoughupdates.util.Utils;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
-import net.minecraft.util.EnumChatFormatting;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
public class MiscTaskLevel {
@@ -86,24 +87,27 @@ public class MiscTaskLevel {
}
// abiphone
- if (netherIslandPlayerData.has("abiphone")) {
- JsonObject abiphone = netherIslandPlayerData.getAsJsonObject("abiphone");
- if (abiphone.has("active_contacts")) sbXpAbiphone =
- abiphone.getAsJsonArray("active_contacts").size() * miscellaneousTask.get("abiphone_contacts_xp").getAsInt();
+ JsonObject leveling = object.getAsJsonObject("leveling");
+ JsonArray completedTask = leveling.get("completed_tasks").getAsJsonArray();
+ Stream<JsonElement> stream = StreamSupport.stream(completedTask.spliterator(), true);
+ long activeContacts = stream.map(JsonElement::getAsString).filter(s -> s.startsWith("ABIPHONE_")).count();
+ JsonObject abiphone = netherIslandPlayerData.getAsJsonObject("abiphone");
+ if (abiphone.has("active_contacts")) {
+ sbXpAbiphone = (int) activeContacts * miscellaneousTask.get("abiphone_contacts_xp").getAsInt();
}
}
// harp
int sbXpGainedHarp = 0;
JsonObject harpSongsNames = miscellaneousTask.get("harp_songs_names").getAsJsonObject();
- if (object.has("harp_quest")) {
- JsonObject harpQuest = object.get("harp_quest").getAsJsonObject();
- for (Map.Entry<String, JsonElement> stringJsonElementEntry : harpSongsNames.entrySet()) {
- String key = stringJsonElementEntry.getKey();
- int value = stringJsonElementEntry.getValue().getAsInt();
- if (harpQuest.has(key)) {
- sbXpGainedHarp += value;
- }
+
+ JsonObject leveling = object.get("leveling").getAsJsonObject();
+ if (leveling.has("completed_tasks")) {
+ JsonArray completedTasks = leveling.get("completed_tasks").getAsJsonArray();
+ for (JsonElement completedTask : completedTasks) {
+ String name = completedTask.getAsString();
+ String harpName = name.substring(0, name.lastIndexOf("_"));
+ if(harpSongsNames.has(harpName))sbXpGainedHarp += harpSongsNames.get(harpName).getAsInt() / 4;
}
}
@@ -116,17 +120,18 @@ public class MiscTaskLevel {
JsonObject communityShopUpgradesMax = miscellaneousTask.getAsJsonObject("community_shop_upgrades_max");
int communityShopUpgradesXp = miscellaneousTask.get("community_shop_upgrades_xp").getAsInt();
-
- for (
- JsonElement upgradeState : upgradeStates) {
- if (!upgradeState.isJsonObject()) continue;
- JsonObject value = upgradeState.getAsJsonObject();
- String upgrade = value.get("upgrade").getAsString();
- int tier = value.get("tier").getAsInt();
- if (communityShopUpgradesMax.has(upgrade)) {
- int max = communityShopUpgradesMax.get(upgrade).getAsInt();
- if (max >= tier) {
- sbXpCommunityUpgrade += communityShopUpgradesXp;
+ if (upgradeStates != null) {
+ for (
+ JsonElement upgradeState : upgradeStates) {
+ if (!upgradeState.isJsonObject()) continue;
+ JsonObject value = upgradeState.getAsJsonObject();
+ String upgrade = value.get("upgrade").getAsString();
+ int tier = value.get("tier").getAsInt();
+ if (communityShopUpgradesMax.has(upgrade)) {
+ int max = communityShopUpgradesMax.get(upgrade).getAsInt();
+ if (max >= tier) {
+ sbXpCommunityUpgrade += communityShopUpgradesXp;
+ }
}
}
}
@@ -157,10 +162,10 @@ public class MiscTaskLevel {
sbXpDojo, miscellaneousTask.get("the_dojo").getAsInt(), false
));
lore.add(levelPage.buildLore(
- EnumChatFormatting.ITALIC + "Harp Songs",
+ "Harp Songs",
sbXpGainedHarp, miscellaneousTask.get("harp_songs").getAsInt(), false
));
- lore.add(levelPage.buildLore(EnumChatFormatting.ITALIC + "Abiphone Contacts",
+ lore.add(levelPage.buildLore("Abiphone Contacts",
sbXpAbiphone, miscellaneousTask.get("abiphone_contacts").getAsInt(), false
));
lore.add(levelPage.buildLore("Community Shop Upgrades",
@@ -170,22 +175,22 @@ public class MiscTaskLevel {
sbXpPersonalBank, miscellaneousTask.get("personal_bank_upgrades").getAsInt(), false
));
+ int totalXp = sbXpReaperPeppers + sbXpDojo + sbXpGainedHarp + sbXpAbiphone +
+ sbXpCommunityUpgrade + sbXpPersonalBank;
levelPage.renderLevelBar(
"Misc. Task",
new ItemStack(Items.map),
- guiLeft + 299,
- guiTop + 55,
+ guiLeft + 299, guiTop + 55,
110,
0,
- sbXpReaperPeppers + sbXpDojo + sbXpGainedHarp + sbXpAbiphone +
- sbXpCommunityUpgrade + sbXpPersonalBank,
+ totalXp,
levelPage.getConstant().getAsJsonObject("category_xp").get("miscellaneous_task").getAsInt(),
- mouseX,
- mouseY,
+ mouseX, mouseY,
true,
lore
);
+ totalXp += sbXpAccessoryUpgrade + sbXpUnlockedPowers;
}
private int getRankIndex(int pointsTotal) {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/SkillRelatedTaskLevel.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/SkillRelatedTaskLevel.java
index 4ba7951c..06ab6f8c 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/SkillRelatedTaskLevel.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/SkillRelatedTaskLevel.java
@@ -43,13 +43,6 @@ public class SkillRelatedTaskLevel {
JsonObject skillRelatedTask = levelPage.getConstant().get("skill_related_task").getAsJsonObject();
JsonObject miningObj = skillRelatedTask.get("mining").getAsJsonObject();
- float mithrilPowder = Utils.getElementAsFloat(Utils.getElement(object, "mining_core.powder_mithril"), 0);
- float gemstonePowder = Utils.getElementAsFloat(Utils.getElement(object, "mining_core.powder_gemstone"), 0);
- float mithril = Utils.getElementAsFloat(Utils.getElement(object, "mining_core.powder_spent_mithril"), 0) +
- mithrilPowder;
- float gemstone = (Utils.getElementAsFloat(Utils.getElement(object, "mining_core.powder_spent_gemstone"), 0)) +
- gemstonePowder;
-
float hotmXp = Utils.getElementAsFloat(Utils.getElement(object, "mining_core.experience"), 0);
ProfileViewer.Level levelObjHotm =
ProfileViewer.getLevel(
@@ -66,29 +59,31 @@ public class SkillRelatedTaskLevel {
hotmXP += hotmXpArray.get(i - 1).getAsInt();
}
- int gainByFirstMithrilThing;
- if (mithril >= 350_000) {
- gainByFirstMithrilThing = (int) (350000 / 2400d);
- mithril -= 350_000;
- } else {
- gainByFirstMithrilThing = (int) (mithril / 2400d);
- mithril = 0;
- }
+ float mithrilPowder = Utils.getElementAsFloat(Utils.getElement(object, "mining_core.powder_mithril"), 0);
+ float gemstonePowder = Utils.getElementAsFloat(Utils.getElement(object, "mining_core.powder_gemstone"), 0);
+ float mithril = Utils.getElementAsFloat(Utils.getElement(object, "mining_core.powder_spent_mithril"), 0) +
+ mithrilPowder;
+ float gemstone = (Utils.getElementAsFloat(Utils.getElement(object, "mining_core.powder_spent_gemstone"), 0)) +
+ gemstonePowder;
- int gainByFirstGemstoneThing;
- if (gemstone >= 350_000) {
- gainByFirstGemstoneThing = (int) (350_000 / 2500d);
- gemstone -= 350_000;
- } else {
- gainByFirstGemstoneThing = (int) (gemstone / 2500d);
- gemstone = 0;
- }
+ // PUNKT NULL
+
+ double totalMithril = mithril + mithrilPowder;
+ double totalGemstone = gemstone + gemstonePowder;
+ double mithrilUnder = Math.min(350000.0, totalMithril);
+ double mithrilOver = Math.max(0, Math.min(totalMithril, 12_500_000.0) - 350000.0);
+ double gemstoneUnder = Math.min(350000.0, totalGemstone);
+ double gemstoneOver = Math.max(0, Math.min(totalGemstone, 20_000_000.0) - 350000.0);
- int sbXpMithrilPowder = (int) powder(3.75, mithril, 12_500_000);
- int sbXpGemstonePowder = (int) powder(4.25, gemstone, 20_000_000);
+ double mithrilXP = Math.floor(mithrilUnder / 2400.0);
+ double gemstoneXP = Math.floor(gemstoneUnder / 2500.0);
+ double mithrilExcess = Math.floor(
+ 3.75 * (Math.sqrt(1 + 8 * Math.sqrt((1758267.0 / 12_500_000.0) * mithrilOver + 9)) - 3));
+ double gemstoneExcess = Math.floor(
+ 4.25 * (Math.sqrt(1 + 8 * Math.sqrt((1758267.0 / 20_000_000.0) * gemstoneOver + 9)) - 3));
double sbXpHotmTier =
- (sbXpMithrilPowder + gainByFirstMithrilThing) + (sbXpGemstonePowder + gainByFirstGemstoneThing)
+ (mithrilXP + mithrilExcess) + (gemstoneXP + gemstoneExcess)
+ hotmXP;
int sbXpPotmTier = 0;
@@ -171,6 +166,18 @@ public class SkillRelatedTaskLevel {
}
}
+ int sbXpNucleus = 0;
+ JsonObject leveling = object.get("leveling").getAsJsonObject();
+ if (leveling.has("completions") && leveling.getAsJsonObject("completions").has("NUCLEUS_RUNS")) {
+ int nucleusRuns = leveling.getAsJsonObject("completions").get("NUCLEUS_RUNS").getAsInt();
+ JsonElement nucleusXp = miningObj.get("crystal_nucleus_xp");
+ if (nucleusXp == null) {
+ Utils.showOutdatedRepoNotification();
+ } else {
+ sbXpNucleus += nucleusRuns * nucleusXp.getAsInt();
+ }
+ }
+
List<String> lore = new ArrayList<>();
lore.add(levelPage.buildLore("Heart of the Mountain", sbXpHotmTier, miningObj.get("hotm").getAsInt(), false));
lore.add(levelPage.buildLore(
@@ -179,7 +186,7 @@ public class SkillRelatedTaskLevel {
miningObj.get("commission_milestone").getAsInt(),
false
));
- lore.add(levelPage.buildLore("Crystal Nucleus", 0, 0, false));
+ lore.add(levelPage.buildLore("Crystal Nucleus", sbXpNucleus, miningObj.get("crystal_nucleus").getAsInt(), false));
lore.add(levelPage.buildLore(
"Anita's Shop Upgrade",
sbXpGainedByAnita,
@@ -189,37 +196,22 @@ public class SkillRelatedTaskLevel {
lore.add(levelPage.buildLore("Peak of the Mountain", sbXpPotmTier, miningObj.get("potm").getAsInt(), false));
lore.add(levelPage.buildLore("Trophy Fish", sbXpTrophyFish, fishingObj.get("trophy_fish").getAsInt(), false));
lore.add(levelPage.buildLore("Rock Milestone", sbXpRockPet, miningObj.get("rock_milestone").getAsInt(), false));
- lore.add(levelPage.buildLore(
- "Dolphin Milestone",
- sbXpDolphinPet,
- fishingObj.get("dolphin_milestone").getAsInt(),
- false
- ));
+ lore.add(levelPage.buildLore("Dolphin Milestone", sbXpDolphinPet, fishingObj.get("dolphin_milestone").getAsInt(), false));
+ int totalXp =
+ (int) (sbXpHotmTier + sbXpCommissionMilestone + sbXpGainedByAnita + sbXpPotmTier + sbXpTrophyFish + sbXpRockPet +
+ sbXpDolphinPet + sbXpNucleus);
levelPage.renderLevelBar(
"Skill Related Task",
new ItemStack(Items.diamond_sword),
- guiLeft + 23,
- guiTop + 115,
+ guiLeft + 23, guiTop + 115,
110,
0,
- sbXpHotmTier + sbXpCommissionMilestone + sbXpGainedByAnita + sbXpPotmTier + sbXpTrophyFish + sbXpRockPet +
- sbXpDolphinPet,
+ totalXp,
levelPage.getConstant().getAsJsonObject("category_xp").get("skill_related_task").getAsInt(),
- mouseX,
- mouseY,
+ mouseX, mouseY,
true,
lore
);
}
-
- private static double powder(double multiplier, float left, int CAP) {
- double cons = 1758267;
- if (left <= 0) return 0;
-
- left = Math.min(CAP, left);
-
- return multiplier * (Math.sqrt(1 + 8 * (Math.sqrt((cons / CAP) * left + 9))) - 3);
- }
-
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/SlayingTaskLevel.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/SlayingTaskLevel.java
index 3aded435..6b624a52 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/SlayingTaskLevel.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/SlayingTaskLevel.java
@@ -233,20 +233,21 @@ public class SlayingTaskLevel {
int slayingTaskMax = levelPage.getConstant().getAsJsonObject("category_xp").get("slaying_task").getAsInt();
+ int totalXp = sbXpGainedSlayer + bossCollectionXp + mythologicalKillsXp +
+ sbXpFromDragonKills + sbXpFromSlayerDefeat + sbXpDefeatKuudra + sbXpGainedArachne;
levelPage.renderLevelBar(
"Slaying Task",
new ItemStack(Items.golden_sword),
- guiLeft + 23,
- guiTop + 85,
+ guiLeft + 23, guiTop + 85,
110,
- 0, sbXpGainedSlayer + bossCollectionXp + mythologicalKillsXp +
- sbXpFromDragonKills + sbXpFromSlayerDefeat + sbXpDefeatKuudra + sbXpGainedArachne,
+ 0,
+ totalXp,
slayingTaskMax,
- mouseX,
- mouseY,
+ mouseX, mouseY,
true,
lore
);
+ totalXp += sbXpBestiary;
}
private int loopThroughCollection(int[] array, double value, JsonArray jsonArray) {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/StoryTaskLevel.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/StoryTaskLevel.java
index 2b1b59cb..3846db5f 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/StoryTaskLevel.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/StoryTaskLevel.java
@@ -61,14 +61,12 @@ public class StoryTaskLevel {
levelPage.renderLevelBar(
"Story Task",
new ItemStack(Items.map),
- guiLeft + 299,
- guiTop + 85,
+ guiLeft + 299, guiTop + 85,
110,
0,
sbXpStory,
levelPage.getConstant().getAsJsonObject("category_xp").get("story_task").getAsInt(),
- mouseX,
- mouseY,
+ mouseX, mouseY,
true,
lore
);
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/ApiUtil.java b/src/main/java/io/github/moulberry/notenoughupdates/util/ApiUtil.java
index c86ac84f..28298fe0 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/util/ApiUtil.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/ApiUtil.java
@@ -48,20 +48,33 @@ import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
+import java.time.Duration;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.zip.GZIPInputStream;
public class ApiUtil {
private static final Gson gson = new Gson();
+
+ private static final Comparator<NameValuePair> nameValuePairComparator = Comparator
+ .comparing(NameValuePair::getName)
+ .thenComparing(NameValuePair::getValue);
+
private static final ExecutorService executorService = Executors.newFixedThreadPool(3);
- private static final String USER_AGENT = "NotEnoughUpdates/" + NotEnoughUpdates.VERSION;
+ private static String getUserAgent() {
+ if (NotEnoughUpdates.INSTANCE.config.hidden.customUserAgent != null) {
+ return NotEnoughUpdates.INSTANCE.config.hidden.customUserAgent;
+ }
+ return "NotEnoughUpdates/" + NotEnoughUpdates.VERSION;
+ }
private static SSLContext ctx;
private final Map<String, CompletableFuture<Void>> updateTasks = new HashMap<>();
@@ -89,11 +102,12 @@ public class ApiUtil {
public void updateProfileData(String playerUuid) {
if (!updateTasks.getOrDefault(playerUuid, CompletableFuture.completedFuture(null)).isDone()) return;
+ String uuid = Minecraft.getMinecraft().thePlayer.getUniqueID().toString().replace("-", "");
updateTasks.put(playerUuid, newHypixelApiRequest("skyblock/profiles")
- .queryArgument("uuid", Minecraft.getMinecraft().thePlayer.getUniqueID().toString().replace("-", ""))
+ .queryArgument("uuid", uuid)
.requestJson()
.handle((jsonObject, throwable) -> {
- new ProfileDataLoadedEvent(jsonObject).post();
+ new ProfileDataLoadedEvent(uuid, jsonObject).post();
return null;
}));
@@ -104,6 +118,7 @@ public class ApiUtil {
private final List<NameValuePair> queryArguments = new ArrayList<>();
private String baseUrl = null;
private boolean shouldGunzip = false;
+ private Duration maxCacheAge = Duration.ofSeconds(500);
private String method = "GET";
private String postData = null;
private String postContentType = null;
@@ -113,6 +128,15 @@ public class ApiUtil {
return this;
}
+ /**
+ * Specify a cache timeout of {@code null} to signify an uncacheable request.
+ * Non {@code GET} requests are always uncacheable.
+ */
+ public Request maxCacheAge(Duration maxCacheAge) {
+ this.maxCacheAge = maxCacheAge;
+ return this;
+ }
+
public Request url(String baseUrl) {
this.baseUrl = baseUrl;
return this;
@@ -154,7 +178,17 @@ public class ApiUtil {
return fut;
}
- public CompletableFuture<String> requestString() {
+ public String getBaseUrl() {
+ return baseUrl;
+ }
+
+ private ApiCache.CacheKey getCacheKey() {
+ if (!"GET".equals(method)) return null;
+ queryArguments.sort(nameValuePairComparator);
+ return new ApiCache.CacheKey(baseUrl, queryArguments, shouldGunzip);
+ }
+
+ private CompletableFuture<String> requestString0() {
return buildUrl().thenApplyAsync(url -> {
try {
InputStream inputStream = null;
@@ -169,7 +203,7 @@ public class ApiUtil {
}
conn.setConnectTimeout(10000);
conn.setReadTimeout(10000);
- conn.setRequestProperty("User-Agent", USER_AGENT);
+ conn.setRequestProperty("User-Agent", getUserAgent());
if (this.postContentType != null) {
conn.setRequestProperty("Content-Type", this.postContentType);
}
@@ -177,7 +211,7 @@ public class ApiUtil {
conn.setDoOutput(true);
OutputStream os = conn.getOutputStream();
try {
- os.write(this.postData.getBytes("utf-8"));
+ os.write(this.postData.getBytes(StandardCharsets.UTF_8));
} finally {
os.close();
}
@@ -207,7 +241,16 @@ public class ApiUtil {
} catch (IOException e) {
throw new RuntimeException(e); // We can rethrow, since supplyAsync catches exceptions.
}
- }, executorService);
+ }, executorService).handle((obj, t) -> {
+ if (t != null) {
+ System.err.println(ErrorUtil.printStackTraceWithoutApiKey(t));
+ }
+ return obj;
+ });
+ }
+
+ public CompletableFuture<String> requestString() {
+ return ApiCache.INSTANCE.cacheRequest(this, getCacheKey(), this::requestString0, maxCacheAge);
}
public CompletableFuture<JsonObject> requestJson() {
@@ -215,7 +258,7 @@ public class ApiUtil {
}
public <T> CompletableFuture<T> requestJson(Class<? extends T> clazz) {
- return requestString().thenApply(str -> gson.fromJson(str, clazz));
+ return requestString().thenApplyAsync(str -> gson.fromJson(str, clazz));
}
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/SBInfo.java b/src/main/java/io/github/moulberry/notenoughupdates/util/SBInfo.java
index 8ce765aa..a89b281d 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/util/SBInfo.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/SBInfo.java
@@ -24,6 +24,7 @@ import com.google.gson.JsonObject;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import io.github.moulberry.notenoughupdates.autosubscribe.NEUAutoSubscribe;
import io.github.moulberry.notenoughupdates.listener.ScoreboardLocationChangeListener;
+import io.github.moulberry.notenoughupdates.miscfeatures.CookieWarning;
import io.github.moulberry.notenoughupdates.miscfeatures.customblockzones.LocationChangeEvent;
import io.github.moulberry.notenoughupdates.miscgui.minionhelper.MinionHelperManager;
import io.github.moulberry.notenoughupdates.overlays.OverlayManager;
@@ -86,6 +87,7 @@ public class SBInfo {
public String objective = "";
public String slayer = "";
public boolean stranded = false;
+ public boolean bingo = false;
public String mode = null;
@@ -388,6 +390,7 @@ public class SBInfo {
isInDungeon = tempIsInDungeon;
boolean containsStranded = false;
+ boolean containsBingo = false;
for (String line : lines) { //Slayer stuff
if (line.contains("Tarantula Broodfather")) {
slayer = "Tarantula";
@@ -422,8 +425,10 @@ public class SBInfo {
}
}
if (line.contains("☀ Stranded")) containsStranded = true;
+ if (line.contains("Ⓑ Bingo")) containsBingo = true;
}
stranded = containsStranded;
+ bingo = containsBingo;
if (lines.size() >= 5) {
date = Utils.cleanColour(lines.get(1)).trim();
@@ -473,7 +478,6 @@ public class SBInfo {
.thenAccept(newJson -> mayorJson = newJson);
}
-
public JsonObject getMayorJson() {
return mayorJson;
}
@@ -482,6 +486,7 @@ public class SBInfo {
if (!newProfile.equals(currentProfile)) {
currentProfile = newProfile;
MinionHelperManager.getInstance().onProfileSwitch();
+ CookieWarning.onProfileSwitch();
}
}
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java b/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java
index 952eb50f..38debbbc 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java
@@ -186,7 +186,7 @@ public class Utils {
}
int newScale = guiScales.size() > 0
- ? Math.max(0, Math.min(4, guiScales.peek()))
+ ? Math.max(0, guiScales.peek())
: Minecraft.getMinecraft().gameSettings.guiScale;
if (newScale == 0) newScale = Minecraft.getMinecraft().gameSettings.guiScale;
@@ -925,6 +925,10 @@ public class Utils {
return createItemStack(item, displayName, 0, lore);
}
+ public static ItemStack createItemStackArray(Item item, String displayName, String[] lore) {
+ return createItemStack(item, displayName, 0, lore);
+ }
+
public static ItemStack createItemStack(Block item, String displayName, String... lore) {
return createItemStack(Item.getItemFromBlock(item), displayName, lore);
}
@@ -932,17 +936,7 @@ public class Utils {
public static ItemStack createItemStack(Item item, String displayName, int damage, String... lore) {
ItemStack stack = new ItemStack(item, 1, damage);
NBTTagCompound tag = new NBTTagCompound();
- NBTTagCompound display = new NBTTagCompound();
- NBTTagList Lore = new NBTTagList();
-
- for (String line : lore) {
- Lore.appendTag(new NBTTagString(line));
- }
-
- display.setString("Name", displayName);
- display.setTag("Lore", Lore);
-
- tag.setTag("display", display);
+ addNameAndLore(tag, displayName, lore);
tag.setInteger("HideFlags", 254);
stack.setTagCompound(tag);
@@ -950,6 +944,22 @@ public class Utils {
return stack;
}
+ private static void addNameAndLore(NBTTagCompound tag, String displayName, String[] lore) {
+ NBTTagCompound display = new NBTTagCompound();
+
+ display.setString("Name", displayName);
+
+ if (lore != null) {
+ NBTTagList tagLore = new NBTTagList();
+ for (String line : lore) {
+ tagLore.appendTag(new NBTTagString(line));
+ }
+ display.setTag("Lore", tagLore);
+ }
+
+ tag.setTag("display", display);
+ }
+
public static ItemStack editItemStackInfo(
ItemStack itemStack,
String displayName,
@@ -979,15 +989,17 @@ public class Utils {
return itemStack;
}
-
public static ItemStack createSkull(String displayName, String uuid, String value) {
+ return createSkull(displayName, uuid, value, null);
+ }
+
+ public static ItemStack createSkull(String displayName, String uuid, String value, String[] lore) {
ItemStack render = new ItemStack(Items.skull, 1, 3);
NBTTagCompound tag = new NBTTagCompound();
NBTTagCompound skullOwner = new NBTTagCompound();
NBTTagCompound properties = new NBTTagCompound();
NBTTagList textures = new NBTTagList();
NBTTagCompound textures_0 = new NBTTagCompound();
- NBTTagCompound display = new NBTTagCompound();
skullOwner.setString("Id", uuid);
skullOwner.setString("Name", uuid);
@@ -995,8 +1007,7 @@ public class Utils {
textures_0.setString("Value", value);
textures.appendTag(textures_0);
- display.setString("Name", displayName);
- tag.setTag("display", display);
+ addNameAndLore(tag, displayName, lore);
properties.setTag("textures", textures);
skullOwner.setTag("Properties", properties);
@@ -1229,6 +1240,22 @@ public class Utils {
drawStringScaled(str, fr, x - len / 2, y - fontHeight / 2, shadow, colour, factor);
}
+ public static void drawStringCenteredScaled(
+ String str,
+ FontRenderer fr,
+ float x,
+ float y,
+ boolean shadow,
+ float factor
+ ) {
+ int strLen = fr.getStringWidth(str);
+
+ float x2 = x - strLen / 2f;
+ float y2 = y - fr.FONT_HEIGHT / 2f;
+
+ drawStringScaled(str, fr, x2, y2, shadow, 0, factor);
+ }
+
public static void drawStringCenteredYScaled(
String str,
FontRenderer fr,
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/events/ProfileDataLoadedEvent.java b/src/main/kotlin/io/github/moulberry/notenoughupdates/events/ProfileDataLoadedEvent.kt
index 956acfe0..00a535c6 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/events/ProfileDataLoadedEvent.java
+++ b/src/main/kotlin/io/github/moulberry/notenoughupdates/events/ProfileDataLoadedEvent.kt
@@ -16,25 +16,27 @@
* You should have received a copy of the GNU Lesser General Public License
* along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
*/
+package io.github.moulberry.notenoughupdates.events
-package io.github.moulberry.notenoughupdates.events;
-
-import com.google.gson.JsonObject;
-
-import javax.annotation.Nullable;
+import com.google.gson.JsonObject
//TODO extend the usage of this event (accessory bag and storage data)
-public class ProfileDataLoadedEvent extends NEUEvent {
-
- @Nullable
- private final JsonObject data;
+class ProfileDataLoadedEvent(val uuid: String, val data: JsonObject?) : NEUEvent() {
+ val profileInfo: JsonObject? by lazy { readProfileInfo() }
- public ProfileDataLoadedEvent(@Nullable JsonObject entireApiResponse) {
- this.data = entireApiResponse;
- }
+ private fun readProfileInfo(): JsonObject? {
+ if (data == null) return null
- @Nullable
- public JsonObject getData() {
- return data;
- }
+ val skyblockProfiles = data["profiles"].asJsonArray
+ for (profileEle in skyblockProfiles) {
+ val profile = profileEle.asJsonObject
+ if (!profile.has("members")) continue
+ val members = profile["members"].asJsonObject
+ if (!members.has(uuid)) continue
+ if (profile.has("selected") && profile["selected"].asBoolean) {
+ return members[uuid].asJsonObject
+ }
+ }
+ return null
+ }
}
diff --git a/src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/OldSkyBlockMenu.kt b/src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/OldSkyBlockMenu.kt
new file mode 100644
index 00000000..b871a672
--- /dev/null
+++ b/src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/OldSkyBlockMenu.kt
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2023 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures
+
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates
+import io.github.moulberry.notenoughupdates.autosubscribe.NEUAutoSubscribe
+import io.github.moulberry.notenoughupdates.events.ReplaceItemEvent
+import io.github.moulberry.notenoughupdates.events.SlotClickEvent
+import io.github.moulberry.notenoughupdates.util.Utils
+import net.minecraft.client.player.inventory.ContainerLocalMenu
+import net.minecraft.init.Items
+import net.minecraft.item.Item
+import net.minecraft.item.ItemStack
+import net.minecraftforge.fml.common.eventhandler.EventPriority
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+
+@NEUAutoSubscribe
+object OldSkyBlockMenu {
+
+ val map: Map<Int, SkyBlockButton> by lazy {
+ val map = mutableMapOf<Int, SkyBlockButton>()
+ for (button in SkyBlockButton.values()) {
+ map[button.slot] = button
+ }
+ map
+ }
+
+ @SubscribeEvent
+ fun replaceItem(event: ReplaceItemEvent) {
+ if (!isRightInventory()) return
+ if (event.inventory !is ContainerLocalMenu) return
+
+ val skyBlockButton = map[event.slotNumber] ?: return
+
+ if (skyBlockButton.requiresBoosterCookie && !CookieWarning.hasActiveBoosterCookie()) {
+ event.replaceWith(skyBlockButton.itemWithCookieWarning)
+ } else {
+ event.replaceWith(skyBlockButton.itemWithoutCookieWarning)
+ }
+ }
+
+ @SubscribeEvent(priority = EventPriority.HIGH)
+ fun onStackClick(event: SlotClickEvent) {
+ if (!isRightInventory()) return
+
+ val skyBlockButton = map[event.slotId] ?: return
+ event.isCanceled = true
+
+ if (!skyBlockButton.requiresBoosterCookie || CookieWarning.hasActiveBoosterCookie()) {
+ NotEnoughUpdates.INSTANCE.sendChatMessage("/" + skyBlockButton.command)
+ }
+ }
+
+ private fun isRightInventory(): Boolean {
+ return NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard() &&
+ NotEnoughUpdates.INSTANCE.config.misc.oldSkyBlockMenu &&
+ Utils.getOpenChestName() == "SkyBlock Menu"
+ }
+
+ enum class SkyBlockButton(
+ val command: String,
+ val slot: Int,
+ private val displayName: String,
+ private vararg val displayDescription: String,
+ private val itemData: ItemData,
+ val requiresBoosterCookie: Boolean = true,
+ ) {
+ TRADES(
+ "trades", 40,
+ "Trades",
+ "View your available trades.",
+ "These trades are always",
+ "available and accessible through",
+ "the SkyBlock Menu.",
+ itemData = NormalItemData(Items.emerald),
+ requiresBoosterCookie = false
+ ),
+ ACCESSORY(
+ "accessories", 53,
+ "Accessory Bag",
+ "A special bag which can hold",
+ "Talismans, Rings, Artifacts, Relics, and",
+ "Orbs within it. All will still",
+ "work while in this bag!",
+ itemData = SkullItemData(
+ "2b73dd76-5fc1-4ac3-8139-6a8992f8ce80",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTYxYTkxOGMw" +
+ "YzQ5YmE4ZDA1M2U1MjJjYjkxYWJjNzQ2ODkzNjdiNGQ4YWEwNmJmYzFiYTkxNTQ3MzA5ODVmZiJ9fX0="
+ )
+ ),
+ POTION(
+ "potionbag", 52,
+ "Potion Bag",
+ "A handy bag for holding your",
+ "Potions in.",
+ itemData = SkullItemData(
+ "991c4a18-3283-4629-b0fc-bbce23cd658c",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOWY4Yjg" +
+ "yNDI3YjI2MGQwYTYxZTY0ODNmYzNiMmMzNWE1ODU4NTFlMDhhOWE5ZGYzNzI1NDhiNDE2OGNjODE3YyJ9fX0="
+ )
+ ),
+ QUIVER(
+ "quiver", 44,
+ "Quiver",
+ "A masterfully crafted Quiver",
+ "which holds any kind of",
+ "projectile you can think of!",
+ itemData = SkullItemData(
+ "41758912-e6b1-4700-9de5-04f2cfb9c422",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNGNiM2FjZ" +
+ "GMxMWNhNzQ3YmY3MTBlNTlmNGM4ZTliM2Q5NDlmZGQzNjRjNjg2OTgzMWNhODc4ZjA3NjNkMTc4NyJ9fX0="
+ )
+ ),
+ FISHING(
+ "fishingbag", 43,
+ "Fishing Bag",
+ "A useful bag which can hold all",
+ "types of fish, baits, and fishing",
+ "loot!",
+ itemData = SkullItemData(
+ "508c01d6-eabe-430b-9811-874691ee7ee4",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWI4ZT" +
+ "I5N2RmNmI4ZGZmY2YxMzVkYmE4NGVjNzkyZDQyMGFkOGVjYjQ1OGQxNDQyODg1NzJhODQ2MDNiMTYzMSJ9fX0="
+ )
+ ),
+ SACK_OF_SACKS(
+ "sacks", 35,
+ "Sack of Sacks",
+ "A sack which contains other",
+ "sacks. Sackception!",
+ itemData = SkullItemData(
+ "a206a7eb-70fc-4f9f-8316-c3f69d6ba2ca",
+ "ewogICJ0aW1lc3RhbXAiIDogMTU5MTMxMDU4NTYwOSwKICAicHJvZmlsZUlkIiA6ICI0MWQzYWJjMmQ3NDk0MDBjOTA5MGQ1NDM0" +
+ "ZDAzODMxYiIsCiAgInByb2ZpbGVOYW1lIiA6ICJNZWdha2xvb24iLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVl" +
+ "LAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5l" +
+ "Y3JhZnQubmV0L3RleHR1cmUvODBhMDc3ZTI0OGQxNDI3NzJlYTgwMDg2NGY4YzU3OGI5ZDM2ODg1YjI5ZGFmODM2YjY0" +
+ "YTcwNjg4MmI2ZWMxMCIKICAgIH0KICB9Cn0="
+ ),
+ requiresBoosterCookie = false
+ ),
+ ;
+
+ val itemWithCookieWarning: ItemStack by lazy { createItem(true) }
+ val itemWithoutCookieWarning: ItemStack by lazy { createItem(false) }
+
+ private fun createItem(showCookieWarning: Boolean): ItemStack {
+ val lore = mutableListOf<String>()
+ for (line in displayDescription) {
+ lore.add("§7$line")
+ }
+ lore.add("")
+
+ if (showCookieWarning) {
+ lore.add("§cYou need a booster cookie active")
+ lore.add("§cto use this shortcut!")
+ } else {
+ lore.add("§eClick to execute /${command}")
+ }
+ val array = lore.toTypedArray()
+ val name = "§a${displayName}"
+ return when (itemData) {
+ is NormalItemData -> Utils.createItemStackArray(itemData.displayIcon, name, array)
+ is SkullItemData -> Utils.createSkull(
+ name,
+ itemData.uuid,
+ itemData.value,
+ array
+ )
+ }
+ }
+ }
+
+ sealed interface ItemData
+
+ class NormalItemData(val displayIcon: Item) : ItemData
+
+ class SkullItemData(val uuid: String, val value: String) : ItemData
+}
diff --git a/src/main/kotlin/io/github/moulberry/notenoughupdates/util/ApiCache.kt b/src/main/kotlin/io/github/moulberry/notenoughupdates/util/ApiCache.kt
new file mode 100644
index 00000000..c14df425
--- /dev/null
+++ b/src/main/kotlin/io/github/moulberry/notenoughupdates/util/ApiCache.kt
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2023 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.util
+
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates
+import io.github.moulberry.notenoughupdates.options.customtypes.NEUDebugFlag
+import io.github.moulberry.notenoughupdates.util.ApiUtil.Request
+import org.apache.http.NameValuePair
+import java.nio.file.Files
+import java.nio.file.Path
+import java.time.Duration
+import java.util.*
+import java.util.concurrent.CompletableFuture
+import java.util.function.Supplier
+import kotlin.io.path.deleteIfExists
+import kotlin.io.path.readText
+import kotlin.io.path.writeText
+import kotlin.time.Duration.Companion.hours
+import kotlin.time.Duration.Companion.seconds
+import kotlin.time.ExperimentalTime
+import kotlin.time.TimeSource
+import kotlin.time.toKotlinDuration
+
+@OptIn(ExperimentalTime::class)
+
+object ApiCache {
+ data class CacheKey(
+ val baseUrl: String,
+ val requestParameters: List<NameValuePair>,
+ val shouldGunzip: Boolean,
+ )
+
+ data class CacheResult(
+ private var future: CompletableFuture<String>?,
+ val firedAt: TimeSource.Monotonic.ValueTimeMark,
+ private var file: Path? = null,
+ private var disposed: Boolean = false,
+ ) {
+ init {
+ future!!.thenAcceptAsync { text ->
+ synchronized(this) {
+ if (disposed) {
+ return@synchronized
+ }
+ future = null
+ val f = Files.createTempFile(cacheBaseDir, "api-cache", ".bin")
+ log("Writing cache to disk: $f")
+ f.toFile().deleteOnExit()
+ f.writeText(text)
+ file = f
+ }
+ }
+ }
+
+ val isAvailable get() = file != null && !disposed
+
+ fun getCachedFuture(): CompletableFuture<String> {
+ synchronized(this) {
+ if (disposed) {
+ return CompletableFuture.supplyAsync {
+ throw IllegalStateException("Attempting to read from a disposed future at $file. Most likely caused by non synchronized access to ApiCache.cachedRequests")
+ }
+ }
+ val fut = future
+ if (fut != null) {
+ return fut
+ } else {
+ val text = file!!.readText()
+ return CompletableFuture.completedFuture(text)
+ }
+ }
+ }
+
+ /**
+ * Should be called when removing / replacing a request from [cachedRequests].
+ * Should only be called while holding a lock on [ApiCache].
+ * This deletes the disk cache and smashes the internal state for it to be GCd.
+ * After calling this method no other method may be called on this object.
+ */
+ internal fun dispose() {
+ synchronized(this) {
+ if (disposed) return
+ log("Disposing cache for $file")
+ disposed = true
+ file?.deleteIfExists()
+ future = null
+ }
+ }
+ }
+
+ private val cacheBaseDir by lazy {
+ val d = Files.createTempDirectory("neu-cache")
+ d.toFile().deleteOnExit()
+ d
+ }
+ private val cachedRequests = mutableMapOf<CacheKey, CacheResult>()
+ val histogramTotalRequests: MutableMap<String, Int> = mutableMapOf()
+ val histogramNonCachedRequests: MutableMap<String, Int> = mutableMapOf()
+
+ private val timeout = 10.seconds
+ private val globalMaxCacheAge = 1.hours
+
+ private fun log(message: String) {
+ NEUDebugFlag.API_CACHE.log(message)
+ }
+
+ private fun traceApiRequest(
+ request: Request,
+ failReason: String?,
+ ) {
+ if (!NotEnoughUpdates.INSTANCE.config.hidden.dev) return
+ val callingClass = Thread.currentThread().stackTrace
+ .find {
+ !it.className.startsWith("java.") &&
+ !it.className.startsWith("kotlin.") &&
+ it.className != ApiCache::class.java.name &&
+ it.className != ApiUtil::class.java.name &&
+ it.className != Request::class.java.name
+ }
+ val callingClassText = callingClass?.let {
+ "${it.className}.${it.methodName} (${it.fileName}:${it.lineNumber})"
+ } ?: "no calling class found"
+ callingClass?.className?.let {
+ histogramTotalRequests[it] = (histogramTotalRequests[it] ?: 0) + 1
+ if (failReason != null)
+ histogramNonCachedRequests[it] = (histogramNonCachedRequests[it] ?: 0) + 1
+ }
+ if (failReason != null) {
+ log("Executing api request for url ${request.baseUrl} by $callingClassText: $failReason")
+ } else {
+ log("Cache hit for api request for url ${request.baseUrl} by $callingClassText.")
+ }
+ }
+
+ private fun evictCache() {
+ synchronized(this) {
+ val it = cachedRequests.iterator()
+ while (it.hasNext()) {
+ val next = it.next()
+ if (next.value.firedAt.elapsedNow() >= globalMaxCacheAge) {
+ next.value.dispose()
+ it.remove()
+ }
+ }
+ }
+ }
+
+ fun cacheRequest(
+ request: Request,
+ cacheKey: CacheKey?,
+ futureSupplier: Supplier<CompletableFuture<String>>,
+ maxAge: Duration?
+ ): CompletableFuture<String> {
+ evictCache()
+ if (cacheKey == null) {
+ traceApiRequest(request, "uncacheable request (probably POST)")
+ return futureSupplier.get()
+ }
+ if (maxAge == null) {
+ traceApiRequest(request, "manually specified as uncacheable")
+ return futureSupplier.get()
+ }
+ fun recache(): CompletableFuture<String> {
+ return futureSupplier.get().also {
+ cachedRequests[cacheKey]?.dispose() // Safe to dispose like this because this function is always called in a synchronized block
+ cachedRequests[cacheKey] = CacheResult(it, TimeSource.Monotonic.markNow())
+ }
+ }
+ synchronized(this) {
+ val cachedRequest = cachedRequests[cacheKey]
+ if (cachedRequest == null) {
+ traceApiRequest(request, "no cache found")
+ return recache()
+ }
+
+ return if (cachedRequest.isAvailable) {
+ if (cachedRequest.firedAt.elapsedNow() > maxAge.toKotlinDuration()) {
+ traceApiRequest(request, "outdated cache")
+ recache()
+ } else {
+ // Using local cached request
+ traceApiRequest(request, null)
+ cachedRequest.getCachedFuture()
+ }
+ } else {
+ if (cachedRequest.firedAt.elapsedNow() > timeout) {
+ traceApiRequest(request, "suspiciously slow api response")
+ recache()
+ } else {
+ // Joining ongoing request
+ traceApiRequest(request, null)
+ cachedRequest.getCachedFuture()
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/main/kotlin/io/github/moulberry/notenoughupdates/util/ErrorUtil.kt b/src/main/kotlin/io/github/moulberry/notenoughupdates/util/ErrorUtil.kt
new file mode 100644
index 00000000..f849a40d
--- /dev/null
+++ b/src/main/kotlin/io/github/moulberry/notenoughupdates/util/ErrorUtil.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.util
+
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates
+import java.io.ByteArrayOutputStream
+import java.io.PrintStream
+import java.nio.charset.StandardCharsets
+
+object ErrorUtil {
+ @JvmStatic
+ fun printCensoredStackTrace(e: Throwable, toCensor: List<String>): String {
+ val baos = ByteArrayOutputStream()
+ e.printStackTrace(PrintStream(baos, true, StandardCharsets.UTF_8.name()))
+ var string = String(baos.toByteArray(), StandardCharsets.UTF_8)
+ toCensor.forEach {
+ string = string.replace(it, "*".repeat(it.length))
+ }
+ return string
+ }
+
+ @JvmStatic
+ fun printStackTraceWithoutApiKey(e: Throwable): String {
+ return printCensoredStackTrace(e, listOf(NotEnoughUpdates.INSTANCE.config.apiData.apiKey))
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/MinecraftExecutor.java b/src/main/kotlin/io/github/moulberry/notenoughupdates/util/MinecraftExecutor.kt
index bf973b76..bb0bc8b4 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/util/MinecraftExecutor.java
+++ b/src/main/kotlin/io/github/moulberry/notenoughupdates/util/MinecraftExecutor.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 NotEnoughUpdates contributors
+ * Copyright (C) 2023 NotEnoughUpdates contributors
*
* This file is part of NotEnoughUpdates.
*
@@ -17,21 +17,31 @@
* along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
*/
-package io.github.moulberry.notenoughupdates.util;
+package io.github.moulberry.notenoughupdates.util
-import net.minecraft.client.Minecraft;
-import org.jetbrains.annotations.NotNull;
+import net.minecraft.client.Minecraft
+import java.util.concurrent.Executor
+import java.util.concurrent.ForkJoinPool
-import java.util.concurrent.Executor;
+object MinecraftExecutor {
-public class MinecraftExecutor implements Executor {
+ @JvmField
+ val OnThread = Executor {
+ val mc = Minecraft.getMinecraft()
+ if (mc.isCallingFromMinecraftThread) {
+ it.run()
+ } else {
+ Minecraft.getMinecraft().addScheduledTask(it)
+ }
+ }
- public static MinecraftExecutor INSTANCE = new MinecraftExecutor();
-
- private MinecraftExecutor() {}
-
- @Override
- public void execute(@NotNull Runnable runnable) {
- Minecraft.getMinecraft().addScheduledTask(runnable);
- }
+ @JvmField
+ val OffThread = Executor {
+ val mc = Minecraft.getMinecraft()
+ if (mc.isCallingFromMinecraftThread) {
+ ForkJoinPool.commonPool().execute(it)
+ } else {
+ it.run()
+ }
+ }
}
diff --git a/src/main/resources/assets/notenoughupdates/pv_levels.png b/src/main/resources/assets/notenoughupdates/pv_levels.png
index 21810476..0b6bb093 100644
--- a/src/main/resources/assets/notenoughupdates/pv_levels.png
+++ b/src/main/resources/assets/notenoughupdates/pv_levels.png
Binary files differ