aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorefefury <69400149+efefury@users.noreply.github.com>2023-01-31 22:04:33 +0000
committerGitHub <noreply@github.com>2023-01-31 23:04:33 +0100
commit7d34b5456f9978d063b9098ab095256109d522c2 (patch)
tree3752f4adb11ef6bf77c017102343121141e3571b /src
parent291860435d5487562b122aaddbe57c178a8734de (diff)
downloadNotEnoughUpdates-7d34b5456f9978d063b9098ab095256109d522c2.tar.gz
NotEnoughUpdates-7d34b5456f9978d063b9098ab095256109d522c2.tar.bz2
NotEnoughUpdates-7d34b5456f9978d063b9098ab095256109d522c2.zip
Levels page in Profile Viewer (#562)
* ughidontwannafigureouthowtousethis * not finished hgdt< * Make use of new collections api in collectionspage * final commit HOPEFULLY * fix infer v1 * fix mithril powder going over cap my beloved * Formatting :thumbsup: * More Formatting :thumbsup: important * ea sports its in the game * maybe fix cache * change location of weight and networth and config option for weght requested by alea * Fix jump at CAP powder * Code formatting and deleted unused variables. * Used KUUDRA_TIERS array from CrimsonIslePage in SlayingTaskLevel. * Used SLAYERS array from PROFILEVIEWER in SlayingTaskLevel. * Intellij Code Cleanup. * revert fun things Please efe put formatting in another PR. * fix issues idk * Import fixes and formatting. And an unnecessary empty space in 2.1.1 for jani. * fix nea issue --------- Co-authored-by: nea <nea@nea.moe> Co-authored-by: jani270 <jani270@gmx.de> Co-authored-by: hannibal2 <24389977+hannibal00212@users.noreply.github.com>
Diffstat (limited to 'src')
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/dev/DevTestCommand.java36
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/util/StringUtils.java15
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/ProfileViewer.java8
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/BasicPage.java251
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/CollectionsPage.java379
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/CrimsonIslePage.java31
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/DungeonPage.java339
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ExtraPage.java2
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java23
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/InventoriesPage.java2
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/PlayerStats.java123
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ProfileViewer.java438
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/bestiary/BestiaryPage.java36
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/LevelPage.java229
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/CoreTaskLevel.java163
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/DungeonTaskLevel.java126
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/EssenceTaskLevel.java140
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/MiscTaskLevel.java200
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/SkillRelatedTaskLevel.java225
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/SlayingTaskLevel.java264
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/StoryTaskLevel.java76
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/Constants.java3
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java79
-rw-r--r--src/main/kotlin/io/github/moulberry/notenoughupdates/util/hypixelapi/Collection.kt159
-rw-r--r--src/main/resources/assets/notenoughupdates/pv_basic.pngbin2836 -> 2818 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/pv_levels.pngbin0 -> 3526 bytes
26 files changed, 2473 insertions, 874 deletions
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 cf266dca..0d882358 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
@@ -19,6 +19,9 @@
package io.github.moulberry.notenoughupdates.commands.dev;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
import io.github.moulberry.notenoughupdates.BuildFlags;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import io.github.moulberry.notenoughupdates.commands.ClientCommandBase;
@@ -34,6 +37,7 @@ 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 net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.command.CommandException;
@@ -122,6 +126,32 @@ public class DevTestCommand extends ClientCommandBase {
Utils.addChatMessage(EnumChatFormatting.RED + DEV_FAIL_STRINGS[devFailIndex++]);
return;
}
+ if (args.length == 1 && args[0].equalsIgnoreCase("testprofile")) {
+ NotEnoughUpdates.INSTANCE.manager.apiUtils.newHypixelApiRequest("skyblock/profiles")
+ .queryArgument(
+ "uuid",
+ "" + Minecraft.getMinecraft().thePlayer.getUniqueID()
+ )
+ .requestJson()
+ .thenApply(jsonObject -> {
+ JsonArray profiles = jsonObject.get("profiles").getAsJsonArray();
+ JsonObject cp = null;
+ for (JsonElement profile : profiles) {
+ JsonObject asJsonObject = profile.getAsJsonObject();
+ if ((asJsonObject.has("selected") &&
+ asJsonObject.get("selected").getAsBoolean()) || cp == null) {
+ cp = asJsonObject;
+ }
+ }
+ return cp;
+ })
+ .thenCompose(obj -> ProfileCollectionInfo.getCollectionData(
+ obj,
+ Minecraft.getMinecraft().thePlayer.getUniqueID().toString()
+ ))
+ .thenAccept(it ->
+ Utils.addChatMessage("Response: " + it));
+ }
if (args.length >= 1 && args[0].equalsIgnoreCase("profileinfo")) {
String currentProfile = SBInfo.getInstance().currentProfile;
SBInfo.Gamemode gamemode = SBInfo.getInstance().getGamemodeForProfile(currentProfile);
@@ -146,7 +176,8 @@ public class DevTestCommand extends ClientCommandBase {
Arrays.copyOfRange(args, 1, args.length)
);
}
- Utils.addChatMessage("§e[NEU] §fYour external editor is: §Z" + NotEnoughUpdates.INSTANCE.config.hidden.externalEditor);
+ Utils.addChatMessage(
+ "§e[NEU] §fYour external editor is: §Z" + NotEnoughUpdates.INSTANCE.config.hidden.externalEditor);
return;
}
if (args.length >= 1 && args[0].equalsIgnoreCase("pricetest")) {
@@ -181,7 +212,8 @@ public class DevTestCommand extends ClientCommandBase {
}
if (args.length == 1 && args[0].equalsIgnoreCase("dev")) {
NotEnoughUpdates.INSTANCE.config.hidden.dev = !NotEnoughUpdates.INSTANCE.config.hidden.dev;
- Utils.addChatMessage("§e[NEU] Dev mode " + (NotEnoughUpdates.INSTANCE.config.hidden.dev ? "§aenabled": "§cdisabled"));
+ Utils.addChatMessage(
+ "§e[NEU] Dev mode " + (NotEnoughUpdates.INSTANCE.config.hidden.dev ? "§aenabled" : "§cdisabled"));
return;
}
if (args.length == 1 && args[0].equalsIgnoreCase("saveconfig")) {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/util/StringUtils.java b/src/main/java/io/github/moulberry/notenoughupdates/core/util/StringUtils.java
index c19c4826..c7c118bb 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/util/StringUtils.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/util/StringUtils.java
@@ -24,6 +24,7 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import java.io.UnsupportedEncodingException;
+import java.math.BigInteger;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Set;
@@ -71,7 +72,17 @@ public class StringUtils {
return shortNumberFormat(n, 0);
}
- private static final char[] c = new char[] { 'k', 'm', 'b', 't' };
+ private static final char[] sizeSuffix = new char[]{'k', 'm', 'b', 't'};
+
+ public static String shortNumberFormat(BigInteger bigInteger) {
+ BigInteger THOUSAND = BigInteger.valueOf(1000);
+ int i = -1;
+ while (bigInteger.compareTo(THOUSAND) > 0 && i < sizeSuffix.length) {
+ bigInteger = bigInteger.divide(THOUSAND);
+ i++;
+ }
+ return bigInteger.toString() + (i == -1 ? "" : sizeSuffix[i]);
+ }
public static String shortNumberFormat(double n, int iteration) {
if (n < 1000) {
@@ -84,7 +95,7 @@ public class StringUtils {
double d = ((long) n / 100) / 10.0;
boolean isRound = (d * 10) % 10 == 0;
- return d < 1000 ? (isRound || d > 9.99 ? (int) d * 10 / 10 : d + "") + "" + c[iteration] : shortNumberFormat(d, iteration + 1);
+ return d < 1000 ? (isRound || d > 9.99 ? (int) d * 10 / 10 : d + "") + "" + sizeSuffix[iteration] : shortNumberFormat(d, iteration + 1);
}
public static String urlEncode(String something) {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/ProfileViewer.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/ProfileViewer.java
index 30915daa..42a52639 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/ProfileViewer.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/ProfileViewer.java
@@ -103,4 +103,12 @@ public class ProfileViewer {
)
@ConfigEditorBoolean
public boolean useSoopyNetworth = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Display Weight",
+ desc = "Display Lily and Senither Weight in the Basic PV page"
+ )
+ @ConfigEditorBoolean
+ public boolean displayWeight = true;
}
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 47df3c6e..8a48dd2c 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/BasicPage.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/BasicPage.java
@@ -19,13 +19,13 @@
package io.github.moulberry.notenoughupdates.profileviewer;
-import com.google.common.base.Splitter;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.mojang.authlib.GameProfile;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import io.github.moulberry.notenoughupdates.core.util.StringUtils;
+import io.github.moulberry.notenoughupdates.profileviewer.level.LevelPage;
import io.github.moulberry.notenoughupdates.profileviewer.weight.lily.LilyWeight;
import io.github.moulberry.notenoughupdates.profileviewer.weight.senither.SenitherWeight;
import io.github.moulberry.notenoughupdates.util.Constants;
@@ -53,11 +53,12 @@ import org.apache.commons.lang3.text.WordUtils;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.GL11;
-import org.lwjgl.opengl.GL14;
import java.awt.*;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -72,6 +73,34 @@ import static io.github.moulberry.notenoughupdates.util.Utils.roundToNearestInt;
public class BasicPage extends GuiProfileViewerPage {
private static final ResourceLocation pv_basic = new ResourceLocation("notenoughupdates:pv_basic.png");
+
+ public static final ItemStack skull = Utils.createSkull(
+ "egirlefe",
+ "152de44a-43a3-46e1-badc-66cca2793471",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODdkODg1YjMyYjBkZDJkNmI3ZjFiNTgyYTM0MTg2ZjhhNTM3M2M0NjU4OWEyNzM0MjMxMzJiNDQ4YjgwMzQ2MiJ9fX0="
+ );
+
+ private static final LinkedHashMap<String, ItemStack> dungeonsModeIcons = new LinkedHashMap<String, ItemStack>() {
+ {
+ put(
+ "first_page",
+ Utils.editItemStackInfo(
+ new ItemStack(Items.paper),
+ EnumChatFormatting.GRAY + "Front Page",
+ true
+ )
+ );
+ put(
+ "second_page",
+ Utils.editItemStackInfo(
+ skull,
+ EnumChatFormatting.GRAY + "Level Page",
+ true
+ )
+ );
+ }
+ };
+
private static final ExecutorService profileLoader = Executors.newFixedThreadPool(1);
public EntityOtherPlayerMP entityPlayer = null;
private ResourceLocation playerLocationSkin = null;
@@ -88,9 +117,14 @@ public class BasicPage extends GuiProfileViewerPage {
private int backgroundClickedX = -1;
+ private boolean onSecondPage;
+
+ private final LevelPage levelPage;
+
public BasicPage(GuiProfileViewer instance) {
super(instance);
this.guiProfileViewer = instance;
+ this.levelPage = new LevelPage(guiProfileViewer, this);
}
@Override
@@ -101,6 +135,11 @@ public class BasicPage extends GuiProfileViewerPage {
int guiLeft = GuiProfileViewer.getGuiLeft();
int guiTop = GuiProfileViewer.getGuiTop();
+ if (onSecondPage) {
+ levelPage.drawPage(mouseX, mouseY);
+ return;
+ }
+
String location = null;
JsonObject status = profile.getPlayerStatus();
if (status != null && status.has("mode")) {
@@ -280,7 +319,7 @@ public class BasicPage extends GuiProfileViewerPage {
EnumChatFormatting.GREEN + "Net Worth: " + EnumChatFormatting.GOLD +
GuiProfileViewer.numberFormat.format(networth),
fr,
- guiLeft + 63,
+ guiLeft + 165,
guiTop + 38,
true,
0
@@ -297,11 +336,10 @@ public class BasicPage extends GuiProfileViewerPage {
);
String networthIRLMoney = GuiProfileViewer.numberFormat.format(Math.round(
((networthInCookies * 325) / 675) * 4.99));
- if (
- mouseX > guiLeft + 8 &&
- mouseX < guiLeft + 8 + fr.getStringWidth("Net Worth: " + GuiProfileViewer.numberFormat.format(networth))
- ) {
- if (mouseY > guiTop + 32 && mouseY < guiTop + 32 + fr.FONT_HEIGHT) {
+
+ int fontWidth = fr.getStringWidth("Net Worth: " + GuiProfileViewer.numberFormat.format(networth));
+ if (mouseX > guiLeft + 165 - fontWidth / 2 && mouseX < guiLeft + 165 + fontWidth / 2) {
+ if (mouseY > guiTop + 32 && mouseY < guiTop + 38 + fr.FONT_HEIGHT) {
getInstance().tooltipToDisplay = new ArrayList<>();
getInstance()
.tooltipToDisplay.add(
@@ -349,7 +387,7 @@ public class BasicPage extends GuiProfileViewerPage {
Utils.drawStringCentered(
EnumChatFormatting.GREEN + "Net Worth: " + stateStr,
fr,
- guiLeft + 63,
+ guiLeft + 165,
guiTop + 38,
true,
0
@@ -534,116 +572,29 @@ public class BasicPage extends GuiProfileViewerPage {
);
}
- PlayerStats.Stats stats = profile.getStats(profileId);
+ // sb lvlL
- if (stats != null) {
- Splitter splitter = Splitter.on(" ").omitEmptyStrings().limit(2);
- for (int i = 0; i < PlayerStats.defaultStatNames.length; i++) {
- String statName = PlayerStats.defaultStatNames[i];
- //if (statName.equals("mining_fortune") || statName.equals("mining_speed")) continue;
- String statNamePretty = PlayerStats.defaultStatNamesPretty[i];
+ int sbLevelX = guiLeft + 162;
+ int sbLevelY = guiTop + 90;
- int val = Math.round(stats.get(statName));
+ double skyblockLevel = profile.getSkyblockLevel(profileId);
+ EnumChatFormatting skyblockLevelColour = profile.getSkyblockLevelColour(profileId);
- GlStateManager.color(1, 1, 1, 1);
- GlStateManager.enableBlend();
- GL14.glBlendFuncSeparate(
- GL11.GL_SRC_ALPHA,
- GL11.GL_ONE_MINUS_SRC_ALPHA,
- GL11.GL_ONE,
- GL11.GL_ONE_MINUS_SRC_ALPHA
- );
- Utils.renderAlignedString(
- statNamePretty,
- EnumChatFormatting.WHITE.toString() + val,
- guiLeft + 132,
- guiTop + 21 + 11f * i,
- 80
- );
+ GlStateManager.pushMatrix();
+ GlStateManager.translate(sbLevelX, sbLevelY, 0);
+ 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
+ );
- if (mouseX > guiLeft + 132 && mouseX < guiLeft + 212) {
- if (mouseY > guiTop + 21 + 11f * i && mouseY < guiTop + 37 + 11f * i) {
- List<String> split = splitter.splitToList(statNamePretty);
- PlayerStats.Stats baseStats = PlayerStats.getBaseStats();
- getInstance().tooltipToDisplay = new ArrayList<>();
- getInstance().tooltipToDisplay.add(statNamePretty);
- int base = Math.round(baseStats.get(statName));
- getInstance()
- .tooltipToDisplay.add(
- EnumChatFormatting.GRAY +
- "Base " +
- split.get(1) +
- ": " +
- EnumChatFormatting.GREEN +
- base +
- " " +
- split.get(0)
- );
- int passive = Math.round(profile.getPassiveStats(profileId).get(statName) - baseStats.get(statName));
- getInstance()
- .tooltipToDisplay.add(
- EnumChatFormatting.GRAY +
- "Passive " +
- split.get(1) +
- " Bonus: +" +
- EnumChatFormatting.YELLOW +
- passive +
- " " +
- split.get(0)
- );
- int itemBonus = Math.round(stats.get(statName) - profile.getPassiveStats(profileId).get(statName));
- getInstance()
- .tooltipToDisplay.add(
- EnumChatFormatting.GRAY +
- "Item " +
- split.get(1) +
- " Bonus: +" +
- EnumChatFormatting.DARK_PURPLE +
- itemBonus +
- " " +
- split.get(0)
- );
- int finalStat = Math.round(stats.get(statName));
- getInstance()
- .tooltipToDisplay.add(
- EnumChatFormatting.GRAY +
- "Final " +
- split.get(1) +
- ": +" +
- EnumChatFormatting.RED +
- finalStat +
- " " +
- split.get(0)
- );
- }
- }
- }
- } else {
- Utils.drawStringCentered(
- EnumChatFormatting.RED + "Skill/Inv/Coll",
- Minecraft.getMinecraft().fontRendererObj,
- guiLeft + 172,
- guiTop + 101 - 10,
- true,
- 0
- );
- Utils.drawStringCentered(
- EnumChatFormatting.RED + "APIs not",
- Minecraft.getMinecraft().fontRendererObj,
- guiLeft + 172,
- guiTop + 101,
- true,
- 0
- );
- Utils.drawStringCentered(
- EnumChatFormatting.RED + "enabled!",
- Minecraft.getMinecraft().fontRendererObj,
- guiLeft + 172,
- guiTop + 101 + 10,
- true,
- 0
- );
- }
+ float progress = (float) (skyblockLevel - (long) skyblockLevel);
+ getInstance().renderBar(sbLevelX - 30, sbLevelY + 30, 80, progress);
+
+ Utils.drawStringScaled(EnumChatFormatting.YELLOW.toString() + (int) (progress * 100) + "/100", fr,
+ sbLevelX - 30, sbLevelY + 20, true, 0, 0.9f
+ );
if (skyblockInfo != null) {
int position = 0;
@@ -672,6 +623,12 @@ 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<>();
@@ -759,7 +716,8 @@ public class BasicPage extends GuiProfileViewerPage {
);
}
- renderWeight(mouseX, mouseY, skyblockInfo, profileInfo);
+ drawSideButtons();
+ if (NotEnoughUpdates.INSTANCE.config.profileViewer.displayWeight) renderWeight(mouseX, mouseY, skyblockInfo, profileInfo);
}
private String getIcon(String gameModeType) {
@@ -830,14 +788,13 @@ public class BasicPage extends GuiProfileViewerPage {
weight = profile.getSoopyWeightLeaderboardPosition();
}
-
Utils.drawStringCentered(
EnumChatFormatting.GREEN +
"Senither Weight: " +
EnumChatFormatting.GOLD +
GuiProfileViewer.numberFormat.format(roundToNearestInt(senitherWeight.getTotalWeight().getRaw())),
fr,
- guiLeft + 63,
+ guiLeft + 165,
guiTop + 18,
true,
0
@@ -847,7 +804,7 @@ public class BasicPage extends GuiProfileViewerPage {
"Senither Weight: " +
GuiProfileViewer.numberFormat.format(roundToNearestInt(senitherWeight.getTotalWeight().getRaw()))
);
- if (mouseX > guiLeft + 63 - textWidth / 2 && mouseX < guiLeft + 63 + textWidth / 2) {
+ if (mouseX > guiLeft + 165 - textWidth / 2 && mouseX < guiLeft + 165 + textWidth / 2) {
if (mouseY > guiTop + 12 && mouseY < guiTop + 12 + fr.FONT_HEIGHT) {
getInstance().tooltipToDisplay = new ArrayList<>();
getInstance()
@@ -905,7 +862,7 @@ public class BasicPage extends GuiProfileViewerPage {
EnumChatFormatting.GOLD +
GuiProfileViewer.numberFormat.format(roundToNearestInt(lilyWeight.getTotalWeight().getRaw())),
fr,
- guiLeft + 63,
+ guiLeft + 165,
guiTop + 28,
true,
0
@@ -914,7 +871,7 @@ public class BasicPage extends GuiProfileViewerPage {
int fontWidth = fr.getStringWidth(
"Lily Weight: " + GuiProfileViewer.numberFormat.format(roundToNearestInt(lilyWeight.getTotalWeight().getRaw()))
);
- if (mouseX > guiLeft + 63 - fontWidth / 2 && mouseX < guiLeft + 63 + fontWidth / 2) {
+ if (mouseX > guiLeft + 165 - fontWidth / 2 && mouseX < guiLeft + 165 + fontWidth / 2) {
if (mouseY > guiTop + 22 && mouseY < guiTop + 22 + fr.FONT_HEIGHT) {
getInstance().tooltipToDisplay = new ArrayList<>();
getInstance()
@@ -992,10 +949,62 @@ public class BasicPage extends GuiProfileViewerPage {
GlStateManager.setActiveTexture(OpenGlHelper.defaultTexUnit);
}
+ @Override
+ public boolean mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException {
+ super.mouseClicked(mouseX, mouseY, mouseButton);
+ int guiLeft = GuiProfileViewer.getGuiLeft();
+ int guiTop = GuiProfileViewer.getGuiTop();
+
+ int i = onSlotToChangePage(mouseX, mouseY, guiLeft, guiTop);
+ switch (i) {
+ case 1:
+ onSecondPage = false;
+ break;
+ case 2:
+ onSecondPage = true;
+ break;
+
+ default:
+ break;
+ }
+
+ return false;
+ }
+
+ public int onSlotToChangePage(int mouseX, int mouseY, int guiLeft, int guiTop) {
+ if (mouseX >= guiLeft - 29 && mouseX <= guiLeft) {
+ if (mouseY >= guiTop && mouseY <= guiTop + 28) {
+ return 1;
+ } else if (mouseY + 28 >= guiTop && mouseY <= guiTop + 28 * 2) {
+ return 2;
+ }
+ }
+ return 0;
+ }
+
public String getGameModeType(JsonObject profileInfo) {
if (profileInfo != null && profileInfo.has("game_mode")) {
return profileInfo.get("game_mode").getAsString();
}
return "";
}
+
+ public void drawSideButtons() {
+ GlStateManager.enableDepth();
+ GlStateManager.translate(0, 0, 5);
+ if (onSecondPage) {
+ Utils.drawPvSideButton(1, dungeonsModeIcons.get("second_page"), true, guiProfileViewer);
+ } else {
+ Utils.drawPvSideButton(0, dungeonsModeIcons.get("first_page"), true, guiProfileViewer);
+ }
+ GlStateManager.translate(0, 0, -3);
+
+ GlStateManager.translate(0, 0, -2);
+ if (!onSecondPage) {
+ Utils.drawPvSideButton(1, dungeonsModeIcons.get("second_page"), false, guiProfileViewer);
+ } else {
+ Utils.drawPvSideButton(0, dungeonsModeIcons.get("first_page"), false, guiProfileViewer);
+ }
+ GlStateManager.disableDepth();
+ }
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/CollectionsPage.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/CollectionsPage.java
index 554e204c..45d9370b 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/CollectionsPage.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/CollectionsPage.java
@@ -24,6 +24,7 @@ import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import io.github.moulberry.notenoughupdates.core.util.StringUtils;
import io.github.moulberry.notenoughupdates.util.Constants;
import io.github.moulberry.notenoughupdates.util.Utils;
+import io.github.moulberry.notenoughupdates.util.hypixelapi.ProfileCollectionInfo;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.item.ItemStack;
@@ -35,6 +36,9 @@ import org.lwjgl.opengl.GL11;
import java.awt.*;
import java.io.IOException;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.math.RoundingMode;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Iterator;
@@ -87,7 +91,8 @@ public class CollectionsPage extends GuiProfileViewerPage {
Minecraft.getMinecraft().getTextureManager().bindTexture(pv_cols);
Utils.drawTexturedRect(guiLeft, guiTop, getInstance().sizeX, getInstance().sizeY, GL11.GL_NEAREST);
- JsonObject collectionInfo = GuiProfileViewer.getProfile().getCollectionInfo(GuiProfileViewer.getProfileId());
+ ProfileCollectionInfo collectionInfo =
+ GuiProfileViewer.getProfile().getCollectionInfo(GuiProfileViewer.getProfileId());
if (collectionInfo == null) {
Utils.drawStringCentered(
EnumChatFormatting.RED + "Collection API not enabled!",
@@ -197,110 +202,114 @@ public class CollectionsPage extends GuiProfileViewerPage {
4210752
);
- JsonObject minionTiers = collectionInfo.get("minion_tiers").getAsJsonObject();
- JsonObject collectionTiers = collectionInfo.get("collection_tiers").getAsJsonObject();
- JsonObject maxAmounts = collectionInfo.get("max_amounts").getAsJsonObject();
- JsonObject totalAmounts = collectionInfo.get("total_amounts").getAsJsonObject();
- JsonObject personalAmounts = collectionInfo.get("personal_amounts").getAsJsonObject();
-
if (collections != null) {
for (int i = page * 20, j = 0; i < Math.min((page + 1) * 20, collections.size()); i++, j++) {
String collection = collections.get(i);
- if (collection != null) {
- ItemStack collectionItem = ProfileViewer.getCollectionToCollectionDisplayMap().get(collection);
- if (collectionItem != null) {
- int xIndex = j % COLLS_XCOUNT;
- int yIndex = j / COLLS_XCOUNT;
-
- float x = 39 + COLLS_XPADDING + (COLLS_XPADDING + 20) * xIndex;
- float y = 7 + COLLS_YPADDING + (COLLS_YPADDING + 20) * yIndex;
-
- String tierString;
- int tier = (int) Utils.getElementAsFloat(collectionTiers.get(collection), 0);
- if (tier > 20 || tier < 0) {
- tierString = String.valueOf(tier);
- } else {
- tierString = romans[tier];
- }
- float amount = Utils.getElementAsFloat(totalAmounts.get(collection), 0);
- float maxAmount = Utils.getElementAsFloat(maxAmounts.get(collection), 0);
- Color color = new Color(128, 128, 128, 255);
- int tierStringColour = color.getRGB();
- float completedness = 0;
- if (maxAmount > 0) {
- completedness = amount / maxAmount;
- }
- completedness = Math.min(1, completedness);
- if (maxAmounts.has(collection) && completedness >= 1) {
- tierStringColour = new Color(255, 215, 0).getRGB();
- }
-
- GlStateManager.color(1, 1, 1, 1);
- Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements);
- Utils.drawTexturedRect(
- guiLeft + x,
- guiTop + y,
- 20,
- 20 * (1 - completedness),
- 0,
- 20 / 256f,
- 0,
- 20 * (1 - completedness) / 256f,
- GL11.GL_NEAREST
- );
- GlStateManager.color(1, 185 / 255f, 0, 1);
- Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements);
- Utils.drawTexturedRect(
- guiLeft + x,
- guiTop + y + 20 * (1 - completedness),
- 20,
- 20 * (completedness),
- 0,
- 20 / 256f,
- 20 * (1 - completedness) / 256f,
- 20 / 256f,
- GL11.GL_NEAREST
+ if (collection == null) {
+ continue;
+ }
+ ProfileCollectionInfo.CollectionInfo thisCollection = collectionInfo.getCollections().get(collection);
+ if (thisCollection == null) {
+ Utils.showOutdatedRepoNotification();
+ continue;
+ }
+ ItemStack collectionItem = ProfileViewer.getCollectionToCollectionDisplayMap().get(collection);
+ if (collectionItem == null) {
+ continue;
+ }
+ int xIndex = j % COLLS_XCOUNT;
+ int yIndex = j / COLLS_XCOUNT;
+
+ float x = 39 + COLLS_XPADDING + (COLLS_XPADDING + 20) * xIndex;
+ float y = 7 + COLLS_YPADDING + (COLLS_YPADDING + 20) * yIndex;
+
+ String tierString;
+ int tier = thisCollection.getUnlockedTiers().size();
+ if (tier > 20 || tier == 0) {
+ tierString = String.valueOf(tier);
+ } else {
+ tierString = romans[tier - 1];
+ }
+ BigInteger amount = thisCollection.getTotalCollectionCount();
+ BigInteger maxAmount = BigInteger.valueOf(thisCollection.getCollection().getTiers().get(thisCollection.getCollection().getTiers().size() - 1).getAmountRequired());
+ Color color = new Color(128, 128, 128, 255);
+ int tierStringColour = color.getRGB();
+ float completedness = 0;
+ if (maxAmount.compareTo(BigInteger.ZERO) > 0) {
+ if (amount.compareTo(maxAmount) > 0) {
+ completedness = 1;
+ } else {
+ completedness = amount.floatValue() / maxAmount.floatValue();
+ }
+ }
+ if (completedness >= 1) {
+ tierStringColour = new Color(255, 215, 0).getRGB();
+ }
+
+ GlStateManager.color(1, 1, 1, 1);
+ Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements);
+ Utils.drawTexturedRect(
+ guiLeft + x,
+ guiTop + y,
+ 20,
+ 20 * (1 - completedness),
+ 0,
+ 20 / 256f,
+ 0,
+ 20 * (1 - completedness) / 256f,
+ GL11.GL_NEAREST
+ );
+ GlStateManager.color(1, 185 / 255f, 0, 1);
+ Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements);
+ Utils.drawTexturedRect(
+ guiLeft + x,
+ guiTop + y + 20 * (1 - completedness),
+ 20,
+ 20 * (completedness),
+ 0,
+ 20 / 256f,
+ 20 * (1 - completedness) / 256f,
+ 20 / 256f,
+ GL11.GL_NEAREST
+ );
+ Utils.drawItemStack(collectionItem, guiLeft + (int) x + 2, guiTop + (int) y + 2);
+
+ if (mouseX > guiLeft + (int) x + 2 && mouseX < guiLeft + (int) x + 18) {
+ if (mouseY > guiTop + (int) y + 2 && mouseY < guiTop + (int) y + 18) {
+ tooltipToDisplay = new ArrayList<>();
+ tooltipToDisplay.add(
+ collectionItem.getDisplayName() +
+ " " +
+ (completedness >= 1 ? EnumChatFormatting.GOLD : EnumChatFormatting.GRAY) +
+ tierString
);
- Utils.drawItemStack(collectionItem, guiLeft + (int) x + 2, guiTop + (int) y + 2);
-
- if (mouseX > guiLeft + (int) x + 2 && mouseX < guiLeft + (int) x + 18) {
- if (mouseY > guiTop + (int) y + 2 && mouseY < guiTop + (int) y + 18) {
- tooltipToDisplay = new ArrayList<>();
- tooltipToDisplay.add(
- collectionItem.getDisplayName() +
- " " +
- (completedness >= 1 ? EnumChatFormatting.GOLD : EnumChatFormatting.GRAY) +
- tierString
- );
- tooltipToDisplay.add(
- "Collected: " + numberFormat.format(Utils.getElementAsFloat(personalAmounts.get(collection), 0))
- );
- tooltipToDisplay.add("Total Collected: " + numberFormat.format(amount));
- }
- }
-
- GlStateManager.color(1, 1, 1, 1);
- if (tier >= 0) {
- Utils.drawStringCentered(
- tierString,
- Minecraft.getMinecraft().fontRendererObj,
- guiLeft + x + 10,
- guiTop + y - 4,
- true,
- tierStringColour
- );
- }
-
- Utils.drawStringCentered(
- StringUtils.shortNumberFormat(amount) + "",
- Minecraft.getMinecraft().fontRendererObj,
- guiLeft + x + 10,
- guiTop + y + 26,
- true,
- color.getRGB()
+ tooltipToDisplay.add(
+ "Collected: " + numberFormat.format(thisCollection.getPersonalCollectionCount())
);
+ tooltipToDisplay.add("Total Collected: " + numberFormat.format(amount));
}
}
+
+ GlStateManager.color(1, 1, 1, 1);
+ if (tier >= 0) {
+ Utils.drawStringCentered(
+ tierString,
+ Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + x + 10,
+ guiTop + y - 4,
+ true,
+ tierStringColour
+ );
+ }
+
+ Utils.drawStringCentered(
+ StringUtils.shortNumberFormat(amount) + "",
+ Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + x + 10,
+ guiTop + y + 26,
+ true,
+ color.getRGB()
+ );
}
}
@@ -316,97 +325,99 @@ public class CollectionsPage extends GuiProfileViewerPage {
if (minions != null) {
for (int i = page * 20, j = 0; i < Math.min((page + 1) * 20, minions.size()); i++, j++) {
String minion = minions.get(i);
- if (minion != null) {
- JsonObject misc = Constants.MISC;
- float MAX_MINION_TIER = Utils.getElementAsFloat(Utils.getElement(misc, "minions." + minion + "_GENERATOR"), 11);
-
- int tier = (int) Utils.getElementAsFloat(minionTiers.get(minion), 0);
- JsonObject minionJson;
- if (tier == 0) {
- minionJson = NotEnoughUpdates.INSTANCE.manager.getItemInformation().get(minion + "_GENERATOR_1");
- } else {
- minionJson = NotEnoughUpdates.INSTANCE.manager.getItemInformation().get(minion + "_GENERATOR_" + tier);
- }
+ if (minion == null) {
+ continue;
+ }
+ JsonObject misc = Constants.MISC;
+ float MAX_MINION_TIER = Utils.getElementAsFloat(Utils.getElement(misc, "minions." + minion + "_GENERATOR"), 11);
- if (minionJson != null) {
- int xIndex = j % COLLS_XCOUNT;
- int yIndex = j / COLLS_XCOUNT;
-
- float x = 231 + COLLS_XPADDING + (COLLS_XPADDING + 20) * xIndex;
- float y = 7 + COLLS_YPADDING + (COLLS_YPADDING + 20) * yIndex;
-
- String tierString;
-
- if (tier - 1 >= romans.length || tier - 1 < 0) {
- tierString = String.valueOf(tier);
- } else {
- tierString = romans[tier - 1];
- }
-
- Color color = new Color(128, 128, 128, 255);
- int tierStringColour = color.getRGB();
- float completedness = tier / MAX_MINION_TIER;
-
- completedness = Math.min(1, completedness);
- if (completedness >= 1) {
- tierStringColour = new Color(255, 215, 0).getRGB();
- }
-
- GlStateManager.color(1, 1, 1, 1);
- Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements);
- Utils.drawTexturedRect(
- guiLeft + x,
- guiTop + y,
- 20,
- 20 * (1 - completedness),
- 0,
- 20 / 256f,
- 0,
- 20 * (1 - completedness) / 256f,
- GL11.GL_NEAREST
- );
- GlStateManager.color(1, 185 / 255f, 0, 1);
- Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements);
- Utils.drawTexturedRect(
- guiLeft + x,
- guiTop + y + 20 * (1 - completedness),
- 20,
- 20 * (completedness),
- 0,
- 20 / 256f,
- 20 * (1 - completedness) / 256f,
- 20 / 256f,
- GL11.GL_NEAREST
- );
+ int tier = collectionInfo.getCraftedGenerators().getOrDefault(minion, 0);
+ JsonObject minionJson;
+ if (tier == 0) {
+ minionJson = NotEnoughUpdates.INSTANCE.manager.getItemInformation().get(minion + "_GENERATOR_1");
+ } else {
+ minionJson = NotEnoughUpdates.INSTANCE.manager.getItemInformation().get(minion + "_GENERATOR_" + tier);
+ }
- Utils.drawItemStack(
- NotEnoughUpdates.INSTANCE.manager.jsonToStack(minionJson),
- guiLeft + (int) x + 2,
- guiTop + (int) y + 2
- );
+ if (minionJson == null) {
+ continue;
+ }
+ int xIndex = j % COLLS_XCOUNT;
+ int yIndex = j / COLLS_XCOUNT;
+
+ float x = 231 + COLLS_XPADDING + (COLLS_XPADDING + 20) * xIndex;
+ float y = 7 + COLLS_YPADDING + (COLLS_YPADDING + 20) * yIndex;
+
+ String tierString;
+
+ if (tier - 1 >= romans.length || tier - 1 < 0) {
+ tierString = String.valueOf(tier);
+ } else {
+ tierString = romans[tier - 1];
+ }
+
+ Color color = new Color(128, 128, 128, 255);
+ int tierStringColour = color.getRGB();
+ float completedness = tier / MAX_MINION_TIER;
+
+ completedness = Math.min(1, completedness);
+ if (completedness >= 1) {
+ tierStringColour = new Color(255, 215, 0).getRGB();
+ }
- if (mouseX > guiLeft + (int) x + 2 && mouseX < guiLeft + (int) x + 18) {
- if (mouseY > guiTop + (int) y + 2 && mouseY < guiTop + (int) y + 18) {
- tooltipToDisplay =
- NotEnoughUpdates.INSTANCE.manager
- .jsonToStack(minionJson)
- .getTooltip(Minecraft.getMinecraft().thePlayer, false);
- }
- }
-
- GlStateManager.color(1, 1, 1, 1);
- if (tier >= 0) {
- Utils.drawStringCentered(
- tierString,
- Minecraft.getMinecraft().fontRendererObj,
- guiLeft + x + 10,
- guiTop + y - 4,
- true,
- tierStringColour
- );
- }
+ GlStateManager.color(1, 1, 1, 1);
+ Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements);
+ Utils.drawTexturedRect(
+ guiLeft + x,
+ guiTop + y,
+ 20,
+ 20 * (1 - completedness),
+ 0,
+ 20 / 256f,
+ 0,
+ 20 * (1 - completedness) / 256f,
+ GL11.GL_NEAREST
+ );
+ GlStateManager.color(1, 185 / 255f, 0, 1);
+ Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements);
+ Utils.drawTexturedRect(
+ guiLeft + x,
+ guiTop + y + 20 * (1 - completedness),
+ 20,
+ 20 * (completedness),
+ 0,
+ 20 / 256f,
+ 20 * (1 - completedness) / 256f,
+ 20 / 256f,
+ GL11.GL_NEAREST
+ );
+
+ Utils.drawItemStack(
+ NotEnoughUpdates.INSTANCE.manager.jsonToStack(minionJson),
+ guiLeft + (int) x + 2,
+ guiTop + (int) y + 2
+ );
+
+ if (mouseX > guiLeft + (int) x + 2 && mouseX < guiLeft + (int) x + 18) {
+ if (mouseY > guiTop + (int) y + 2 && mouseY < guiTop + (int) y + 18) {
+ tooltipToDisplay =
+ NotEnoughUpdates.INSTANCE.manager
+ .jsonToStack(minionJson)
+ .getTooltip(Minecraft.getMinecraft().thePlayer, false);
}
}
+
+ GlStateManager.color(1, 1, 1, 1);
+ if (tier >= 0) {
+ Utils.drawStringCentered(
+ tierString,
+ Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + x + 10,
+ guiTop + y - 4,
+ true,
+ tierStringColour
+ );
+ }
}
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/CrimsonIslePage.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/CrimsonIslePage.java
index 95009b1d..6460003a 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/CrimsonIslePage.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/CrimsonIslePage.java
@@ -55,15 +55,12 @@ public class CrimsonIslePage extends GuiProfileViewerPage {
NotEnoughUpdates.INSTANCE.manager.createItem("KUUDRA_INFERNAL_TIER_KEY"),
};
- public static final String[] KUUDRA_TIERS = {
- "Basic",
- "Hot",
- "Burning",
- "Fiery",
- "Infernal"
- };
+ private static final String[] KUUDRA_TIERS_NAME = {"Basic", "Hot", "Burning", "Fiery", "Infernal"};
+
+ // This is different to the one above as these refer to the names of the tiers in the API
+ public static final String[] KUUDRA_TIERS = {"none", "hot", "burning", "fiery", "infernal"};
- private static final LinkedHashMap<String, String> apiDojoTestNames = new LinkedHashMap<String, String>() {{
+ public static final LinkedHashMap<String, String> apiDojoTestNames = new LinkedHashMap<String, String>() {{
put("mob_kb", EnumChatFormatting.GOLD + "Test of Force");
put("wall_jump", EnumChatFormatting.LIGHT_PURPLE + "Test of Stamina");
put("archer", EnumChatFormatting.YELLOW + "Test of Mastery");
@@ -73,7 +70,7 @@ public class CrimsonIslePage extends GuiProfileViewerPage {
put("fireball", EnumChatFormatting.GOLD + "Test of Tenacity");
}};
- private static final LinkedHashMap<Integer, String> dojoPointsToRank = new LinkedHashMap<Integer, String>() {{
+ public static final LinkedHashMap<Integer, String> dojoPointsToRank = new LinkedHashMap<Integer, String>() {{
put(0, EnumChatFormatting.GRAY + "None");
put(1000, EnumChatFormatting.YELLOW + "Yellow");
put(2000, EnumChatFormatting.GREEN + "Green");
@@ -151,21 +148,18 @@ public class CrimsonIslePage extends GuiProfileViewerPage {
JsonObject kuudraCompletedTiers = data.getAsJsonObject("kuudra_completed_tiers");
- // This is different to the one initialised at the start of the class as these refer to the names of the tiers in the API
- String[] kuudraTiers = {"none", "hot", "burning", "fiery", "infernal"};
-
RenderHelper.enableGUIStandardItemLighting();
for (int i = 0; i < 5; i++) {
// Checking the player has completions for each tier
// and get the number of completions if they do
int completions =
- kuudraCompletedTiers.has(kuudraTiers[i]) ? kuudraCompletedTiers.get(kuudraTiers[i]).getAsInt() : 0;
+ kuudraCompletedTiers.has(KUUDRA_TIERS[i]) ? kuudraCompletedTiers.get(KUUDRA_TIERS[i]).getAsInt() : 0;
// Get the highest wave for this tier of kuudra if they have completed a run
// since infernal kuudra was released
- int highestWaveCompleted = kuudraCompletedTiers.has("highest_wave_" + kuudraTiers[i]) ?
- kuudraCompletedTiers.get("highest_wave_" + kuudraTiers[i]).getAsInt() : 0;
+ int highestWaveCompleted = kuudraCompletedTiers.has("highest_wave_" + KUUDRA_TIERS[i]) ?
+ kuudraCompletedTiers.get("highest_wave_" + KUUDRA_TIERS[i]).getAsInt() : 0;
Minecraft.getMinecraft().getRenderItem().renderItemIntoGUI(
KUUDRA_KEYS[i],
@@ -174,7 +168,7 @@ public class CrimsonIslePage extends GuiProfileViewerPage {
);
Utils.renderAlignedString(
- EnumChatFormatting.RED + KUUDRA_TIERS[i] + ": ",
+ EnumChatFormatting.RED + KUUDRA_TIERS_NAME[i] + ": ",
EnumChatFormatting.WHITE + String.valueOf(completions),
guiLeft + 23,
guiTop + 30 + (i * 30),
@@ -190,7 +184,8 @@ public class CrimsonIslePage extends GuiProfileViewerPage {
);
if (highestWaveCompleted == 0) {
- if (mouseX > guiLeft + 23 && mouseX < guiLeft + 133 && mouseY < guiTop + 50 + (i*30) && mouseY > guiTop + 42 + (i*30)) {
+ if (mouseX > guiLeft + 23 && mouseX < guiLeft + 133 && mouseY < guiTop + 50 + (i * 30) &&
+ mouseY > guiTop + 42 + (i * 30)) {
getInstance().tooltipToDisplay = new ArrayList<>();
getInstance().tooltipToDisplay.add(EnumChatFormatting.RED + "N/A will only show for highest wave");
getInstance().tooltipToDisplay.add(EnumChatFormatting.RED + "if you have not completed a run for");
@@ -278,7 +273,7 @@ public class CrimsonIslePage extends GuiProfileViewerPage {
);
}
- public String getRank(int points) {
+ public static String getRank(int points) {
int lastRank = 0;
for (Map.Entry<Integer, String> rank : dojoPointsToRank.entrySet()) {
if (points < rank.getKey()) {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/DungeonPage.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/DungeonPage.java
index cbebb6f4..9d227daf 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/DungeonPage.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/DungeonPage.java
@@ -42,7 +42,6 @@ import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.ResourceLocation;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.GL11;
-import org.lwjgl.opengl.GL14;
import java.io.IOException;
import java.util.Base64;
@@ -54,7 +53,7 @@ public class DungeonPage extends GuiProfileViewerPage {
private static final ResourceLocation pv_dung = new ResourceLocation("notenoughupdates:pv_dung.png");
private static final ItemStack DEADBUSH = new ItemStack(Item.getItemFromBlock(Blocks.deadbush));
- private static final String[] dungSkillsName = { "Healer", "Mage", "Berserk", "Archer", "Tank" };
+ private static final String[] dungSkillsName = {"Healer", "Mage", "Berserk", "Archer", "Tank"};
private static final ItemStack[] BOSS_HEADS = new ItemStack[7];
private static final ItemStack[] dungSkillsStack = {
new ItemStack(Items.potionitem, 1, 16389),
@@ -63,7 +62,7 @@ public class DungeonPage extends GuiProfileViewerPage {
new ItemStack(Items.bow),
new ItemStack(Items.leather_chestplate),
};
- private static final String[] bossFloorArr = { "Bonzo", "Scarf", "Professor", "Thorn", "Livid", "Sadan", "Necron" };
+ private static final String[] bossFloorArr = {"Bonzo", "Scarf", "Professor", "Thorn", "Livid", "Sadan", "Necron"};
private static final String[] bossFloorHeads = {
"12716ecbf5b8da00b05f316ec6af61e8bd02805b21eb8e440151468dc656549c",
"7de7bbbdf22bfe17980d4e20687e386f11d59ee1db6f8b4762391b79a5ac532d",
@@ -145,7 +144,7 @@ public class DungeonPage extends GuiProfileViewerPage {
//Catacombs level thingy
{
if (levelObjCata == null) {
- float cataXp = Utils.getElementAsFloat(Utils.getElement(profileInfo, "dungeons.dungeon_types.catacombs.experience"), 0);
+ float cataXp = getElementAsFloat(profileInfo, "dungeons.dungeon_types.catacombs.experience");
levelObjCata =
ProfileViewer.getLevel(
Utils.getElementOrDefault(leveling, "catacombs", new JsonArray()).getAsJsonArray(),
@@ -181,11 +180,20 @@ public class DungeonPage extends GuiProfileViewerPage {
if (mouseX > x && mouseX < x + sectionWidth && mouseY > y + 16 && mouseY < y + 24 && !onMasterMode) {
float F5 =
- (Utils.getElementAsFloat(Utils.getElement(profileInfo, "dungeons.dungeon_types.catacombs.tier_completions." + 5), 0)); //this can prob be done better
+ (Utils.getElementAsFloat(Utils.getElement(
+ profileInfo,
+ "dungeons.dungeon_types.catacombs.tier_completions." + 5
+ ), 0)); //this can prob be done better
float F6 =
- (Utils.getElementAsFloat(Utils.getElement(profileInfo, "dungeons.dungeon_types.catacombs.tier_completions." + 6), 0));
+ (Utils.getElementAsFloat(Utils.getElement(
+ profileInfo,
+ "dungeons.dungeon_types.catacombs.tier_completions." + 6
+ ), 0));
float F7 =
- (Utils.getElementAsFloat(Utils.getElement(profileInfo, "dungeons.dungeon_types.catacombs.tier_completions." + 7), 0));
+ (Utils.getElementAsFloat(Utils.getElement(
+ profileInfo,
+ "dungeons.dungeon_types.catacombs.tier_completions." + 7
+ ), 0));
if (F5 > 150) {
F5 = 150;
}
@@ -208,43 +216,23 @@ public class DungeonPage extends GuiProfileViewerPage {
long runsF6 = (int) Math.ceil(floorLevelToXP / xpF6);
long runsF7 = (int) Math.ceil(floorLevelToXP / xpF7);
- float timeF5 = Utils.getElementAsFloat(
- Utils.getElement(profileInfo, "dungeons.dungeon_types.catacombs.fastest_time_s_plus.5"),
- 0
- );
- float timeF6 = Utils.getElementAsFloat(
- Utils.getElement(profileInfo, "dungeons.dungeon_types.catacombs.fastest_time_s_plus.6"),
- 0
- );
- float timeF7 = Utils.getElementAsFloat(
- Utils.getElement(profileInfo, "dungeons.dungeon_types.catacombs.fastest_time_s_plus.7"),
- 0
- );
+ float timeF5 = getElementAsFloat(profileInfo, "dungeons.dungeon_types.catacombs.fastest_time_s_plus.5");
+ float timeF6 = getElementAsFloat(profileInfo, "dungeons.dungeon_types.catacombs.fastest_time_s_plus.6");
+ float timeF7 = getElementAsFloat(profileInfo, "dungeons.dungeon_types.catacombs.fastest_time_s_plus.7");
getInstance().tooltipToDisplay =
Lists.newArrayList(
- EnumChatFormatting.YELLOW + "Remaining XP: " + EnumChatFormatting.GRAY + String.format("%,d", floorLevelToXP),
+ EnumChatFormatting.YELLOW + "Remaining XP: " + EnumChatFormatting.GRAY +
+ String.format("%,d", floorLevelToXP),
String.format("# F5 Runs (%s xp) : %d", StringUtils.shortNumberFormat(xpF5), runsF5),
String.format("# F6 Runs (%s xp) : %d", StringUtils.shortNumberFormat(xpF6), runsF6),
String.format("# F7 Runs (%s xp) : %d", StringUtils.shortNumberFormat(xpF7), runsF7),
""
);
boolean hasTime = false;
- if (timeF5 > 1000) {
- getInstance()
- .tooltipToDisplay.add(String.format("Expected Time (F5) : %s", Utils.prettyTime(runsF5 * (long) (timeF5 * 1.2))));
- hasTime = true;
- }
- if (timeF6 > 1000) {
- getInstance()
- .tooltipToDisplay.add(String.format("Expected Time (F6) : %s", Utils.prettyTime(runsF6 * (long) (timeF6 * 1.2))));
- hasTime = true;
- }
- if (timeF7 > 1000) {
- getInstance()
- .tooltipToDisplay.add(String.format("Expected Time (F7) : %s", Utils.prettyTime(runsF7 * (long) (timeF7 * 1.2))));
- hasTime = true;
- }
+ hasTime = isHasTime(timeF5, "Expected Time (F5) : %s", runsF5, hasTime);
+ hasTime = isHasTime(timeF6, "Expected Time (F6) : %s", runsF6, hasTime);
+ hasTime = isHasTime(timeF7, "Expected Time (F7) : %s", runsF7, hasTime);
if (hasTime) {
getInstance().tooltipToDisplay.add("");
}
@@ -261,19 +249,20 @@ public class DungeonPage extends GuiProfileViewerPage {
getInstance()
.tooltipToDisplay.add(
"The " +
- EnumChatFormatting.DARK_PURPLE +
- "Catacombs Expert Ring" +
- EnumChatFormatting.GRAY +
- " is assumed to be used, unless " +
- EnumChatFormatting.YELLOW +
- "SHIFT" +
- EnumChatFormatting.GRAY +
- " is held."
+ EnumChatFormatting.DARK_PURPLE +
+ "Catacombs Expert Ring" +
+ EnumChatFormatting.GRAY +
+ " is assumed to be used, unless " +
+ EnumChatFormatting.YELLOW +
+ "SHIFT" +
+ EnumChatFormatting.GRAY +
+ " is held."
);
getInstance().tooltipToDisplay.add("[Time per run] is calculated using Fastest S+ x 120%");
} else {
getInstance()
- .tooltipToDisplay.add("[Hold " + EnumChatFormatting.YELLOW + "CTRL" + EnumChatFormatting.GRAY + " to see details]");
+ .tooltipToDisplay.add(
+ "[Hold " + EnumChatFormatting.YELLOW + "CTRL" + EnumChatFormatting.GRAY + " to see details]");
}
}
@@ -348,63 +337,29 @@ public class DungeonPage extends GuiProfileViewerPage {
long runsM6 = (int) Math.ceil(floorLevelToXP / xpM6);
long runsM7 = (int) Math.ceil(floorLevelToXP / xpM7);
- float timeM3 = Utils.getElementAsFloat(
- Utils.getElement(profileInfo, "dungeons.dungeon_types.master_catacombs.fastest_time_s_plus.3"),
- 0
- );
- float timeM4 = Utils.getElementAsFloat(
- Utils.getElement(profileInfo, "dungeons.dungeon_types.master_catacombs.fastest_time_s_plus.4"),
- 0
- );
- float timeM5 = Utils.getElementAsFloat(
- Utils.getElement(profileInfo, "dungeons.dungeon_types.master_catacombs.fastest_time_s_plus.5"),
- 0
- );
- float timeM6 = Utils.getElementAsFloat(
- Utils.getElement(profileInfo, "dungeons.dungeon_types.master_catacombs.fastest_time_s_plus.6"),
- 0
- );
- float timeM7 = Utils.getElementAsFloat(
- Utils.getElement(profileInfo, "dungeons.dungeon_types.master_catacombs.fastest_time_s_plus.7"),
- 0
- );
+ float timeM3 = getElementAsFloat(profileInfo, "dungeons.dungeon_types.master_catacombs.fastest_time_s_plus.3");
+ float timeM4 = getElementAsFloat(profileInfo, "dungeons.dungeon_types.master_catacombs.fastest_time_s_plus.4");
+ float timeM5 = getElementAsFloat(profileInfo, "dungeons.dungeon_types.master_catacombs.fastest_time_s_plus.5");
+ float timeM6 = getElementAsFloat(profileInfo, "dungeons.dungeon_types.master_catacombs.fastest_time_s_plus.6");
+ float timeM7 = getElementAsFloat(profileInfo, "dungeons.dungeon_types.master_catacombs.fastest_time_s_plus.7");
getInstance().tooltipToDisplay =
Lists.newArrayList(
- EnumChatFormatting.YELLOW + "Remaining XP: " + EnumChatFormatting.GRAY + String.format("%,d", floorLevelToXP),
+ EnumChatFormatting.YELLOW + "Remaining XP: " + EnumChatFormatting.GRAY +
+ String.format("%,d", floorLevelToXP),
String.format("# M3 Runs (%s xp) : %d", StringUtils.shortNumberFormat(xpM3), runsM3),
String.format("# M4 Runs (%s xp) : %d", StringUtils.shortNumberFormat(xpM4), runsM4),
String.format("# M5 Runs (%s xp) : %d", StringUtils.shortNumberFormat(xpM5), runsM5),
String.format("# M6 Runs (%s xp) : %d", StringUtils.shortNumberFormat(xpM6), runsM6),
- String.format("# M7 Runs (%s xp) : %d", StringUtils.shortNumberFormat(xpM7), runsM7),
+ String.format("# M7 Runs (%s xp) : %d", StringUtils.shortNumberFormat(xpM7), runsM7),
""
);
boolean hasTime = false;
- if (timeM3 > 1000) {
- getInstance()
- .tooltipToDisplay.add(String.format("Expected Time (M3) : %s", Utils.prettyTime(runsM3 * (long) (timeM3 * 1.2))));
- hasTime = true;
- }
- if (timeM4 > 1000) {
- getInstance()
- .tooltipToDisplay.add(String.format("Expected Time (M4) : %s", Utils.prettyTime(runsM4 * (long) (timeM4 * 1.2))));
- hasTime = true;
- }
- if (timeM5 > 1000) {
- getInstance()
- .tooltipToDisplay.add(String.format("Expected Time (M5) : %s", Utils.prettyTime(runsM5 * (long) (timeM5 * 1.2))));
- hasTime = true;
- }
- if (timeM6 > 1000) {
- getInstance()
- .tooltipToDisplay.add(String.format("Expected Time (M6) : %s", Utils.prettyTime(runsM6 * (long) (timeM6 * 1.2))));
- hasTime = true;
- }
- if (timeM7 > 1000) {
- getInstance()
- .tooltipToDisplay.add(String.format("Expected Time (M7) : %s", Utils.prettyTime(runsM7 * (long) (timeM7 * 1.2))));
- hasTime = true;
- }
+ hasTime = isHasTime(timeM3, "Expected Time (M3) : %s", runsM3, hasTime);
+ hasTime = isHasTime(timeM4, "Expected Time (M4) : %s", runsM4, hasTime);
+ hasTime = isHasTime(timeM5, "Expected Time (M5) : %s", runsM5, hasTime);
+ hasTime = isHasTime(timeM6, "Expected Time (M6) : %s", runsM6, hasTime);
+ hasTime = isHasTime(timeM7, "Expected Time (M7) : %s", runsM7, hasTime);
if (hasTime) {
getInstance().tooltipToDisplay.add("");
}
@@ -421,26 +376,32 @@ public class DungeonPage extends GuiProfileViewerPage {
getInstance()
.tooltipToDisplay.add(
"The " +
- EnumChatFormatting.DARK_PURPLE +
- "Catacombs Expert Ring" +
- EnumChatFormatting.GRAY +
- " is assumed to be used, unless " +
- EnumChatFormatting.YELLOW +
- "SHIFT" +
- EnumChatFormatting.GRAY +
- " is held."
+ EnumChatFormatting.DARK_PURPLE +
+ "Catacombs Expert Ring" +
+ EnumChatFormatting.GRAY +
+ " is assumed to be used, unless " +
+ EnumChatFormatting.YELLOW +
+ "SHIFT" +
+ EnumChatFormatting.GRAY +
+ " is held."
);
getInstance().tooltipToDisplay.add("[Time per run] is calculated using Fastest S+ x 120%");
} else {
getInstance()
- .tooltipToDisplay.add("[Hold " + EnumChatFormatting.YELLOW + "CTRL" + EnumChatFormatting.GRAY + " to see details]");
+ .tooltipToDisplay.add(
+ "[Hold " + EnumChatFormatting.YELLOW + "CTRL" + EnumChatFormatting.GRAY + " to see details]");
}
}
dungeonLevelTextField.setSize(20, 10);
dungeonLevelTextField.render(x + 22, y + 29);
int calcLen = fontRendererObj.getStringWidth("Calculate");
- Utils.renderShadowedString(EnumChatFormatting.WHITE + "Calculate", x + sectionWidth - 17 - calcLen / 2f, y + 30, 100);
+ Utils.renderShadowedString(
+ EnumChatFormatting.WHITE + "Calculate",
+ x + sectionWidth - 17 - calcLen / 2f,
+ y + 30,
+ 100
+ );
//Random stats
@@ -451,10 +412,7 @@ public class DungeonPage extends GuiProfileViewerPage {
float totalRunsF = 0;
float totalRunsF5 = 0;
for (int i = 1; i <= 7; i++) {
- float runs = Utils.getElementAsFloat(
- Utils.getElement(profileInfo, "dungeons.dungeon_types.catacombs.tier_completions." + i),
- 0
- );
+ float runs = getElementAsFloat(profileInfo, "dungeons.dungeon_types.catacombs.tier_completions." + i);
totalRunsF += runs;
if (i >= 5) {
totalRunsF5 += runs;
@@ -463,10 +421,7 @@ public class DungeonPage extends GuiProfileViewerPage {
float totalRunsM = 0;
float totalRunsM5 = 0;
for (int i = 1; i <= 7; i++) {
- float runs = Utils.getElementAsFloat(
- Utils.getElement(profileInfo, "dungeons.dungeon_types.master_catacombs.tier_completions." + i),
- 0
- );
+ float runs = getElementAsFloat(profileInfo, "dungeons.dungeon_types.master_catacombs.tier_completions." + i);
totalRunsM += runs;
if (i >= 5) {
totalRunsM5 += runs;
@@ -477,18 +432,12 @@ public class DungeonPage extends GuiProfileViewerPage {
float mobKills;
float mobKillsF = 0;
for (int i = 1; i <= 7; i++) {
- float kills = Utils.getElementAsFloat(
- Utils.getElement(profileInfo, "dungeons.dungeon_types.catacombs.mobs_killed." + i),
- 0
- );
+ float kills = getElementAsFloat(profileInfo, "dungeons.dungeon_types.catacombs.mobs_killed." + i);
mobKillsF += kills;
}
float mobKillsM = 0;
for (int i = 1; i <= 7; i++) {
- float kills = Utils.getElementAsFloat(
- Utils.getElement(profileInfo, "dungeons.dungeon_types.master_catacombs.mobs_killed." + i),
- 0
- );
+ float kills = getElementAsFloat(profileInfo, "dungeons.dungeon_types.master_catacombs.mobs_killed." + i);
mobKillsM += kills;
}
mobKills = mobKillsF + mobKillsM;
@@ -518,7 +467,8 @@ public class DungeonPage extends GuiProfileViewerPage {
);
Utils.renderAlignedString(
EnumChatFormatting.YELLOW + "Secrets (/Run) ",
- EnumChatFormatting.WHITE.toString() + (secrets == -1 ? "?" : (Math.round(secrets / Math.max(1, totalRuns) * 100) / 100f)),
+ EnumChatFormatting.WHITE.toString() + (secrets == -1 ? "?" : (Math.round(
+ secrets / Math.max(1, totalRuns) * 100) / 100f)),
x,
miscTopY + 30,
sectionWidth
@@ -538,40 +488,16 @@ public class DungeonPage extends GuiProfileViewerPage {
int bx = x + sectionWidth * i / 8 - w / 2;
- boolean invert = i == floorTime;
- float uMin = 20 / 256f;
- float uMax = 29 / 256f;
- float vMin = 0 / 256f;
- float vMax = 11 / 256f;
-
GlStateManager.color(1, 1, 1, 1);
- Minecraft.getMinecraft().getTextureManager().bindTexture(GuiProfileViewer.pv_elements);
- Utils.drawTexturedRect(
- bx - 2,
- y3 - 2,
- 9,
- 11,
- invert ? uMax : uMin,
- invert ? uMin : uMax,
- invert ? vMax : vMin,
- invert ? vMin : vMax,
- GL11.GL_NEAREST
- );
Utils.renderShadowedString(EnumChatFormatting.WHITE.toString() + i, bx + w / 2, y3, 10);
}
- float timeNorm = Utils.getElementAsFloat(
- Utils.getElement(profileInfo, "dungeons.dungeon_types." + dungeonString + ".fastest_time." + floorTime),
- 0
- );
- float timeS = Utils.getElementAsFloat(
- Utils.getElement(profileInfo, "dungeons.dungeon_types." + dungeonString + ".fastest_time_s." + floorTime),
- 0
- );
- float timeSPLUS = Utils.getElementAsFloat(
- Utils.getElement(profileInfo, "dungeons.dungeon_types." + dungeonString + ".fastest_time_s_plus." + floorTime),
- 0
+ float timeNorm = getElementAsFloat(profileInfo, "dungeons.dungeon_types." + dungeonString + ".fastest_time." + floorTime);
+ float timeS = getElementAsFloat(profileInfo, "dungeons.dungeon_types." + dungeonString + ".fastest_time_s." + floorTime);
+ float timeSPLUS = getElementAsFloat(
+ profileInfo,
+ "dungeons.dungeon_types." + dungeonString + ".fastest_time_s_plus." + floorTime
);
String timeNormStr = timeNorm <= 0 ? "N/A" : Utils.prettyTime((long) timeNorm);
String timeSStr = timeS <= 0 ? "N/A" : Utils.prettyTime((long) timeS);
@@ -606,15 +532,13 @@ public class DungeonPage extends GuiProfileViewerPage {
Utils.renderShadowedString(EnumChatFormatting.RED + "Boss Collections", x + sectionWidth / 2, y, sectionWidth);
for (int i = 1; i <= 7; i++) {
- float compl = Utils.getElementAsFloat(
- Utils.getElement(profileInfo, "dungeons.dungeon_types." + dungeonString + ".tier_completions." + i),
- 0
- );
+ float compl = getElementAsFloat(profileInfo, "dungeons.dungeon_types." + dungeonString + ".tier_completions." + i);
if (BOSS_HEADS[i - 1] == null) {
String textureLink = bossFloorHeads[i - 1];
- String b64Decoded = "{\"textures\":{\"SKIN\":{\"url\":\"http://textures.minecraft.net/texture/" + textureLink + "\"}}}";
+ String b64Decoded =
+ "{\"textures\":{\"SKIN\":{\"url\":\"http://textures.minecraft.net/texture/" + textureLink + "\"}}}";
String b64Encoded = new String(Base64.getEncoder().encode(b64Decoded.getBytes()));
ItemStack stack = new ItemStack(Items.skull, 1, 3);
@@ -646,7 +570,11 @@ public class DungeonPage extends GuiProfileViewerPage {
GlStateManager.popMatrix();
Utils.renderAlignedString(
- String.format(EnumChatFormatting.YELLOW + "%s (" + (onMasterMode ? "M" : "F") + "%d) ", bossFloorArr[i - 1], i),
+ String.format(
+ EnumChatFormatting.YELLOW + "%s (" + (onMasterMode ? "M" : "F") + "%d) ",
+ bossFloorArr[i - 1],
+ i
+ ),
EnumChatFormatting.WHITE.toString() + (int) compl,
x + 16,
y + 18 + 20 * (i - 1),
@@ -662,7 +590,12 @@ public class DungeonPage extends GuiProfileViewerPage {
//Gui.drawRect(x, y, x+120, y+147, 0xffffffff);
- Utils.renderShadowedString(EnumChatFormatting.DARK_PURPLE + "Class Levels", x + sectionWidth / 2, y, sectionWidth);
+ Utils.renderShadowedString(
+ EnumChatFormatting.DARK_PURPLE + "Class Levels",
+ x + sectionWidth / 2,
+ y,
+ sectionWidth
+ );
JsonElement activeClassElement = Utils.getElement(profileInfo, "dungeons.selected_dungeon_class");
String activeClass = null;
@@ -675,12 +608,12 @@ public class DungeonPage extends GuiProfileViewerPage {
for (int i = 0; i < dungSkillsName.length; i++) {
String skillName = dungSkillsName[i];
- HashMap<String, ProfileViewer.Level> levelObjClasses = levelObjClasseses.computeIfAbsent(profileId, k -> new HashMap<>());
+ HashMap<String, ProfileViewer.Level> levelObjClasses = levelObjClasseses.computeIfAbsent(
+ profileId,
+ k -> new HashMap<>()
+ );
if (!levelObjClasses.containsKey(skillName)) {
- float cataXp = Utils.getElementAsFloat(
- Utils.getElement(profileInfo, "dungeons.player_classes." + skillName.toLowerCase() + ".experience"),
- 0
- );
+ float cataXp = getElementAsFloat(profileInfo, "dungeons.player_classes." + skillName.toLowerCase() + ".experience");
ProfileViewer.Level levelObj = ProfileViewer.getLevel(
Utils.getElementOrDefault(leveling, "catacombs", new JsonArray()).getAsJsonArray(),
cataXp,
@@ -708,7 +641,16 @@ public class DungeonPage extends GuiProfileViewerPage {
ProfileViewer.Level levelObj = levelObjClasses.get(skillName);
getInstance()
- .renderXpBar(colour + skillName, dungSkillsStack[i], x, y + 20 + 24 * i, sectionWidth, levelObj, mouseX, mouseY);
+ .renderXpBar(
+ colour + skillName,
+ dungSkillsStack[i],
+ x,
+ y + 20 + 24 * i,
+ sectionWidth,
+ levelObj,
+ mouseX,
+ mouseY
+ );
}
getInstance().renderXpBar(
@@ -718,12 +660,29 @@ public class DungeonPage extends GuiProfileViewerPage {
y + 20 + 24 * 5,
sectionWidth,
classAverage,
- mouseX, mouseY);
+ mouseX, mouseY
+ );
}
drawSideButtons();
}
+ private boolean isHasTime(float fastestTime, String format, long runsAmount, boolean hasTime) {
+ if (fastestTime > 1000) {
+ getInstance()
+ .tooltipToDisplay.add(String.format(
+ format,
+ Utils.prettyTime(runsAmount * (long) (fastestTime * 1.2))
+ ));
+ hasTime = true;
+ }
+ return hasTime;
+ }
+
+ private static float getElementAsFloat(JsonObject profileInfo, String path) {
+ return Utils.getElementAsFloat(Utils.getElement(profileInfo, path), 0);
+ }
+
@Override
public boolean mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException {
FontRenderer fontRendererObj = Minecraft.getMinecraft().fontRendererObj;
@@ -737,7 +696,8 @@ public class DungeonPage extends GuiProfileViewerPage {
}
int cW = fontRendererObj.getStringWidth("Calculate");
- if (mouseX >= guiLeft + 23 + 110 - 17 - cW && mouseX <= guiLeft + 23 + 110 - 17 && mouseY >= guiTop + 55 && mouseY <= guiTop + 65) {
+ if (mouseX >= guiLeft + 23 + 110 - 17 - cW && mouseX <= guiLeft + 23 + 110 - 17 && mouseY >= guiTop + 55 &&
+ mouseY <= guiTop + 65) {
calculateFloorLevelXP();
}
@@ -774,66 +734,21 @@ public class DungeonPage extends GuiProfileViewerPage {
GlStateManager.enableDepth();
GlStateManager.translate(0, 0, 5);
if (onMasterMode) {
- drawSideButton(1, dungeonsModeIcons.get("master_catacombs"), true);
+ Utils.drawPvSideButton(1, dungeonsModeIcons.get("master_catacombs"), true, getInstance());
} else {
- drawSideButton(0, dungeonsModeIcons.get("catacombs"), true);
+ Utils.drawPvSideButton(0, dungeonsModeIcons.get("catacombs"), true, getInstance());
}
GlStateManager.translate(0, 0, -3);
GlStateManager.translate(0, 0, -2);
if (!onMasterMode) {
- drawSideButton(1, dungeonsModeIcons.get("master_catacombs"), false);
+ Utils.drawPvSideButton(1, dungeonsModeIcons.get("master_catacombs"), false, getInstance());
} else {
- drawSideButton(0, dungeonsModeIcons.get("catacombs"), false);
+ Utils.drawPvSideButton(0, dungeonsModeIcons.get("catacombs"), false, getInstance());
}
GlStateManager.disableDepth();
}
- private void drawSideButton(int yIndex, ItemStack itemStack, boolean pressed) {
- int guiLeft = GuiProfileViewer.getGuiLeft();
- int guiTop = GuiProfileViewer.getGuiTop();
-
- GlStateManager.disableLighting();
- GlStateManager.enableBlend();
- GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
- GlStateManager.enableAlpha();
- GlStateManager.alphaFunc(516, 0.1F);
-
- int x = guiLeft - 28;
- int y = guiTop + yIndex * 28;
-
- float uMin = 193 / 256f;
- float uMax = 223 / 256f;
- float vMin = 200 / 256f;
- float vMax = 228 / 256f;
- if (pressed) {
- uMin = 224 / 256f;
- uMax = 1f;
-
- if (yIndex != 0) {
- vMin = 228 / 256f;
- vMax = 1f;
- }
-
- getInstance().renderBlurredBackground(getInstance().width, getInstance().height, x + 2, y + 2, 30, 28 - 4);
- } else {
- getInstance().renderBlurredBackground(getInstance().width, getInstance().height, x + 2, y + 2, 28 - 2, 28 - 4);
- }
-
- GlStateManager.disableLighting();
- GlStateManager.enableBlend();
- GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
- GlStateManager.enableAlpha();
- GlStateManager.alphaFunc(516, 0.1F);
-
- Minecraft.getMinecraft().getTextureManager().bindTexture(GuiProfileViewer.pv_elements);
-
- Utils.drawTexturedRect(x, y, pressed ? 32 : 28, 28, uMin, uMax, vMin, vMax, GL11.GL_NEAREST);
-
- GlStateManager.enableDepth();
- Utils.drawItemStack(itemStack, x + 8, y + 7);
- }
-
private void calculateFloorLevelXP() {
JsonObject leveling = Constants.LEVELING;
if (leveling == null) return;
@@ -852,7 +767,7 @@ public class DungeonPage extends GuiProfileViewerPage {
if (level < Math.floor(levelObjCata.level)) {
continue;
}
- remaining += levelingArray.get(level).getAsFloat();
+ remaining += levelingArray.get(level).getAsFloat();
}
if (remaining < 0) {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ExtraPage.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ExtraPage.java
index 59c78dda..90ffd388 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ExtraPage.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ExtraPage.java
@@ -94,7 +94,7 @@ public class ExtraPage extends GuiProfileViewerPage {
}
// pls update in the future tyvm !!!
- final static HashMap<String, Integer> slayers = new HashMap<String, Integer>() {
+ public final static HashMap<String, Integer> slayers = new HashMap<String, Integer>() {
{
put("zombie", 5);
put("spider", 4);
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java
index 4bf65cc6..c379c7eb 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java
@@ -171,7 +171,10 @@ public class GuiProfileViewer extends GuiScreen {
);
public final GuiElementTextField playerNameTextField;
public final GuiElementTextField inventoryTextField = new GuiElementTextField("", GuiElementTextField.SCALE_TEXT);
- public final GuiElementTextField killDeathSearchTextField = new GuiElementTextField("", GuiElementTextField.SCALE_TEXT);
+ public final GuiElementTextField killDeathSearchTextField = new GuiElementTextField(
+ "",
+ GuiElementTextField.SCALE_TEXT
+ );
private final Map<ProfileViewerPage, GuiProfileViewerPage> pages = new HashMap<>();
public int sizeX;
public int sizeY;
@@ -390,7 +393,7 @@ public class GuiProfileViewer extends GuiScreen {
GL11.GL_NEAREST
);
Utils.drawStringCenteredScaledMaxWidth(
- "Open in Skycrypt",
+ "Open in SkyCrypt",
Minecraft.getMinecraft().fontRendererObj,
guiLeft + 50 + 100 + 6,
guiTop + sizeY + 3 + 10,
@@ -838,8 +841,9 @@ public class GuiProfileViewer extends GuiScreen {
profileId != null
) {
if (mouseY > guiTop + sizeY + 3 && mouseY < guiTop + sizeY + 23) {
- String url = "https://sky.shiiyu.moe/stats/" + profile.getHypixelProfile().get("displayname").getAsString() + "/" +
- profileId;
+ String url =
+ "https://sky.shiiyu.moe/stats/" + profile.getHypixelProfile().get("displayname").getAsString() + "/" +
+ profileId;
Utils.openUrl(url);
Utils.playPressSound();
return;
@@ -960,14 +964,17 @@ public class GuiProfileViewer extends GuiScreen {
String totalXpStr = null;
if (skillName.contains("Catacombs")) {
totalXpStr = EnumChatFormatting.GRAY + "Total XP: " + EnumChatFormatting.DARK_PURPLE +
- numberFormat.format(levelObj.totalXp) + EnumChatFormatting.DARK_GRAY + " (" +
+ numberFormat.format(levelObj.totalXp) + EnumChatFormatting.DARK_GRAY + " (" +
DECIMAL_FORMAT.format(getPercentage(skillName.toLowerCase(), levelObj)) + "% to 50)";
}
- // Adds overflow level to each level object that is maxed, avoids hotm level as there is no overflow xp for it
+ // Adds overflow level to each level object that is maxed, avoids hotm level as there is no overflow xp for it
if (levelObj.maxed) {
levelStr = levelObj.maxLevel != 7 ?
- EnumChatFormatting.GOLD + "MAXED!" + EnumChatFormatting.GRAY + " (Overflow level: " + String.format("%.2f", levelObj.level) + ")" :
- EnumChatFormatting.GOLD + "MAXED!";
+ EnumChatFormatting.GOLD + "MAXED!" + EnumChatFormatting.GRAY + " (Overflow level: " + String.format(
+ "%.2f",
+ levelObj.level
+ ) + ")" :
+ EnumChatFormatting.GOLD + "MAXED!";
} else {
if (skillName.contains("Class Average")) {
levelStr = "Progress: " + EnumChatFormatting.DARK_PURPLE + String.format("%.1f", (level % 1 * 100)) + "%";
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/InventoriesPage.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/InventoriesPage.java
index a981183a..164f5d78 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/InventoriesPage.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/InventoriesPage.java
@@ -154,7 +154,7 @@ public class InventoriesPage extends GuiProfileViewerPage {
getInstance().tooltipToDisplay = entry.getValue().getTooltip(Minecraft.getMinecraft().thePlayer, false);
if (Objects.equals(entry.getKey(), "talisman_bag")) {
StringBuilder magicalPowerString = new StringBuilder(EnumChatFormatting.DARK_GRAY + "Magical Power: ");
- int magicalPower = PlayerStats.getMagicalPower(inventoryInfo, profileInformation);
+ int magicalPower = profile.getMagicalPower(profileId);
getInstance()
.tooltipToDisplay.add(
magicalPower == -1
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/PlayerStats.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/PlayerStats.java
index 56ecd3a2..9be3eaf4 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/PlayerStats.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/PlayerStats.java
@@ -170,12 +170,14 @@ public class PlayerStats {
return skillBonus;
}
- private static Stats getTamingBonus(JsonObject profile) {
+ public static int getPetScore(JsonObject profile) {
JsonObject bonuses = Constants.BONUSES;
- if (bonuses == null) return null;
-
+ if (bonuses == null) {
+ Utils.showOutdatedRepoNotification();
+ return 0;
+ }
JsonElement petsElement = Utils.getElement(profile, "pets");
- if (petsElement == null) return new Stats();
+ if (petsElement == null) return 0;
JsonArray pets = petsElement.getAsJsonArray();
@@ -190,11 +192,19 @@ public class PlayerStats {
for (String value : highestRarityMap.values()) {
petScore += Utils.getElementAsFloat(Utils.getElement(bonuses, "pet_value." + value.toUpperCase()), 0);
}
+ return petScore;
+ }
+
+ private static Stats getTamingBonus(JsonObject profile) {
+ JsonObject bonuses = Constants.BONUSES;
+ if (bonuses == null) return null;
JsonElement petRewardsElement = Utils.getElement(bonuses, "pet_rewards");
if (petRewardsElement == null) return null;
JsonObject petRewards = petRewardsElement.getAsJsonObject();
+ int petScore = getPetScore(profile);
+
Stats petBonus = new Stats();
for (int i = 0; i <= petScore; i++) {
if (petRewards.has("" + i)) {
@@ -287,7 +297,6 @@ public class PlayerStats {
private static Stats getSetBonuses(
Stats stats,
JsonObject inventoryInfo,
- JsonObject collectionInfo,
Map<String, ProfileViewer.Level> skyblockInfo,
JsonObject profile
) {
@@ -298,17 +307,11 @@ public class PlayerStats {
String fullset = getFullset(armor, -1);
if (fullset != null) {
+ // TODO @nea: repo based stat delivery? (with lisp)
switch (fullset) {
case "LAPIS_ARMOR_":
bonuses.addStat(HEALTH, 60);
break;
- case "EMERALD_ARMOR_":
- {
- int bonus = (int) Math.floor(Utils.getElementAsFloat(Utils.getElement(collectionInfo, "EMERALD"), 0) / 3000);
- bonuses.addStat(HEALTH, bonus);
- bonuses.addStat(DEFENCE, bonus);
- }
- break;
case "FAIRY_":
bonuses.addStat(HEALTH, Utils.getElementAsFloat(Utils.getElement(profile, "fairy_souls_collected"), 0));
break;
@@ -616,11 +619,10 @@ public class PlayerStats {
public static Stats getStats(
Map<String, ProfileViewer.Level> skyblockInfo,
JsonObject inventoryInfo,
- JsonObject collectionInfo,
JsonObject petsInfo,
JsonObject profile
) {
- if (skyblockInfo == null || inventoryInfo == null || collectionInfo == null || profile == null) return null;
+ if (skyblockInfo == null || inventoryInfo == null || profile == null) return null;
JsonArray armor = Utils.getElement(inventoryInfo, "inv_armor").getAsJsonArray();
JsonArray inventory = Utils.getElement(inventoryInfo, "inv_contents").getAsJsonArray();
@@ -645,7 +647,7 @@ public class PlayerStats {
stats = stats.add(passiveBonuses).add(armorBonuses).add(talismanBonuses).add(petBonus).add(hotmBonuses);
- stats.add(getSetBonuses(stats, inventoryInfo, collectionInfo, skyblockInfo, profile));
+ stats.add(getSetBonuses(stats, inventoryInfo, skyblockInfo, profile));
stats.scaleAll(getStatMult(inventoryInfo));
@@ -655,97 +657,6 @@ public class PlayerStats {
}
/**
- * Calculates the amount of Magical Power the player has using the list of accessories
- *
- * @param inventoryInfo inventory info object
- * @return the amount of Magical Power or -1
- * @see io.github.moulberry.notenoughupdates.profileviewer.ProfileViewer.Profile#getInventoryInfo(String)
- */
- public static int getMagicalPower(JsonObject inventoryInfo, JsonObject profileInfo) {
- if (inventoryInfo == null || !inventoryInfo.has("talisman_bag") || !inventoryInfo.get("talisman_bag").isJsonArray()) {
- 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 powderAmount = 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:
- powderAmount += 16;
- break;
- case 5:
- powderAmount += 22;
- break;
- }
- }
- if (entry.getKey().equals("ABICASE")) {
- if (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();
- powderAmount += Math.floor(contact / 2);
- }
- }
- switch (entry.getValue()) {
- case 0:
- case 6:
- powderAmount += 3;
- break;
- case 1:
- case 7:
- powderAmount += 5;
- break;
- case 2:
- powderAmount += 8;
- break;
- case 3:
- powderAmount += 12;
- break;
- case 4:
- powderAmount += 16;
- break;
- case 5:
- powderAmount += 22;
- break;
- }
- }
- return powderAmount;
- }
-
- /**
* Finds the Magical Power the player selected if applicable
*
* @param profileInfo profile information object
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 63c2435a..610e4090 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ProfileViewer.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ProfileViewer.java
@@ -25,14 +25,18 @@ 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.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;
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;
@@ -40,19 +44,25 @@ import net.minecraft.util.EnumChatFormatting;
import javax.annotation.Nullable;
import java.io.ByteArrayInputStream;
import java.io.IOException;
+import java.util.AbstractMap;
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.Matcher;
import java.util.regex.Pattern;
+import java.util.stream.Collectors;
public class ProfileViewer {
@@ -247,7 +257,7 @@ public class ProfileViewer {
"REDSTONE",
"QUARTZ",
"OBSIDIAN",
- "GLOWSTONE",
+ "GLOWSTONE_DUST",
"GRAVEL",
"ICE",
null,
@@ -444,11 +454,15 @@ public class ProfileViewer {
);
}
};
+
+ public static final List<String> SLAYERS = Arrays.asList("zombie", "spider", "wolf", "enderman", "blaze");
+
private static final AtomicBoolean updatingResourceCollection = new AtomicBoolean(false);
private static JsonObject resourceCollection = null;
private final NEUManager manager;
private final HashMap<String, JsonObject> uuidToHypixelProfile = new HashMap<>();
private final HashMap<String, Profile> uuidToProfileMap = new HashMap<>();
+
private final HashMap<String, String> nameToUuid = new HashMap<>();
public ProfileViewer(NEUManager manager) {
@@ -643,11 +657,14 @@ public class ProfileViewer {
private final HashMap<String, List<JsonObject>> coopProfileMap = new HashMap<>();
private final HashMap<String, Map<String, Level>> skyblockInfoCache = new HashMap<>();
private final HashMap<String, JsonObject> inventoryCacheMap = new HashMap<>();
- private final HashMap<String, JsonObject> collectionInfoMap = new HashMap<>();
+ private final HashMap<String, CompletableFuture<ProfileCollectionInfo>> collectionInfoMap = new HashMap<>();
+ private final HashMap<String, Double> skyBlockExperience = new HashMap<>();
+ private final HashMap<String, EnumChatFormatting> skyBlockExperienceColour = new HashMap<>();
private final List<String> profileNames = new ArrayList<>();
private final HashMap<String, PlayerStats.Stats> stats = new HashMap<>();
private final HashMap<String, PlayerStats.Stats> passiveStats = new HashMap<>();
private final HashMap<String, Long> networth = new HashMap<>();
+ private final HashMap<String, Integer> magicalPower = new HashMap<>();
private final HashMap<String, SoopyNetworthData> soopyNetworth = new HashMap<>();
private final AtomicBoolean updatingSkyblockProfilesState = new AtomicBoolean(false);
private final AtomicBoolean updatingGuildInfoState = new AtomicBoolean(false);
@@ -671,6 +688,117 @@ public class ProfileViewer {
this.uuid = uuid;
}
+ /**
+ * Calculates the amount of Magical Power the player has using the list of accessories
+ *
+ * @return the amount of Magical Power or -1
+ * @see io.github.moulberry.notenoughupdates.profileviewer.ProfileViewer.Profile#getInventoryInfo(String)
+ */
+ public int getMagicalPower(String profileId) {
+ JsonObject inventoryInfo = getInventoryInfo(profileId);
+ JsonObject profileInfo = getProfileInformation(profileId);
+ if (magicalPower.containsKey(profileId)) return magicalPower.get(profileId);
+ if (inventoryInfo == null || !inventoryInfo.has("talisman_bag") ||
+ !inventoryInfo.get("talisman_bag").isJsonArray()) {
+ 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;
+ }
+ }
+ magicalPower.put(profileId, powerAmount);
+ return powerAmount;
+ }
+
public JsonObject getPlayerStatus() {
if (playerStatus != null) return playerStatus;
if (updatingPlayerStatusState.get()) return null;
@@ -924,6 +1052,50 @@ public class ProfileViewer {
return null;
}
+ public EnumChatFormatting getSkyblockLevelColour(String profileName) {
+ if (Constants.SBLEVELS == null) return EnumChatFormatting.WHITE;
+ if (skyBlockExperienceColour.containsKey(profileName)) {
+ return skyBlockExperienceColour.get(profileName);
+ }
+
+ double skyblockLevel = getSkyblockLevel(profileName);
+
+ EnumChatFormatting previousColor = EnumChatFormatting.WHITE;
+ if (Constants.SBLEVELS == null || !Constants.SBLEVELS.has("sblevel_colours")) {
+ Utils.showOutdatedRepoNotification();
+ return EnumChatFormatting.WHITE;
+ }
+ JsonObject sblevelColours = Constants.SBLEVELS.getAsJsonObject("sblevel_colours");
+ try {
+ for (Map.Entry<String, JsonElement> stringJsonElementEntry : sblevelColours.entrySet()) {
+ int key = Integer.parseInt(stringJsonElementEntry.getKey());
+ EnumChatFormatting valueByName = EnumChatFormatting.getValueByName(stringJsonElementEntry
+ .getValue()
+ .getAsString());
+ if (skyblockLevel <= key) {
+ skyBlockExperienceColour.put(profileName, previousColor);
+ return previousColor;
+ }
+ previousColor = valueByName;
+ }
+ } catch (RuntimeException ignored) {
+ // catch both numberformat and getValueByName being wrong
+ }
+ skyBlockExperienceColour.put(profileName, EnumChatFormatting.WHITE);
+ return EnumChatFormatting.WHITE;
+ }
+
+ public double getSkyblockLevel(String profileName) {
+ if (skyBlockExperience.containsKey(profileName)) {
+ return skyBlockExperience.get(profileName);
+ }
+ final JsonObject profileInfo = getProfileInformation(profileName);
+ int element = Utils.getElementAsInt(Utils.getElement(profileInfo, "leveling.experience"), 0);
+ double level = (element / 100F);
+ skyBlockExperience.put(profileName, level);
+ return level;
+ }
+
public long getNetWorth(String profileName) {
if (profileName == null) profileName = latestProfile;
if (networth.get(profileName) != null) return networth.get(profileName);
@@ -1141,65 +1313,62 @@ public class ProfileViewer {
}
public JsonObject getProfileInformation(String profileName) {
+ if (profileName == null) profileName = latestProfile;
+ if (profileMap.containsKey(profileName)) return profileMap.get(profileName);
+ JsonObject profile = getRawProfileInformation(profileName);
+ if (profile == null) return null;
+ if (!profile.has("members")) return null;
+ JsonObject members = profile.get("members").getAsJsonObject();
+ if (!members.has(uuid)) return null;
+ JsonObject profileInfo = members.get(uuid).getAsJsonObject();
+ if (profile.has("banking")) {
+ profileInfo.add("banking", profile.get("banking").getAsJsonObject());
+ }
+ if (profile.has("game_mode")) {
+ profileInfo.add("game_mode", profile.get("game_mode"));
+ }
+ if (profile.has("community_upgrades")) {
+ profileInfo.add("community_upgrades", profile.get("community_upgrades"));
+ }
+ profileMap.put(profileName, profileInfo);
+ return profileInfo;
+ }
+
+ public JsonObject getRawProfileInformation(String profileName) {
JsonArray playerInfo = getSkyblockProfiles(() -> {});
if (playerInfo == null) return null;
if (profileName == null) profileName = latestProfile;
- if (profileMap.containsKey(profileName)) return profileMap.get(profileName);
- for (int i = 0; i < skyblockProfiles.size(); i++) {
- if (!skyblockProfiles.get(i).isJsonObject()) {
+ for (JsonElement skyblockProfile : skyblockProfiles) {
+ if (!skyblockProfile.isJsonObject()) {
skyblockProfiles = null;
return null;
}
- JsonObject profile = skyblockProfiles.get(i).getAsJsonObject();
- if (profile.get("cute_name").getAsString().equalsIgnoreCase(profileName)) {
- if (!profile.has("members")) return null;
- JsonObject members = profile.get("members").getAsJsonObject();
- if (!members.has(uuid)) continue;
- JsonObject profileInfo = members.get(uuid).getAsJsonObject();
- if (profile.has("banking")) {
- profileInfo.add("banking", profile.get("banking").getAsJsonObject());
- }
- if (profile.has("game_mode")) {
- profileInfo.add("game_mode", profile.get("game_mode"));
- }
- profileMap.put(profileName, profileInfo);
- return profileInfo;
- }
+ if (skyblockProfile.getAsJsonObject().get("cute_name").getAsString().equalsIgnoreCase(profileName))
+ return skyblockProfile.getAsJsonObject();
}
-
return null;
}
public List<JsonObject> getCoopProfileInformation(String profileName) {
- JsonArray playerInfo = getSkyblockProfiles(() -> {});
- if (playerInfo == null) return null;
if (profileName == null) profileName = latestProfile;
if (coopProfileMap.containsKey(profileName)) return coopProfileMap.get(profileName);
-
- for (int i = 0; i < skyblockProfiles.size(); i++) {
- if (!skyblockProfiles.get(i).isJsonObject()) {
- skyblockProfiles = null;
- return null;
- }
- JsonObject profile = skyblockProfiles.get(i).getAsJsonObject();
- if (profile.get("cute_name").getAsString().equalsIgnoreCase(profileName)) {
- if (!profile.has("members")) return null;
- JsonObject members = profile.get("members").getAsJsonObject();
- if (!members.has(uuid)) return null;
- List<JsonObject> coopList = new ArrayList<>();
- for (Map.Entry<String, JsonElement> islandMember : members.entrySet()) {
- if (!islandMember.getKey().equals(uuid)) {
- JsonObject coopProfileInfo = islandMember.getValue().getAsJsonObject();
- coopList.add(coopProfileInfo);
- }
- }
- coopProfileMap.put(profileName, coopList);
- return coopList;
+ JsonObject profile = getRawProfileInformation(profileName);
+ if (profile == null) return null;
+
+ if (!profile.has("members")) return null;
+ JsonObject members = profile.get("members").getAsJsonObject();
+ if (!members.has(uuid)) return null;
+ List<JsonObject> coopList = new ArrayList<>();
+ for (Map.Entry<String, JsonElement> islandMember : members.entrySet()) {
+ if (!islandMember.getKey().equals(uuid)) {
+ JsonObject coopProfileInfo = islandMember.getValue().getAsJsonObject();
+ coopList.add(coopProfileInfo);
}
}
+ coopProfileMap.put(profileName, coopList);
+ return coopList;
- return null;
}
public void resetCache() {
@@ -1216,6 +1385,9 @@ public class ProfileViewer {
inventoryCacheMap.clear();
collectionInfoMap.clear();
networth.clear();
+ magicalPower.clear();
+ skyBlockExperience.clear();
+ skyBlockExperienceColour.clear();
}
public int getCap(JsonObject leveling, String skillName) {
@@ -1225,6 +1397,40 @@ public class ProfileViewer {
: 50;
}
+ public int getBestiaryTiers(JsonObject profileInfo) {
+ int beLevel = 0;
+ for (ItemStack items : BestiaryData.getBestiaryLocations().keySet()) {
+ List<String> mobs = BestiaryData.getBestiaryLocations().get(items);
+ if (mobs != null) {
+ for (String mob : mobs) {
+ if (mob != null) {
+ float kills = Utils.getElementAsFloat(Utils.getElement(profileInfo, "bestiary.kills_" + mob), 0);
+ String type;
+ if (BestiaryData.getMobType().get(mob) != null) {
+ type = BestiaryData.getMobType().get(mob);
+ } else {
+ type = "MOB";
+ }
+ JsonObject leveling = Constants.LEVELING;
+ ProfileViewer.Level level = null;
+ if (leveling != null && Utils.getElement(leveling, "bestiary." + type) != null) {
+ JsonArray levelingArray = Utils.getElement(leveling, "bestiary." + type).getAsJsonArray();
+ int levelCap = Utils.getElementAsInt(Utils.getElement(leveling, "bestiary.caps." + type), 0);
+ level = ProfileViewer.getLevel(levelingArray, kills, levelCap, false);
+ }
+
+ float levelNum = 0;
+ if (level != null) {
+ levelNum = level.level;
+ }
+ beLevel += (int) Math.floor(levelNum);
+ }
+ }
+ }
+ }
+ return beLevel;
+ }
+
public Map<String, Level> getSkyblockInfo(String profileName) {
JsonObject profileInfo = getProfileInformation(profileName);
@@ -1329,9 +1535,7 @@ public class ProfileViewer {
)
);
}
-
- List<String> slayers = Arrays.asList("zombie", "spider", "wolf", "enderman", "blaze");
- for (String slayerName : slayers) {
+ for (String slayerName : SLAYERS) {
float slayerExperience = Utils.getElementAsFloat(Utils.getElement(
profileInfo,
"slayer_bosses." + slayerName + ".xp"
@@ -1560,134 +1764,15 @@ public class ProfileViewer {
return null;
}
- public JsonObject getCollectionInfo(String profileName) {
- JsonObject profileInfo = getProfileInformation(profileName);
- if (profileInfo == null) return null;
- JsonObject resourceCollectionInfo = getResourceCollectionInformation();
- if (resourceCollectionInfo == null) return null;
- if (profileName == null) profileName = latestProfile;
- if (collectionInfoMap.containsKey(profileName)) return collectionInfoMap.get(profileName);
-
- List<JsonObject> coopMembers = getCoopProfileInformation(profileName);
- JsonElement unlocked_coll_tiers_element = Utils.getElement(profileInfo, "unlocked_coll_tiers");
- JsonElement crafted_generators_element = Utils.getElement(profileInfo, "crafted_generators");
- JsonObject fakeMember = new JsonObject();
- fakeMember.add("crafted_generators", crafted_generators_element);
- coopMembers.add(coopMembers.size(), fakeMember);
- JsonElement collectionInfoElement = Utils.getElement(profileInfo, "collection");
-
- if (unlocked_coll_tiers_element == null || collectionInfoElement == null) {
- return null;
- }
-
- JsonObject collectionInfo = new JsonObject();
- JsonObject collectionTiers = new JsonObject();
- JsonObject minionTiers = new JsonObject();
- JsonObject personalAmounts = new JsonObject();
- JsonObject totalAmounts = new JsonObject();
-
- if (collectionInfoElement.isJsonObject()) {
- personalAmounts = collectionInfoElement.getAsJsonObject();
- }
-
- for (Map.Entry<String, JsonElement> entry : personalAmounts.entrySet()) {
- totalAmounts.addProperty(entry.getKey(), entry.getValue().getAsLong());
- }
-
- List<JsonObject> coopProfiles = getCoopProfileInformation(profileName);
- if (coopProfiles != null) {
- for (JsonObject coopProfile : coopProfiles) {
- JsonElement coopCollectionInfoElement = Utils.getElement(coopProfile, "collection");
- if (coopCollectionInfoElement != null && coopCollectionInfoElement.isJsonObject()) {
- for (Map.Entry<String, JsonElement> entry : coopCollectionInfoElement.getAsJsonObject().entrySet()) {
- float existing = Utils.getElementAsFloat(totalAmounts.get(entry.getKey()), 0);
- totalAmounts.addProperty(entry.getKey(), existing + entry.getValue().getAsLong());
- }
- }
- }
- }
-
- if (unlocked_coll_tiers_element.isJsonArray()) {
- JsonArray unlocked_coll_tiers = unlocked_coll_tiers_element.getAsJsonArray();
- for (int i = 0; i < unlocked_coll_tiers.size(); i++) {
- String unlocked = unlocked_coll_tiers.get(i).getAsString();
-
- Matcher matcher = COLL_TIER_PATTERN.matcher(unlocked);
-
- if (matcher.find()) {
- String tier_str = matcher.group(1);
- int tier = Integer.parseInt(tier_str);
- String coll = unlocked.substring(0, unlocked.length() - (matcher.group().length()));
- if (!collectionTiers.has(coll) || collectionTiers.get(coll).getAsInt() < tier) {
- collectionTiers.addProperty(coll, tier);
- }
- }
- }
- }
- for (JsonObject current_member_info : coopMembers) {
- if (
- !current_member_info.has("crafted_generators") || !current_member_info.get("crafted_generators").isJsonArray()
- ) continue;
- JsonArray crafted_generators = Utils.getElement(current_member_info, "crafted_generators").getAsJsonArray();
- for (int j = 0; j < crafted_generators.size(); j++) {
- String unlocked = crafted_generators.get(j).getAsString();
- Matcher matcher = COLL_TIER_PATTERN.matcher(unlocked);
- if (matcher.find()) {
- String tierString = matcher.group(1);
- int tier = Integer.parseInt(tierString);
- String coll = unlocked.substring(0, unlocked.length() - (matcher.group().length()));
- if (!minionTiers.has(coll) || minionTiers.get(coll).getAsInt() < tier) {
- minionTiers.addProperty(coll, tier);
- }
- }
- }
- }
-
- JsonObject maxAmount = new JsonObject();
- JsonObject updatedCollectionTiers = new JsonObject();
- for (Map.Entry<String, JsonElement> totalAmountsEntry : totalAmounts.entrySet()) {
- String collName = totalAmountsEntry.getKey();
- int collTier = (int) Utils.getElementAsFloat(collectionTiers.get(collName), 0);
-
- int currentAmount = (int) Utils.getElementAsFloat(totalAmounts.get(collName), 0);
- if (currentAmount > 0) {
- for (Map.Entry<String, JsonElement> resourceEntry : resourceCollectionInfo.entrySet()) {
- JsonElement tiersElement = Utils.getElement(resourceEntry.getValue(), "items." + collName + ".tiers");
- if (tiersElement != null && tiersElement.isJsonArray()) {
- JsonArray tiers = tiersElement.getAsJsonArray();
- int maxTierAcquired = -1;
- int maxAmountRequired = -1;
- for (int i = 0; i < tiers.size(); i++) {
- JsonObject tierInfo = tiers.get(i).getAsJsonObject();
- int tier = tierInfo.get("tier").getAsInt();
- int amountRequired = tierInfo.get("amountRequired").getAsInt();
- if (currentAmount >= amountRequired) {
- maxTierAcquired = tier;
- }
- maxAmountRequired = amountRequired;
- }
- if (maxTierAcquired >= 0 && maxTierAcquired > collTier) {
- updatedCollectionTiers.addProperty(collName, maxTierAcquired);
- }
- maxAmount.addProperty(collName, maxAmountRequired);
- }
- }
- }
- }
-
- for (Map.Entry<String, JsonElement> collectionTiersEntry : updatedCollectionTiers.entrySet()) {
- collectionTiers.add(collectionTiersEntry.getKey(), collectionTiersEntry.getValue());
- }
-
- collectionInfo.add("minion_tiers", minionTiers);
- collectionInfo.add("max_amounts", maxAmount);
- collectionInfo.add("personal_amounts", personalAmounts);
- collectionInfo.add("total_amounts", totalAmounts);
- collectionInfo.add("collection_tiers", collectionTiers);
-
- collectionInfoMap.put(profileName, collectionInfo);
-
- return collectionInfo;
+ public ProfileCollectionInfo getCollectionInfo(String profileName) {
+ JsonObject rawProfileInformation = getRawProfileInformation(profileName);
+ if (rawProfileInformation == null) return null;
+ CompletableFuture<ProfileCollectionInfo> future =
+ collectionInfoMap.computeIfAbsent(
+ profileName.toLowerCase(Locale.ROOT),
+ ignored -> ProfileCollectionInfo.getCollectionData(rawProfileInformation, uuid)
+ );
+ return future.getNow(null);
}
public PlayerStats.Stats getPassiveStats(String profileName) {
@@ -1716,7 +1801,6 @@ public class ProfileViewer {
PlayerStats.Stats stats = PlayerStats.getStats(
getSkyblockInfo(profileName),
getInventoryInfo(profileName),
- getCollectionInfo(profileName),
getPetsInfo(profileName),
profileInfo
);
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/bestiary/BestiaryPage.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/bestiary/BestiaryPage.java
index 70ea051a..7da6c627 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/bestiary/BestiaryPage.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/bestiary/BestiaryPage.java
@@ -117,7 +117,7 @@ public class BestiaryPage extends GuiProfileViewerPage {
Color color = new Color(128, 128, 128, 255);
Utils.renderAlignedString(
EnumChatFormatting.RED + "Bestiary Level: ",
- EnumChatFormatting.GRAY + "" + (float) getBestiaryTiers(profileInfo) / 10,
+ EnumChatFormatting.GRAY + "" + (float) GuiProfileViewer.getProfile().getBestiaryTiers(profileInfo) / 10,
guiLeft + 220,
guiTop + 50,
110
@@ -265,38 +265,4 @@ public class BestiaryPage extends GuiProfileViewerPage {
yIndex++;
}
}
-
- private int getBestiaryTiers(JsonObject profileInfo) {
- int beLevel = 0;
- for (ItemStack items : BestiaryData.getBestiaryLocations().keySet()) {
- List<String> mobs = BestiaryData.getBestiaryLocations().get(items);
- if (mobs != null) {
- for (String mob : mobs) {
- if (mob != null) {
- float kills = Utils.getElementAsFloat(Utils.getElement(profileInfo, "bestiary.kills_" + mob), 0);
- String type;
- if (BestiaryData.getMobType().get(mob) != null) {
- type = BestiaryData.getMobType().get(mob);
- } else {
- type = "MOB";
- }
- JsonObject leveling = Constants.LEVELING;
- ProfileViewer.Level level = null;
- if (leveling != null && Utils.getElement(leveling, "bestiary." + type) != null) {
- JsonArray levelingArray = Utils.getElement(leveling, "bestiary." + type).getAsJsonArray();
- int levelCap = Utils.getElementAsInt(Utils.getElement(leveling, "bestiary.caps." + type), 0);
- level = ProfileViewer.getLevel(levelingArray, kills, levelCap, false);
- }
-
- float levelNum = 0;
- if (level != null) {
- levelNum = level.level;
- }
- beLevel += (int) Math.floor(levelNum);
- }
- }
- }
- }
- return beLevel;
- }
}
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
new file mode 100644
index 00000000..16abf251
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/LevelPage.java
@@ -0,0 +1,229 @@
+/*
+ * 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;
+
+import com.google.gson.JsonObject;
+import io.github.moulberry.notenoughupdates.profileviewer.BasicPage;
+import io.github.moulberry.notenoughupdates.profileviewer.GuiProfileViewer;
+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.MiscTaskLevel;
+import io.github.moulberry.notenoughupdates.profileviewer.level.task.SkillRelatedTaskLevel;
+import io.github.moulberry.notenoughupdates.profileviewer.level.task.SlayingTaskLevel;
+import io.github.moulberry.notenoughupdates.profileviewer.level.task.StoryTaskLevel;
+import io.github.moulberry.notenoughupdates.util.Constants;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.ResourceLocation;
+import org.lwjgl.opengl.GL11;
+
+import java.text.NumberFormat;
+import java.util.Collections;
+import java.util.List;
+
+public class LevelPage {
+
+ private final GuiProfileViewer instance;
+ private final BasicPage basicPage;
+ private ProfileViewer.Profile profile;
+
+ private String profileId;
+
+ private final JsonObject constant;
+
+ private final CoreTaskLevel coreTaskLevel;
+ private final DungeonTaskLevel dungeonTaskLevel;
+ private final EssenceTaskLevel essenceTaskLevel;
+ private final MiscTaskLevel miscTaskLevel;
+ private final SkillRelatedTaskLevel skillRelatedTaskLevel;
+ private final SlayingTaskLevel slayingTaskLevel;
+ private final StoryTaskLevel storyTaskLevel;
+
+ private static final ResourceLocation pv_levels = new ResourceLocation("notenoughupdates:pv_levels.png");
+
+ public LevelPage(GuiProfileViewer instance, BasicPage basicPage) {
+ this.instance = instance;
+ this.basicPage = basicPage;
+ constant = Constants.SBLEVELS;
+
+ coreTaskLevel = new CoreTaskLevel(this);
+ dungeonTaskLevel = new DungeonTaskLevel(this);
+ essenceTaskLevel = new EssenceTaskLevel(this);
+ miscTaskLevel = new MiscTaskLevel(this);
+ skillRelatedTaskLevel = new SkillRelatedTaskLevel(this);
+ slayingTaskLevel = new SlayingTaskLevel(this);
+ storyTaskLevel = new StoryTaskLevel(this);
+ }
+
+ public void drawPage(int mouseX, int mouseY) {
+ int guiLeft = GuiProfileViewer.getGuiLeft();
+ int guiTop = GuiProfileViewer.getGuiTop();
+ this.profile = GuiProfileViewer.getProfile();
+ this.profileId = GuiProfileViewer.getProfileId();
+
+ basicPage.drawSideButtons();
+
+ if (constant == null) {
+ Utils.showOutdatedRepoNotification();
+ return;
+ }
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(pv_levels);
+ Utils.drawTexturedRect(guiLeft, guiTop, instance.sizeX, instance.sizeY, GL11.GL_NEAREST);
+
+ double skyblockLevel = profile.getSkyblockLevel(profileId);
+ 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);
+ }
+
+ public void renderLevelBar(
+ String name,
+ ItemStack stack,
+ int x,
+ int y,
+ int xSize,
+ double level,
+ double xp,
+ double max,
+ int mouseX,
+ int mouseY,
+ boolean percentage,
+ List<String> tooltip
+ ) {
+
+ if (xp < 0) xp = 0;
+ double experienceRequired = (xp / max);
+
+ String second = EnumChatFormatting.WHITE.toString() + (int) level;
+ if (percentage) {
+ second = EnumChatFormatting.WHITE.toString() + (int) (experienceRequired * 100) + "%";
+ }
+ Utils.renderAlignedString(
+ EnumChatFormatting.RED + name,
+ second,
+ x + 14,
+ y - 4,
+ xSize - 20
+ );
+
+ if (xp >= max) {
+ getInstance().renderGoldBar(x, y + 6, xSize);
+ } else {
+ getInstance().renderBar(x, y + 6, xSize, (float) experienceRequired);
+ }
+ String levelStr;
+ if (mouseX > x && mouseX < x + 120) {
+ if (mouseY > y - 4 && mouseY < y + 13) {
+ NumberFormat numberFormat = NumberFormat.getInstance();
+ String xpFormatted = numberFormat.format((int) xp);
+ String maxFormatted = numberFormat.format((int) max);
+
+ levelStr =
+ EnumChatFormatting.GRAY + "Progress: " + EnumChatFormatting.DARK_PURPLE + (int) (experienceRequired * 100) +
+ "%" +
+ " §8(" + xpFormatted + "/" + maxFormatted + " XP)";
+ if (tooltip != null && !tooltip.isEmpty()) {
+ tooltip.add("");
+ tooltip.add(levelStr);
+ getInstance().tooltipToDisplay = tooltip;
+ } else {
+ getInstance().tooltipToDisplay = Utils.createList(levelStr);
+ }
+ }
+ }
+
+ GlStateManager.enableDepth();
+ GL11.glTranslatef((x), (y - 6f), 0);
+ GL11.glScalef(0.7f, 0.7f, 1);
+ Utils.drawItemStackLinear(stack, 0, 0);
+ GL11.glScalef(1 / 0.7f, 1 / 0.7f, 1);
+ GL11.glTranslatef(-(x), -(y - 6f), 0);
+ GlStateManager.disableDepth();
+ }
+
+ private void drawMainBar(double skyblockLevel, int mouseX, int mouseY, int guiLeft, int guiTop) {
+ renderLevelBar(
+ "Level",
+ BasicPage.skull,
+ guiLeft + 163,
+ guiTop + 30,
+ 110,
+ skyblockLevel,
+ (skyblockLevel - (long) skyblockLevel) * 100,
+ 100,
+ mouseX,
+ mouseY,
+ false,
+ Collections.emptyList()
+ );
+ }
+
+ public String buildLore(String name, double xpGotten, double xpGainful, boolean hasNoLimit) {
+ String xpGottenFormatted = NumberFormat.getInstance().format((int) xpGotten);
+ String xpGainfulFormatted = NumberFormat.getInstance().format((int) xpGainful);
+
+ if (xpGainful == 0 && xpGotten == 0 && !hasNoLimit) {
+ return EnumChatFormatting.GOLD + name + ": §c§lNOT DETECTABLE!";
+ }
+ if (hasNoLimit) {
+ return EnumChatFormatting.GOLD + name + ": " + EnumChatFormatting.YELLOW + xpGottenFormatted + " XP";
+ }
+ int percentage = (int) ((xpGotten / xpGainful) * 100);
+ if (xpGotten >= xpGainful) {
+ return EnumChatFormatting.GOLD + name + ": " + EnumChatFormatting.GREEN
+ + percentage + "%" + " §8(" + xpGottenFormatted + "/" + xpGainfulFormatted + " XP)";
+ } else if (xpGotten == -1) {
+ return EnumChatFormatting.GOLD + name + ": §c§lCOLLECTION DISABLED!";
+ } else {
+
+ return EnumChatFormatting.GOLD + name + ": " + EnumChatFormatting.YELLOW
+ + percentage + "%" + " §8(" + xpGottenFormatted + "/" + xpGainfulFormatted + " XP)";
+ }
+ }
+
+ public JsonObject getConstant() {
+ return constant;
+ }
+
+ public ProfileViewer.Profile getProfile() {
+ return profile;
+ }
+
+ public String getProfileId() {
+ return profileId;
+ }
+
+ public GuiProfileViewer getInstance() {
+ return instance;
+ }
+}
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
new file mode 100644
index 00000000..be333359
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/CoreTaskLevel.java
@@ -0,0 +1,163 @@
+/*
+ * 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.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;
+import io.github.moulberry.notenoughupdates.util.hypixelapi.ProfileCollectionInfo;
+import net.minecraft.init.Items;
+import net.minecraft.item.ItemStack;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+public class CoreTaskLevel {
+
+ private final LevelPage levelPage;
+
+ public CoreTaskLevel(LevelPage levelPage) {this.levelPage = levelPage;}
+
+ private final List<String> skills = Arrays.asList(
+ "taming",
+ "mining",
+ "foraging",
+ "enchanting",
+ "carpentry",
+ "farming",
+ "combat",
+ "fishing",
+ "alchemy"
+ );
+
+ public void drawTask(JsonObject object, int mouseX, int mouseY, int guiLeft, int guiTop) {
+ JsonObject coreTask = levelPage.getConstant().get("core_task").getAsJsonObject();
+ // skills
+ Map<String, ProfileViewer.Level> skyblockInfo = levelPage.getProfile().getSkyblockInfo(levelPage.getProfileId());
+
+ int sbXpGainedSkillLVL = 0;
+ if (skyblockInfo != null) {
+ for (String skill : skills) {
+ ProfileViewer.Level level = skyblockInfo.get(skill);
+ for (int i = 1; i <= level.level; i++) {
+ if (i <= 10) {
+ sbXpGainedSkillLVL += 5;
+ }
+ if (i <= 25 && i > 10) {
+ sbXpGainedSkillLVL += 10;
+ }
+ if (i <= 50 && i > 25) {
+ sbXpGainedSkillLVL += 20;
+ }
+ if (i <= 60 && i > 50) {
+ sbXpGainedSkillLVL += 30;
+ }
+ }
+ }
+ } else {
+ sbXpGainedSkillLVL = -1;
+ }
+
+ // mp acc
+ int sbXpGainedMp = levelPage.getProfile().getMagicalPower(levelPage.getProfileId());
+
+ // pets
+
+ int petScore = PlayerStats.getPetScore(object);
+ int sbXpPetScore = petScore * coreTask.get("pet_score_xp").getAsInt();
+
+ // museum is not possible
+
+ // fairy soul
+ int fairySoulsCollected = object.get("fairy_souls_collected").getAsInt();
+ int sbXpGainedFairy = ((fairySoulsCollected / 5)) * coreTask.get("fairy_souls_xp").getAsInt();
+
+ int sbXpCollection = -1;
+ int sbXpMinionTier = -1; // keeping at -1 here because cobblestone 1 minion XP isn't included for some reason?
+ JsonObject minionXp = Constants.MISC.get("minionXp").getAsJsonObject();
+ int collectionsXp = coreTask.get("collections_xp").getAsInt();
+ ProfileCollectionInfo collection;
+ collection = levelPage.getProfile().getCollectionInfo(
+ levelPage.getProfileId()
+ );
+ if (collection != null) {
+ sbXpCollection = 0;
+ for (Map.Entry<String, ProfileCollectionInfo.CollectionInfo> stringCollectionInfoEntry : collection
+ .getCollections()
+ .entrySet()) {
+ ProfileCollectionInfo.CollectionInfo value = stringCollectionInfoEntry.getValue();
+ sbXpCollection += value.getUnlockedTiers().size() * collectionsXp;
+ }
+
+ for (int tier : collection.getCraftedGenerators().values()) {
+ for (int i = 1; i <= tier; i++) {
+ if (minionXp.has(i + "")) sbXpMinionTier += minionXp.get(i + "").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
+ ));
+ lore.add(levelPage.buildLore(
+ "Fairy Soul",
+ sbXpGainedFairy, coreTask.get("fairy_souls").getAsInt(), false
+ ));
+ lore.add(levelPage.buildLore("Accessory Bag",
+ sbXpGainedMp, 0, true
+ ));
+ lore.add(levelPage.buildLore("Pet Score",
+ sbXpPetScore, 0, true
+ ));
+ lore.add(levelPage.buildLore("Collections",
+ sbXpCollection, coreTask.get("collections").getAsInt(), false
+ ));
+ lore.add(levelPage.buildLore("Craft Minions",
+ sbXpMinionTier, coreTask.get("craft_minions").getAsInt(), false
+ ));
+ lore.add(levelPage.buildLore("Bank Upgrade",
+ 0, 0, false
+ ));
+
+ levelPage.renderLevelBar(
+ "Core Task",
+ new ItemStack(Items.nether_star),
+ guiLeft + 23,
+ guiTop + 25,
+ 110,
+ 0,
+ sbXpGainedSkillLVL + sbXpGainedFairy +
+ sbXpCollection + sbXpMinionTier,
+ levelPage.getConstant().getAsJsonObject("category_xp").get("core_task").getAsInt(),
+ 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
new file mode 100644
index 00000000..157c8362
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/DungeonTaskLevel.java
@@ -0,0 +1,126 @@
+/*
+ * 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.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.profileviewer.ProfileViewer;
+import io.github.moulberry.notenoughupdates.profileviewer.level.LevelPage;
+import io.github.moulberry.notenoughupdates.util.Utils;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+public class DungeonTaskLevel {
+
+ private final LevelPage levelPage;
+
+ public DungeonTaskLevel(LevelPage levelPage) {this.levelPage = levelPage;}
+
+ public void drawTask(JsonObject object, int mouseX, int mouseY, int guiLeft, int guiTop) {
+ JsonObject dungeonTask = levelPage.getConstant().get("dungeon_task").getAsJsonObject();
+
+ Map<String, ProfileViewer.Level> skyblockInfo =
+ levelPage.getProfile().getSkyblockInfo(levelPage.getProfileId());
+
+ double sbLevelGainedFloor = 0;
+ double sbXpGainedClass = 0;
+ double sbXpGainedLvl = 0;
+ int catacombsLvl = 0;
+ if (skyblockInfo != null && skyblockInfo.containsKey("catacombs")) {
+ ProfileViewer.Level catacombs = skyblockInfo.get("catacombs");
+
+ catacombsLvl = (int) catacombs.level;
+ for (int i = 1; i <= catacombs.level; i++) {
+ if (40 > i) {
+ sbXpGainedLvl += 20;
+ } else {
+ sbXpGainedLvl += 40;
+ }
+ }
+
+ List<String> dungeonClasses = Arrays.asList("healer", "tank", "mage", "archer", "berserk");
+ for (String dungeonClass : dungeonClasses) {
+ ProfileViewer.Level level = skyblockInfo.get(dungeonClass);
+ for (int i = 1; i <= level.level; i++) {
+ if (i <= 50) sbXpGainedClass += dungeonTask.get("class_xp").getAsInt();
+ }
+ }
+
+ JsonArray completeCatacombs = dungeonTask.get("complete_catacombs").getAsJsonArray();
+ int index = 0;
+ for (JsonElement completeCatacomb : completeCatacombs) {
+ int value = completeCatacomb.getAsInt();
+ JsonObject normalCompletions = Utils
+ .getElement(object, "dungeons.dungeon_types.catacombs.tier_completions")
+ .getAsJsonObject();
+ if (normalCompletions.has(index + "")) {
+ sbLevelGainedFloor = sbLevelGainedFloor + value;
+ }
+ index++;
+ }
+
+ int masterCatacombs = dungeonTask.get("complete_master_catacombs").getAsInt();
+ for (int i = 0; i <= 7; i++) {
+ JsonElement masterCompletions = Utils
+ .getElementOrDefault(object, "dungeons.dungeon_types.master_catacombs.tier_completions", null);
+ if (masterCompletions != null) {
+ if (masterCompletions.getAsJsonObject().has(i + "")) {
+ sbLevelGainedFloor = sbLevelGainedFloor + masterCatacombs;
+ }
+ }
+ }
+ }
+
+ int catacombsLevelUp = dungeonTask.get("catacombs_level_up").getAsInt();
+ int classLevelUp = dungeonTask.get("class_level_up").getAsInt();
+ int completeDungeon = dungeonTask.get("complete_dungeon").getAsInt();
+ int totalGainful = catacombsLevelUp + classLevelUp + completeDungeon;
+ double totalXp = sbXpGainedLvl + sbXpGainedClass + sbLevelGainedFloor;
+
+ List<String> lore = new ArrayList<>();
+
+ lore.add(levelPage.buildLore("Catacombs Level Up", sbXpGainedLvl, catacombsLevelUp, false));
+ lore.add(levelPage.buildLore("Class Level Up", sbXpGainedClass, classLevelUp, false));
+ lore.add(levelPage.buildLore("Complete Dungeons", sbLevelGainedFloor, completeDungeon, false));
+
+ levelPage.renderLevelBar(
+ "Dungeon",
+ NotEnoughUpdates.INSTANCE.manager
+ .createItemResolutionQuery()
+ .withKnownInternalName("WITHER_RELIC")
+ .resolveToItemStack(),
+ guiLeft + 23,
+ guiTop + 55,
+ 110,
+ catacombsLvl,
+ totalXp,
+ totalGainful,
+ 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
new file mode 100644
index 00000000..d64f54c1
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/EssenceTaskLevel.java
@@ -0,0 +1,140 @@
+/*
+ * 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.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.profileviewer.level.LevelPage;
+import io.github.moulberry.notenoughupdates.util.Constants;
+import net.minecraft.util.EnumChatFormatting;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class EssenceTaskLevel {
+
+ private final LevelPage levelPage;
+
+ public EssenceTaskLevel(LevelPage levelPage) {this.levelPage = levelPage;}
+
+ public void drawTask(JsonObject object, int mouseX, int mouseY, int guiLeft, int guiTop) {
+ List<String> lore = new ArrayList<>();
+
+ JsonObject categoryXp = levelPage.getConstant().get("category_xp").getAsJsonObject();
+ JsonObject essenceShopTask = levelPage.getConstant().get("essence_shop_task").getAsJsonObject();
+ JsonArray essenceSteps = essenceShopTask.get("essence_shop_xp").getAsJsonArray();
+ JsonObject essencePerks = object.get("perks").getAsJsonObject();
+
+ Map<String, EssenceShop> loreMap = new HashMap<>();
+ for (Map.Entry<String, JsonElement> stringJsonElementEntry : Constants.ESSENCESHOPS.entrySet()) {
+ String name = stringJsonElementEntry.getKey();
+ JsonObject individualObjects = stringJsonElementEntry.getValue().getAsJsonObject();
+ for (Map.Entry<String, JsonElement> jsonElementEntry : individualObjects.entrySet()) {
+ String key = jsonElementEntry.getKey();
+ if (!essencePerks.has(key)) {
+ continue;
+ }
+
+ int essenceAmount = essencePerks.get(key).getAsInt();
+
+ int amountReceivedForEach = 0;
+ for (int i = essenceAmount - 1; i >= 0; i--) {
+ amountReceivedForEach += essenceSteps.get(i).getAsInt();
+ }
+ if (!loreMap.containsKey(name)) {
+ EssenceShop value = new EssenceShop();
+ value.current += amountReceivedForEach;
+ value.name = name;
+ loreMap.put(name, value);
+ } else {
+ EssenceShop essenceShop = loreMap.get(name);
+ essenceShop.current += amountReceivedForEach;
+ }
+ }
+ }
+
+ // bad workaround (pls fix later maybe)
+ for (Map.Entry<String, JsonElement> stringJsonElementEntry : essenceShopTask.entrySet()) {
+ String key = stringJsonElementEntry.getKey();
+ if (!key.endsWith("_shop")) continue;
+ String name = key.split("_shop")[0].toUpperCase();
+ if (!loreMap.containsKey(name)) {
+ loreMap.put(name, new EssenceShop().setName(name).setCurrent(0));
+ }
+ }
+
+ int total = 0;
+ for (Map.Entry<String, EssenceShop> stringEssenceShopEntry : loreMap.entrySet()) {
+ String key = stringEssenceShopEntry.getKey();
+ EssenceShop value = stringEssenceShopEntry.getValue();
+ value.name = NotEnoughUpdates.INSTANCE.manager
+ .createItemResolutionQuery()
+ .withKnownInternalName(key)
+ .resolveToItemListJson()
+ .get("displayname")
+ .getAsString();
+ value.max = essenceShopTask.get(key.toLowerCase() + "_shop").getAsInt();
+ lore.add(levelPage.buildLore(
+ EnumChatFormatting.getTextWithoutFormattingCodes(value.name),
+ value.current,
+ value.max,
+ false
+ ));
+ total += value.current;
+ }
+
+ levelPage.renderLevelBar(
+ "Essence",
+ NotEnoughUpdates.INSTANCE.manager.createItemResolutionQuery()
+ .withKnownInternalName("ESSENCE_WITHER")
+ .resolveToItemStack(),
+ guiLeft + 299,
+ guiTop + 25,
+ 110,
+ total,
+ total,
+ categoryXp.get("essence_shop_task").getAsInt(),
+ mouseX,
+ mouseY,
+ true,
+ lore
+ );
+ }
+
+ class EssenceShop {
+ String name;
+ double max;
+ double current;
+
+ public EssenceShop setCurrent(double current) {
+ this.current = current;
+ return this;
+ }
+
+ public EssenceShop setName(String name) {
+ this.name = name;
+ return this;
+ }
+ }
+}
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
new file mode 100644
index 00000000..a717664d
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/MiscTaskLevel.java
@@ -0,0 +1,200 @@
+/*
+ * 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.CrimsonIslePage;
+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;
+
+public class MiscTaskLevel {
+
+ private final LevelPage levelPage;
+
+ public MiscTaskLevel(LevelPage levelPage) {this.levelPage = levelPage;}
+
+ public void drawTask(JsonObject object, int mouseX, int mouseY, int guiLeft, int guiTop) {
+ JsonObject miscellaneousTask = levelPage.getConstant().getAsJsonObject("miscellaneous_task");
+ // I love doing this on god!!!
+
+ int sbXpAccessoryUpgrade = 0;
+ int sbXpReaperPeppers = 0;
+ int sbXpUnlockedPowers = 0;
+ int sbXpAbiphone = 0;
+ if (object.has("accessory_bag_storage")) {
+ JsonObject accessoryBagStorage = object.getAsJsonObject("accessory_bag_storage");
+
+ sbXpAccessoryUpgrade = Utils.getElementAsInt(Utils.getElement(
+ accessoryBagStorage,
+ "bag_upgrades_purchased"
+ ), 0) * miscellaneousTask.get("accessory_bag_upgrades_xp").getAsInt();
+ sbXpReaperPeppers =
+ miscellaneousTask.get("reaper_peppers_xp").getAsInt() * Utils.getElementAsInt(Utils.getElement(
+ object,
+ "reaper_peppers_eaten"
+ ), 0);
+ if (accessoryBagStorage.has("unlocked_powers")) sbXpUnlockedPowers = accessoryBagStorage.getAsJsonArray(
+ "unlocked_powers").size() * miscellaneousTask.get("unlocking_powers_xp").getAsInt();
+ }
+
+ int sbXpDojo = 0;
+ if (object.has("nether_island_player_data")) {
+ JsonObject netherIslandPlayerData = object.getAsJsonObject("nether_island_player_data");
+ if (netherIslandPlayerData.has("dojo")) {
+ JsonObject dojoScoresObj = netherIslandPlayerData.getAsJsonObject("dojo");
+
+ int pointsTotal = 0;
+ for (int i = 0; i < CrimsonIslePage.apiDojoTestNames.size(); i++) {
+ for (Map.Entry<String, JsonElement> dojoData : dojoScoresObj.entrySet()) {
+ if (dojoData.getKey().equals("dojo_points_" + CrimsonIslePage.apiDojoTestNames.keySet().toArray()[i])) {
+ pointsTotal += dojoData.getValue().getAsInt();
+ }
+ }
+ }
+ int index = getRankIndex(pointsTotal);
+ JsonArray theDojoXp = miscellaneousTask.getAsJsonArray("the_dojo_xp");
+ for (int i = 0; i < index; i++) {
+ sbXpDojo += theDojoXp.get(i).getAsInt();
+ }
+ }
+
+ // 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();
+ }
+ }
+
+ // 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;
+ }
+ }
+ }
+
+ // community upgrades
+ int sbXpCommunityUpgrade = 0;
+ JsonObject profileInformation = levelPage.getProfile().getProfileInformation(levelPage.getProfileId());
+ if (profileInformation != null && profileInformation.has("community_upgrades")) {
+ JsonObject communityUpgrades = profileInformation.getAsJsonObject("community_upgrades");
+ JsonArray upgradeStates = communityUpgrades.getAsJsonArray("upgrade_states");
+ 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;
+ }
+ }
+ }
+ }
+
+ // personal bank
+ int sbXpPersonalBank = 0;
+ if (object.has("personal_bank_upgrade")) {
+ int personalBankUpgrade = object.get("personal_bank_upgrade").getAsInt();
+ JsonArray personalBankUpgradesXpArr = miscellaneousTask.getAsJsonArray("personal_bank_upgrades_xp");
+ for (int i = 1; i <= personalBankUpgrade; i++) {
+ sbXpPersonalBank += personalBankUpgradesXpArr.get(i - 1).getAsInt();
+ }
+ }
+
+ List<String> lore = new ArrayList<>();
+
+ lore.add(levelPage.buildLore("Accessory Bag Upgrades",
+ sbXpAccessoryUpgrade, 0, true
+ ));
+ lore.add(levelPage.buildLore("Reaper Peppers",
+ sbXpReaperPeppers, miscellaneousTask.get("reaper_peppers").getAsInt(), false
+ ));
+ lore.add(levelPage.buildLore("Unlocking Powers",
+ sbXpUnlockedPowers, 0, true
+ ));
+ lore.add(levelPage.buildLore("The Dojo",
+ sbXpDojo, miscellaneousTask.get("the_dojo").getAsInt(), false
+ ));
+ lore.add(levelPage.buildLore(
+ EnumChatFormatting.ITALIC + "Harp Songs",
+ sbXpGainedHarp, miscellaneousTask.get("harp_songs").getAsInt(), false
+ ));
+ lore.add(levelPage.buildLore(EnumChatFormatting.ITALIC + "Abiphone Contacts",
+ sbXpAbiphone, miscellaneousTask.get("abiphone_contacts").getAsInt(), false
+ ));
+ lore.add(levelPage.buildLore("Community Shop Upgrades",
+ sbXpCommunityUpgrade, miscellaneousTask.get("community_shop_upgrades").getAsInt(), false
+ ));
+ lore.add(levelPage.buildLore("Personal Bank Upgrades",
+ sbXpPersonalBank, miscellaneousTask.get("personal_bank_upgrades").getAsInt(), false
+ ));
+
+ levelPage.renderLevelBar(
+ "Misc. Task",
+ new ItemStack(Items.map),
+ guiLeft + 299,
+ guiTop + 55,
+ 110,
+ 0,
+ sbXpReaperPeppers + sbXpDojo + sbXpGainedHarp + sbXpAbiphone +
+ sbXpCommunityUpgrade + sbXpPersonalBank,
+ levelPage.getConstant().getAsJsonObject("category_xp").get("miscellaneous_task").getAsInt(),
+ mouseX,
+ mouseY,
+ true,
+ lore
+ );
+
+ }
+
+ private int getRankIndex(int pointsTotal) {
+ AtomicInteger index = new AtomicInteger();
+ CrimsonIslePage.dojoPointsToRank.forEach((required, name) -> {
+ if (pointsTotal > required) {
+ index.getAndIncrement();
+ }
+ });
+ return index.get();
+ }
+}
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
new file mode 100644
index 00000000..4ba7951c
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/SkillRelatedTaskLevel.java
@@ -0,0 +1,225 @@
+/*
+ * 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.ProfileViewer;
+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.init.Items;
+import net.minecraft.item.ItemStack;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class SkillRelatedTaskLevel {
+
+ private final LevelPage levelPage;
+
+ public SkillRelatedTaskLevel(LevelPage levelPage) {this.levelPage = levelPage;}
+
+ public void drawTask(JsonObject object, int mouseX, int mouseY, int guiLeft, int guiTop) {
+ 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(
+ Utils.getElementOrDefault(Constants.LEVELING, "HOTM", new JsonArray()).getAsJsonArray(),
+ hotmXp,
+ 7,
+ false
+ );
+
+ int hotmXP = 0;
+ float level = levelObjHotm.level;
+ JsonArray hotmXpArray = miningObj.get("hotm_xp").getAsJsonArray();
+ for (int i = 1; i <= level; i++) {
+ 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;
+ }
+
+ int gainByFirstGemstoneThing;
+ if (gemstone >= 350_000) {
+ gainByFirstGemstoneThing = (int) (350_000 / 2500d);
+ gemstone -= 350_000;
+ } else {
+ gainByFirstGemstoneThing = (int) (gemstone / 2500d);
+ gemstone = 0;
+ }
+
+ int sbXpMithrilPowder = (int) powder(3.75, mithril, 12_500_000);
+ int sbXpGemstonePowder = (int) powder(4.25, gemstone, 20_000_000);
+
+ double sbXpHotmTier =
+ (sbXpMithrilPowder + gainByFirstMithrilThing) + (sbXpGemstonePowder + gainByFirstGemstoneThing)
+ + hotmXP;
+
+ int sbXpPotmTier = 0;
+ JsonArray potmXpArray = miningObj.get("potm_xp").getAsJsonArray();
+
+ int potm = ((Utils.getElementAsInt(Utils.getElement(object, "mining_core.nodes.special_0"), 0)));
+ for (int i = 1; i <= potm; i++) {
+ sbXpPotmTier += potmXpArray.get(i - 1).getAsInt();
+ }
+
+ int sbXpCommissionMilestone = 0;
+ JsonArray tutorialArray = object.get("tutorial").getAsJsonArray();
+ JsonArray commissionMilestoneXpArray = miningObj.get("commission_milestone_xp").getAsJsonArray();
+ for (JsonElement jsonElement : tutorialArray) {
+ if (jsonElement.getAsJsonPrimitive().isString() && jsonElement.getAsString().startsWith(
+ "commission_milestone_reward_skyblock_xp_tier"))
+ for (int i = 1; i <= commissionMilestoneXpArray.size(); i++) {
+ int value = commissionMilestoneXpArray.get(i - 1).getAsInt();
+ if (jsonElement.getAsString().equals("commission_milestone_reward_skyblock_xp_tier_" + i)) {
+ sbXpCommissionMilestone += value;
+ }
+ }
+ }
+
+ // rock mines
+ float pet_milestone_ores_mined = Utils.getElementAsFloat(Utils.getElement(
+ object,
+ "stats.pet_milestone_ores_mined"
+ ), 0);
+
+ int sbXpRockPet = 0;
+ int rockMilestoneXp = miningObj.get("rock_milestone_xp").getAsInt();
+ JsonArray rockMilestoneRequired = miningObj.get("rock_milestone_required").getAsJsonArray();
+ for (JsonElement jsonElement : rockMilestoneRequired) {
+ int value = jsonElement.getAsInt();
+ if (pet_milestone_ores_mined >= value) {
+ sbXpRockPet += rockMilestoneXp;
+ }
+ }
+
+ // farming
+ JsonObject farmingObj = skillRelatedTask.get("farming").getAsJsonObject();
+ int anitaShopUpgradesXp = farmingObj.get("anita_shop_upgrades_xp").getAsInt();
+ int doubleDrops = Utils.getElementAsInt(Utils.getElement(object, "jacob2.perks.double_drops"), 0);
+ int farmingLevelCap = Utils.getElementAsInt(Utils.getElement(object, "jacob2.perks.farming_level_cap"), 0);
+
+ int sbXpGainedByAnita = (doubleDrops + farmingLevelCap) * anitaShopUpgradesXp;
+
+ // fishing
+ int sbXpTrophyFish = 0;
+ JsonObject fishingObj = skillRelatedTask.get("fishing").getAsJsonObject();
+
+ JsonArray trophyFishXpArr = fishingObj.get("trophy_fish_xp").getAsJsonArray();
+ if (object.has("trophy_fish")) {
+
+ JsonObject trophyFish = object.get("trophy_fish").getAsJsonObject();
+ for (Map.Entry<String, JsonElement> stringJsonElementEntry : trophyFish.entrySet()) {
+ String key = stringJsonElementEntry.getKey();
+ if (stringJsonElementEntry.getValue().isJsonPrimitive()) {
+ if (key.endsWith("_bronze")) sbXpTrophyFish += trophyFishXpArr.get(0).getAsInt();
+ if (key.endsWith("_silver")) sbXpTrophyFish += trophyFishXpArr.get(1).getAsInt();
+ if (key.endsWith("_gold")) sbXpTrophyFish += trophyFishXpArr.get(2).getAsInt();
+ if (key.endsWith("_diamond")) sbXpTrophyFish += trophyFishXpArr.get(3).getAsInt();
+ }
+ }
+
+ }
+ float petMilestoneKilled = Utils.getElementAsFloat(
+ Utils.getElement(object, "stats.pet_milestone_sea_creatures_killed"),
+ 0
+ );
+
+ int sbXpDolphinPet = 0;
+ int dolphinMilestoneXp = fishingObj.get("dolphin_milestone_xp").getAsInt();
+ JsonArray dolphinMilestoneRequired = fishingObj.get("dolphin_milestone_required").getAsJsonArray();
+ for (JsonElement jsonElement : dolphinMilestoneRequired) {
+ int value = jsonElement.getAsInt();
+ if (petMilestoneKilled >= value) {
+ sbXpDolphinPet += dolphinMilestoneXp;
+ }
+ }
+
+ List<String> lore = new ArrayList<>();
+ lore.add(levelPage.buildLore("Heart of the Mountain", sbXpHotmTier, miningObj.get("hotm").getAsInt(), false));
+ lore.add(levelPage.buildLore(
+ "Commission Milestones",
+ sbXpCommissionMilestone,
+ miningObj.get("commission_milestone").getAsInt(),
+ false
+ ));
+ lore.add(levelPage.buildLore("Crystal Nucleus", 0, 0, false));
+ lore.add(levelPage.buildLore(
+ "Anita's Shop Upgrade",
+ sbXpGainedByAnita,
+ farmingObj.get("anita_shop_upgrades").getAsInt(),
+ false
+ ));
+ 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
+ ));
+
+ levelPage.renderLevelBar(
+ "Skill Related Task",
+ new ItemStack(Items.diamond_sword),
+ guiLeft + 23,
+ guiTop + 115,
+ 110,
+ 0,
+ sbXpHotmTier + sbXpCommissionMilestone + sbXpGainedByAnita + sbXpPotmTier + sbXpTrophyFish + sbXpRockPet +
+ sbXpDolphinPet,
+ levelPage.getConstant().getAsJsonObject("category_xp").get("skill_related_task").getAsInt(),
+ 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
new file mode 100644
index 00000000..3aded435
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/SlayingTaskLevel.java
@@ -0,0 +1,264 @@
+/*
+ * 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.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.profileviewer.CrimsonIslePage;
+import io.github.moulberry.notenoughupdates.profileviewer.ExtraPage;
+import io.github.moulberry.notenoughupdates.profileviewer.GuiProfileViewer;
+import io.github.moulberry.notenoughupdates.profileviewer.ProfileViewer;
+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 java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class SlayingTaskLevel {
+
+ private final LevelPage levelPage;
+ private final int[] bossLow = {25, 50, 100, 150, 250, 1000};
+ private final int[] thorn = {25, 50, 150, 250, 400, 1000};
+ private final int[] bossHigh = {50, 100, 150, 250, 500, 750, 1000};
+
+
+ public SlayingTaskLevel(LevelPage levelPage) {this.levelPage = levelPage;}
+
+ public void drawTask(JsonObject object, int mouseX, int mouseY, int guiLeft, int guiTop) {
+ // slayer
+ JsonObject slayingTask = levelPage.getConstant().get("slaying_task").getAsJsonObject();
+ JsonArray slayerLevelUpXp = slayingTask.get("slayer_level_up_xp").getAsJsonArray();
+ Map<String, ProfileViewer.Level> skyblockInfo = levelPage.getProfile().getSkyblockInfo(levelPage.getProfileId());
+
+ int sbXpGainedSlayer = 0;
+ if (skyblockInfo != null) {
+ for (String slayer : ProfileViewer.SLAYERS) {
+ ProfileViewer.Level level = skyblockInfo.get(slayer);
+ for (int i = 0; i < (int) level.level; i++) {
+ int asInt = slayerLevelUpXp.get(i).getAsInt();
+ sbXpGainedSlayer += asInt;
+ }
+ }
+ }
+
+ JsonObject bossCollectionsXp = slayingTask.getAsJsonObject("boss_collections_xp");
+
+ HashMap<String, Double> allComps = new HashMap<>();
+ JsonElement normalCompletions = Utils
+ .getElement(object, "dungeons.dungeon_types.catacombs.tier_completions");
+
+ JsonElement masterCompletions = Utils
+ .getElement(object, "dungeons.dungeon_types.master_catacombs.tier_completions");
+
+ if (normalCompletions != null) {
+ HashMap<String, Double> normalCompMap = NotEnoughUpdates.INSTANCE.manager.gson.fromJson(
+ normalCompletions.getAsJsonObject(),
+ HashMap.class
+ );
+ normalCompMap.forEach((floor, value) -> {
+ if (allComps.containsKey(floor)) {
+ allComps.put(floor, allComps.get(floor) + value);
+ } else {
+ allComps.put(floor, value);
+ }
+ });
+ }
+ if (masterCompletions != null) {
+ HashMap<String, Double> masterCompMap = NotEnoughUpdates.INSTANCE.manager.gson.fromJson(
+ masterCompletions.getAsJsonObject(),
+ HashMap.class
+ );
+
+ masterCompMap.forEach((floor, value) -> {
+ if (allComps.containsKey(floor)) {
+ allComps.put(floor, allComps.get(floor) + value);
+ } else {
+ allComps.put(floor, value);
+ }
+ });
+ }
+ // THIS SERVER IS AWESOME I LOVE CONSISTENCY!!!!!!!
+
+ int bossCollectionXp = 0;
+ JsonArray dungeonCollectionXp = bossCollectionsXp.getAsJsonArray("dungeon_collection_xp");
+ for (int i = 1; i <= 7; i++) {
+ if (!allComps.containsKey(i + "")) continue;
+ double value = allComps.get(i + "");
+ switch (i) {
+ case 1:
+ case 2:
+ case 3:
+ bossCollectionXp += loopThroughCollection(bossLow, value, dungeonCollectionXp);
+ break;
+ case 4:
+ bossCollectionXp += loopThroughCollection(thorn, value, dungeonCollectionXp);
+ break;
+ case 5:
+ case 6:
+ case 7:
+ bossCollectionXp += loopThroughCollection(bossHigh, value, dungeonCollectionXp);
+ break;
+ }
+ }
+
+ JsonArray defeatKuudraXp = slayingTask.get("defeat_kuudra_xp").getAsJsonArray();
+ // kuudra
+
+ int sbXpDefeatKuudra = 0;
+
+ int kuudraBossCollection = 0;
+ if (object.has("nether_island_player_data")) {
+ JsonObject jsonObject = object.getAsJsonObject("nether_island_player_data").getAsJsonObject(
+ "kuudra_completed_tiers");
+ for (Map.Entry<String, JsonElement> stringJsonElementEntry : jsonObject.entrySet()) {
+ String key = stringJsonElementEntry.getKey();
+ int value = stringJsonElementEntry.getValue().getAsInt();
+
+ int i = 0;
+ for (String kuudraTier : CrimsonIslePage.KUUDRA_TIERS) {
+ if (key.equals(kuudraTier)) {
+ sbXpDefeatKuudra += defeatKuudraXp.get(i).getAsInt();
+ kuudraBossCollection += (i + 1) * value;
+ }
+ i++;
+ }
+ }
+ if (kuudraBossCollection >= 10) bossCollectionXp += 10;
+ if (kuudraBossCollection >= 100) bossCollectionXp += 15;
+ if (kuudraBossCollection >= 500) bossCollectionXp += 20;
+ if (kuudraBossCollection >= 2000) bossCollectionXp += 25;
+ if (kuudraBossCollection >= 5000) bossCollectionXp += 30;
+ }
+
+ int sbXpBestiary = 0;
+ int bestiaryTiers = GuiProfileViewer.getProfile().getBestiaryTiers(object);
+ sbXpBestiary += bestiaryTiers;
+ sbXpBestiary = sbXpBestiary + (sbXpBestiary / 10) * 2;
+
+ int mythologicalKillsXp = 0;
+ if (object.has("stats")) {
+ JsonObject stats = object.get("stats").getAsJsonObject();
+ if (stats.has("mythos_kills")) mythologicalKillsXp += (stats.get("mythos_kills").getAsLong() / 100);
+ }
+
+ int mythologicalKillsMax = slayingTask.get("mythological_kills").getAsInt();
+ if (mythologicalKillsXp > mythologicalKillsMax) mythologicalKillsXp = mythologicalKillsMax;
+
+ // dragons
+ int sbXpFromDragonKills = 0;
+ JsonObject slayDragonsXp = slayingTask.getAsJsonObject("slay_dragons_xp");
+ for (Map.Entry<String, JsonElement> stringJsonElementEntry : slayDragonsXp.entrySet()) {
+ String key = stringJsonElementEntry.getKey();
+ int value = stringJsonElementEntry.getValue().getAsInt();
+ // kills_superior_dragon_100
+ float element = Utils.getElementAsFloat(Utils.getElement(object, "bestiary.kills_" + key + "_100"), 0);
+ if (element > 0) {
+ sbXpFromDragonKills += value;
+ }
+ }
+
+ // slayer kills
+ int sbXpFromSlayerDefeat = 0;
+
+ JsonArray defeatSlayersXp = slayingTask.get("defeat_slayers_xp").getAsJsonArray();
+ for (String s : ExtraPage.slayers.keySet()) {
+ int maxLevel = ExtraPage.slayers.get(s);
+ for (int i = 0; i < 5; i++) {
+ if (i >= maxLevel) break;
+ float tier = Utils.getElementAsFloat(
+ Utils.getElement(object, "slayer_bosses." + s + ".boss_kills_tier_" + i),
+ 0
+ );
+ if (tier != 0) {
+ int value = defeatSlayersXp.get(i).getAsInt();
+ sbXpFromSlayerDefeat += value;
+ }
+ }
+ }
+
+ // arachne
+ JsonArray defeatArachneXp = slayingTask.get("defeat_arachne_xp").getAsJsonArray();
+ int sbXpGainedArachne = 0;
+
+ JsonElement tier1 = Utils.getElement(object, "bestiary.kills_arachne_300");
+ if (tier1 != null) {
+ sbXpGainedArachne += defeatArachneXp.get(0).getAsInt();
+ }
+
+ JsonElement tier2 = Utils.getElement(object, "bestiary.kills_arachne_500");
+ if (tier2 != null) {
+ sbXpGainedArachne += defeatArachneXp.get(1).getAsInt();
+ }
+
+ List<String> lore = new ArrayList<>();
+
+ int slayerLevelUpMax = slayingTask.get("slayer_level_up").getAsInt();
+ int bossCollectionsMax = slayingTask.get("boss_collections").getAsInt();
+ int slayDragonsMax = slayingTask.get("slay_dragons").getAsInt();
+ int defeatSlayersMax = slayingTask.get("defeat_slayers").getAsInt();
+ int defeatKuudraMax = slayingTask.get("defeat_kuudra").getAsInt();
+ int defeatArachneMax = slayingTask.get("defeat_arachne").getAsInt();
+
+ lore.add(levelPage.buildLore("Slayer Level Up", sbXpGainedSlayer, slayerLevelUpMax, false));
+ lore.add(levelPage.buildLore("Boss Collections", bossCollectionXp, bossCollectionsMax, false));
+ lore.add(levelPage.buildLore("Bestiary Progress", sbXpBestiary, 0, true));
+ lore.add(levelPage.buildLore("Mythological Kills", mythologicalKillsXp, mythologicalKillsMax, false));
+ lore.add(levelPage.buildLore("Slay Dragons", sbXpFromDragonKills, slayDragonsMax, false));
+ lore.add(levelPage.buildLore("Defeat Slayers", sbXpFromSlayerDefeat, defeatSlayersMax, false));
+ lore.add(levelPage.buildLore("Defeat Kuudra", sbXpDefeatKuudra, defeatKuudraMax, false));
+ lore.add(levelPage.buildLore("Defeat Arachne", sbXpGainedArachne, defeatArachneMax, false));
+
+ int slayingTaskMax = levelPage.getConstant().getAsJsonObject("category_xp").get("slaying_task").getAsInt();
+
+ levelPage.renderLevelBar(
+ "Slaying Task",
+ new ItemStack(Items.golden_sword),
+ guiLeft + 23,
+ guiTop + 85,
+ 110,
+ 0, sbXpGainedSlayer + bossCollectionXp + mythologicalKillsXp +
+ sbXpFromDragonKills + sbXpFromSlayerDefeat + sbXpDefeatKuudra + sbXpGainedArachne,
+ slayingTaskMax,
+ mouseX,
+ mouseY,
+ true,
+ lore
+ );
+ }
+
+ private int loopThroughCollection(int[] array, double value, JsonArray jsonArray) {
+ int i = 0;
+ int gain = 0;
+ for (int bossReq : array) {
+ if (value >= bossReq) {
+ int gained = jsonArray.get(i).getAsInt();
+ gain += gained;
+ }
+ i++;
+ }
+ return gain;
+ }
+}
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
new file mode 100644
index 00000000..2b1b59cb
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/StoryTaskLevel.java
@@ -0,0 +1,76 @@
+/*
+ * 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 StoryTaskLevel {
+
+ private final LevelPage levelPage;
+
+ public StoryTaskLevel(LevelPage levelPage) {this.levelPage = levelPage;}
+
+ public void drawTask(JsonObject object, int mouseX, int mouseY, int guiLeft, int guiTop) {
+ JsonObject storyTask = levelPage.getConstant().getAsJsonObject("story_task");
+ JsonArray storyTaskNames = storyTask.getAsJsonArray("complete_objectives_names");
+
+ JsonObject objectives = object.getAsJsonObject("objectives");
+
+ int storyTaskXp = storyTask.get("complete_objectives_xp").getAsInt();
+ int sbXpStory = 0;
+ for (JsonElement storyTaskName : storyTaskNames) {
+ String value = storyTaskName.getAsString();
+ if (objectives.has(value)) {
+ JsonObject jsonObject = objectives.get(value).getAsJsonObject();
+ if (jsonObject.has("status") && jsonObject.get("status").getAsString().equals("COMPLETE")) {
+ sbXpStory += storyTaskXp;
+ }
+ }
+ }
+
+ List<String> lore = new ArrayList<>();
+ lore.add(levelPage.buildLore("Complete Objectives",
+ sbXpStory, storyTask.get("complete_objectives").getAsInt(), false
+ ));
+
+ levelPage.renderLevelBar(
+ "Story Task",
+ new ItemStack(Items.map),
+ guiLeft + 299,
+ guiTop + 85,
+ 110,
+ 0,
+ sbXpStory,
+ levelPage.getConstant().getAsJsonObject("category_xp").get("story_task").getAsInt(),
+ mouseX,
+ mouseY,
+ true,
+ lore
+ );
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/Constants.java b/src/main/java/io/github/moulberry/notenoughupdates/util/Constants.java
index 6b1bef26..6819ccc4 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/util/Constants.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/Constants.java
@@ -43,6 +43,7 @@ import java.util.regex.Pattern;
@NEUAutoSubscribe
public class Constants {
+
private static class PatternSerializer implements JsonDeserializer<Pattern>, JsonSerializer<Pattern> {
@Override
public Pattern deserialize(
@@ -80,6 +81,7 @@ public class Constants {
public static JsonObject RNGSCORE;
public static JsonObject ABIPHONE;
public static JsonObject ESSENCESHOPS;
+ public static JsonObject SBLEVELS;
private static final ReentrantLock lock = new ReentrantLock();
@@ -104,6 +106,7 @@ public class Constants {
RNGSCORE = Utils.getConstant("rngscore", gson);
ABIPHONE = Utils.getConstant("abiphone", gson);
ESSENCESHOPS = Utils.getConstant("essenceshops", gson);
+ SBLEVELS = Utils.getConstant("sblevels", gson);
parseEssenceCosts();
} catch (Exception ex) {
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 571a43f9..952eb50f 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java
@@ -28,6 +28,7 @@ import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import io.github.moulberry.notenoughupdates.miscfeatures.SlotLocking;
+import io.github.moulberry.notenoughupdates.profileviewer.GuiProfileViewer;
import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
import net.minecraft.client.audio.PositionedSoundRecord;
@@ -569,6 +570,70 @@ public class Utils {
drawTexturedRect(x, y, width, height, 0, 1, 0, 1);
}
+ public static void drawPvSideButton(
+ int yIndex,
+ ItemStack itemStack,
+ boolean pressed,
+ GuiProfileViewer guiProfileViewer
+ ) {
+ int guiLeft = GuiProfileViewer.getGuiLeft();
+ int guiTop = GuiProfileViewer.getGuiTop();
+
+ GlStateManager.disableLighting();
+ GlStateManager.enableBlend();
+ GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
+ GlStateManager.enableAlpha();
+ GlStateManager.alphaFunc(516, 0.1F);
+
+ int x = guiLeft - 28;
+ int y = guiTop + yIndex * 28;
+
+ float uMin = 193 / 256f;
+ float uMax = 223 / 256f;
+ float vMin = 200 / 256f;
+ float vMax = 228 / 256f;
+ if (pressed) {
+ uMin = 224 / 256f;
+ uMax = 1f;
+
+ if (yIndex != 0) {
+ vMin = 228 / 256f;
+ vMax = 1f;
+ }
+
+ guiProfileViewer.renderBlurredBackground(
+ guiProfileViewer.width,
+ guiProfileViewer.height,
+ x + 2,
+ y + 2,
+ 30,
+ 28 - 4
+ );
+ } else {
+ guiProfileViewer.renderBlurredBackground(
+ guiProfileViewer.width,
+ guiProfileViewer.height,
+ x + 2,
+ y + 2,
+ 28 - 2,
+ 28 - 4
+ );
+ }
+
+ GlStateManager.disableLighting();
+ GlStateManager.enableBlend();
+ GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
+ GlStateManager.enableAlpha();
+ GlStateManager.alphaFunc(516, 0.1F);
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(GuiProfileViewer.pv_elements);
+
+ Utils.drawTexturedRect(x, y, pressed ? 32 : 28, 28, uMin, uMax, vMin, vMax, GL11.GL_NEAREST);
+
+ GlStateManager.enableDepth();
+ Utils.drawItemStack(itemStack, x + 8, y + 7);
+ }
+
public static void drawTexturedRect(float x, float y, float width, float height, int filter) {
drawTexturedRect(x, y, width, height, 0, 1, 0, 1, filter);
}
@@ -1961,13 +2026,13 @@ public class Utils {
if (NotEnoughUpdates.INSTANCE.config.notifications.outdatedRepo) {
NotificationHandler.displayNotification(Lists.newArrayList(
EnumChatFormatting.RED + EnumChatFormatting.BOLD.toString() + "Missing repo data",
- EnumChatFormatting.RED +
- "Data used for many NEU features is not up to date, this should normally not be the case.",
- EnumChatFormatting.RED + "You can try " + EnumChatFormatting.BOLD + "/neuresetrepo" + EnumChatFormatting.RESET +
- EnumChatFormatting.RED + " and restart your game" +
- " to see if that fixes the issue.",
- EnumChatFormatting.RED + "If the problem persists please join " + EnumChatFormatting.BOLD +
- "discord.gg/moulberry" +
+ EnumChatFormatting.RED +
+ "Data used for many NEU features is not up to date, this should normally not be the case.",
+ EnumChatFormatting.RED + "You can try " + EnumChatFormatting.BOLD + "/neuresetrepo" + EnumChatFormatting.RESET +
+ EnumChatFormatting.RED + " and restart your game" +
+ " to see if that fixes the issue.",
+ EnumChatFormatting.RED + "If the problem persists please join " + EnumChatFormatting.BOLD +
+ "discord.gg/moulberry" +
EnumChatFormatting.RESET + EnumChatFormatting.RED + " and message in " + EnumChatFormatting.BOLD +
"#neu-support" + EnumChatFormatting.RESET + EnumChatFormatting.RED + " to get support"
),
diff --git a/src/main/kotlin/io/github/moulberry/notenoughupdates/util/hypixelapi/Collection.kt b/src/main/kotlin/io/github/moulberry/notenoughupdates/util/hypixelapi/Collection.kt
new file mode 100644
index 00000000..b2c7fcec
--- /dev/null
+++ b/src/main/kotlin/io/github/moulberry/notenoughupdates/util/hypixelapi/Collection.kt
@@ -0,0 +1,159 @@
+/*
+ * 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.hypixelapi
+
+import com.google.gson.JsonArray
+import com.google.gson.JsonObject
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates
+import java.math.BigInteger
+import java.util.concurrent.CompletableFuture
+import kotlin.collections.List
+import kotlin.collections.Map
+import kotlin.collections.component1
+import kotlin.collections.component2
+import kotlin.collections.filter
+import kotlin.collections.flatMap
+import kotlin.collections.groupBy
+import kotlin.collections.mapNotNull
+import kotlin.collections.mapValues
+import kotlin.collections.maxOf
+import kotlin.collections.sumOf
+import kotlin.collections.toList
+import kotlin.collections.toMap
+import kotlin.collections.toSet
+
+data class ProfileCollectionInfo(
+ val collections: Map<String, CollectionInfo>,
+ val craftedGenerators: Map<String, Int>,
+) {
+ data class CollectionInfo(
+ val collection: Collection,
+ val totalCollectionCount: BigInteger,
+ val personalCollectionCount: BigInteger,
+ val unlockedTiers: List<CollectionTier>,
+ )
+
+ class CollectionMetadata internal constructor() {
+ lateinit var collections: Map<String, CollectionCategory>
+ private set
+ val allCollections by lazy { collections.values.flatMap { it.items.toList() }.toMap() }
+ }
+
+ class CollectionCategory internal constructor() {
+ lateinit var items: Map<String, Collection>
+ private set
+ }
+
+ class Collection internal constructor() {
+ lateinit var name: String
+ private set
+ var maxTiers: Int = -1
+ private set
+ lateinit var tiers: List<CollectionTier>
+ private set
+
+ override fun toString(): String {
+ return "Collection(name=$name, maxTiers=$maxTiers, tiers=$tiers)"
+ }
+ }
+
+ class CollectionTier internal constructor() {
+ var tier: Int = -1
+ private set
+ var amountRequired: Int = -1
+ private set
+ lateinit var unlocks: List<String>
+ private set
+
+ override fun toString(): String {
+ return "CollectionTier(tier=$tier, amountRequired=$amountRequired, unlocks=$unlocks)"
+ }
+ }
+
+
+ companion object {
+
+
+ val generatorPattern = "^([^0-9]+)_([0-9]+)$".toRegex()
+
+ val hypixelCollectionInfo: CompletableFuture<CollectionMetadata> by lazy {
+ NotEnoughUpdates.INSTANCE.manager.apiUtils
+ .newHypixelApiRequest("resources/skyblock/collections")
+ .requestJson()
+ .thenApply {
+ NotEnoughUpdates.INSTANCE.manager.gson.fromJson(it, CollectionMetadata::class.java)
+ }
+ }
+
+ fun getCollectionData(
+ profileData: JsonObject,
+ mainPlayer: String,
+ collectionData: CollectionMetadata
+ ): ProfileCollectionInfo? {
+ val mainPlayerUUID = mainPlayer.replace("-", "")
+ val members = profileData["members"] as? JsonObject ?: return null
+ val mainPlayerData =
+ (members[mainPlayerUUID] as? JsonObject ?: return null)
+ val mainPlayerCollection = mainPlayerData["collection"] as? JsonObject ?: return null
+ val memberCollections = members.entrySet().mapNotNull { (uuid, data) ->
+ if (data !is JsonObject) return null
+ data["collection"] as? JsonObject
+ }
+ val generators = members.entrySet().mapNotNull { (uuid, data) ->
+ if (data !is JsonObject) return null
+ data["crafted_generators"] as? JsonArray
+ }.flatMap { it.toList() }
+ return ProfileCollectionInfo(
+ collectionData.allCollections.mapValues { (name, collection) ->
+ val totalCollection = memberCollections.sumOf { it[name]?.asBigInteger ?: BigInteger.ZERO }
+ val personalCollection = mainPlayerCollection[name]?.asBigInteger ?: BigInteger.ZERO
+ CollectionInfo(
+ collection,
+ totalCollection,
+ personalCollection,
+ collection.tiers.filter { BigInteger.valueOf(it.amountRequired.toLong()) <= totalCollection }
+ )
+ },
+ generators.toSet()
+ .mapNotNull {
+ val pattern = generatorPattern.matchEntire(it.asString) ?: return@mapNotNull null
+ pattern.groupValues[1] to pattern.groupValues[2].toInt()
+ }
+ .groupBy { it.first }
+ .mapValues {
+ it.value.maxOf { it.second }
+ }
+ .toMap()
+ )
+ }
+
+ /**
+ * This should be the json object returned by /skyblock/profiles at profiles.<somenumber>. (aka the root tag
+ * should contain profile_id, members, cute_name, etc.)
+ */
+ @JvmStatic
+ fun getCollectionData(profileData: JsonObject, mainPlayer: String): CompletableFuture<ProfileCollectionInfo?> {
+ return hypixelCollectionInfo.thenApply {
+ getCollectionData(profileData, mainPlayer, it)
+ }
+ }
+ }
+
+}
diff --git a/src/main/resources/assets/notenoughupdates/pv_basic.png b/src/main/resources/assets/notenoughupdates/pv_basic.png
index 4d5236f5..de254644 100644
--- a/src/main/resources/assets/notenoughupdates/pv_basic.png
+++ b/src/main/resources/assets/notenoughupdates/pv_basic.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/pv_levels.png b/src/main/resources/assets/notenoughupdates/pv_levels.png
new file mode 100644
index 00000000..21810476
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/pv_levels.png
Binary files differ