summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMoulberry <james.jenour@student.scotch.wa.edu.au>2020-07-20 05:12:05 +1000
committerMoulberry <james.jenour@student.scotch.wa.edu.au>2020-07-20 05:12:05 +1000
commit8499a98beeb556c16987fc375dbd7d05d6c27ab4 (patch)
treeafd17c1abac0eb147258f8f12d33a9ee7bd21fd8
parentf7d3491def0f7498d7bf0d547445f75f0c515912 (diff)
downloadNotEnoughUpdates-8499a98beeb556c16987fc375dbd7d05d6c27ab4.tar.gz
NotEnoughUpdates-8499a98beeb556c16987fc375dbd7d05d6c27ab4.tar.bz2
NotEnoughUpdates-8499a98beeb556c16987fc375dbd7d05d6c27ab4.zip
some profile viewer stuffs
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java33
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java3
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java216
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/auction/APIManager.java16
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java315
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/PlayerStats.java537
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ProfileViewer.java370
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/questing/requirements/RequirementApi.java1
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/HypixelApi.java6
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java48
-rw-r--r--src/main/resources/assets/notenoughupdates/pv_basic.pngbin0 -> 10496 bytes
11 files changed, 1455 insertions, 90 deletions
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java b/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java
index 8d625c14..edf1d31c 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java
@@ -112,10 +112,12 @@ public class NEUManager {
public void setCurrentProfile(String currentProfile) {
this.currentProfile = currentProfile;
+ this.auctionManager.incPlayerInfoVersion();
}
public void setCurrentProfileBackup(String currentProfile) {
this.currentProfileBackup = currentProfile;
+ this.auctionManager.incPlayerInfoVersion();
}
public String getCurrentProfile() {
@@ -227,7 +229,7 @@ public class NEUManager {
public void updatePrices() {
if(System.currentTimeMillis() - auctionLastUpdate > 1000*60*120) { //2 hours
craftCost.clear();
- System.out.println("UPDATING PRICE INFORMATION");
+ System.out.println("[NEU] UPDATING PRICE INFORMATION");
auctionLastUpdate = System.currentTimeMillis();
try(Reader inReader = new InputStreamReader(new GZIPInputStream(new URL(AUCTIONS_PRICE_URL).openStream()))) {
auctionPricesJson = gson.fromJson(inReader, JsonObject.class);
@@ -349,7 +351,7 @@ public class NEUManager {
BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));
JsonObject json = gson.fromJson(reader, JsonObject.class);
return json;
- } catch(Exception e) { return null; }
+ } catch(Exception e) { e.printStackTrace(); return null; }
}
/**
@@ -389,7 +391,6 @@ public class NEUManager {
if (Display.isActive()) dialog.toFront();
if (changedFiles != null && changedFiles.size() <= 20) {
-
String startMessage = "NotEnoughUpdates: Syncing with remote repository (";
int downloaded = 0;
@@ -403,6 +404,7 @@ public class NEUManager {
File item = new File(repoLocation, name);
try {
+ item.getParentFile().mkdirs();
item.createNewFile();
} catch (IOException e) {
}
@@ -810,6 +812,7 @@ public class NEUManager {
public JsonObject getJsonFromItemBytes(String item_bytes) {
try {
NBTTagCompound tag = CompressedStreamTools.readCompressed(new ByteArrayInputStream(Base64.getDecoder().decode(item_bytes)));
+ //System.out.println(tag.toString());
return getJsonFromNBT(tag);
} catch(IOException e) {
return null;
@@ -873,7 +876,12 @@ public class NEUManager {
}
public JsonObject getJsonFromNBT(NBTTagCompound tag) {
- tag = tag.getTagList("i", 10).getCompoundTagAt(0);
+ return getJsonFromNBTEntry(tag.getTagList("i", 10).getCompoundTagAt(0));
+ }
+
+ public JsonObject getJsonFromNBTEntry(NBTTagCompound tag) {
+ if(tag.getKeySet().size() == 0) return null;
+
int id = tag.getShort("id");
int damage = tag.getShort("Damage");
int count = tag.getShort("Count");
@@ -882,6 +890,7 @@ public class NEUManager {
if(id == 141) id = 391; //for some reason hypixel thinks carrots have id 141
String internalname = getInternalnameFromNBT(tag);
+ if(internalname == null) return null;
NBTTagCompound display = tag.getCompoundTag("display");
String[] lore = getLoreFromNBT(tag);
@@ -896,15 +905,25 @@ public class NEUManager {
String clickcommand = "";
- //public JsonObject createItemJson(String internalname, String itemid, String displayname, String[] lore,
- // String crafttext, String infoType, String[] info,
- // String clickcommand, int damage, NBTTagCompound nbttag) {
JsonObject item = new JsonObject();
item.addProperty("internalname", internalname);
item.addProperty("itemid", itemid);
item.addProperty("displayname", displayname);
+ if(tag != null && tag.hasKey("ExtraAttributes", 10)) {
+ NBTTagCompound ea = tag.getCompoundTag("ExtraAttributes");
+
+ if (ea.hasKey("new_year_cake_bag_data", 7)) {
+ byte[] bytes = ea.getByteArray("new_year_cake_bag_data");
+ JsonArray bytesArr = new JsonArray();
+ for(byte b : bytes) {
+ bytesArr.add(new JsonPrimitive(b));
+ }
+ item.add("item_contents", bytesArr);
+ }
+ }
+
if(lore != null && lore.length > 0) {
JsonArray jsonLore = new JsonArray();
for (String line : lore) {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java
index 23def271..a33c13b3 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java
@@ -1097,6 +1097,9 @@ public class NEUOverlay extends Gui {
case "ducttapedigger":
searchedItems.add(CustomItems.DUCTTAPE);
break;
+ case "thirtyvirus":
+ searchedItems.add(manager.getItemInformation().get("SPIKED_BAIT"));
+ break;
}
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java
index a589fe2b..a7a30233 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java
@@ -11,6 +11,8 @@ import io.github.moulberry.notenoughupdates.commands.SimpleCommand;
import io.github.moulberry.notenoughupdates.cosmetics.CapeManager;
import io.github.moulberry.notenoughupdates.infopanes.CollectionLogInfoPane;
import io.github.moulberry.notenoughupdates.infopanes.CosmeticsInfoPane;
+import io.github.moulberry.notenoughupdates.profileviewer.GuiProfileViewer;
+import io.github.moulberry.notenoughupdates.profileviewer.ProfileViewer;
import io.github.moulberry.notenoughupdates.questing.GuiQuestLine;
import io.github.moulberry.notenoughupdates.questing.NEUQuesting;
import io.github.moulberry.notenoughupdates.util.Utils;
@@ -29,6 +31,7 @@ import net.minecraft.inventory.ContainerChest;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.CompressedStreamTools;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.scoreboard.ScoreObjective;
@@ -129,6 +132,37 @@ public class NotEnoughUpdates {
}
});
+ private static ProfileViewer profileViewer;
+
+ SimpleCommand viewProfileCommand = new SimpleCommand("neuprofile", new SimpleCommand.ProcessCommandRunnable() {
+ public void processCommand(ICommandSender sender, String[] args) {
+ if(args.length != 1) {
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.RED +
+ "idiot."));
+ }
+ profileViewer.getProfileByName(args[0], profile -> {
+ openGui = new GuiProfileViewer(profile);
+ });
+ }
+ });
+
+ SimpleCommand linksCommand = new SimpleCommand("neulinks", new SimpleCommand.ProcessCommandRunnable() {
+ public void processCommand(ICommandSender sender, String[] args) {
+ File repo = manager.repoLocation;
+ if(repo.exists()) {
+ File updateJson = new File(repo, "update.json");
+ try {
+ JsonObject update = manager.getJsonFromFile(updateJson);
+
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(""));
+ displayLinks(update);
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(""));
+ } catch (Exception ignored) {
+ }
+ }
+ }
+ });
+
SimpleCommand overlayPlacementsCommand = new SimpleCommand("neuoverlay", new SimpleCommand.ProcessCommandRunnable() {
public void processCommand(ICommandSender sender, String[] args) {
openGui = new NEUOverlayPlacements();
@@ -175,6 +209,8 @@ public class NotEnoughUpdates {
f.mkdirs();
ClientCommandHandler.instance.registerCommand(collectionLogCommand);
ClientCommandHandler.instance.registerCommand(cosmeticsCommand);
+ ClientCommandHandler.instance.registerCommand(linksCommand);
+ ClientCommandHandler.instance.registerCommand(viewProfileCommand);
ClientCommandHandler.instance.registerCommand(overlayPlacementsCommand);
//ClientCommandHandler.instance.registerCommand(questingCommand);
ClientCommandHandler.instance.registerCommand(neuAhCommand);
@@ -183,6 +219,7 @@ public class NotEnoughUpdates {
manager = new NEUManager(this, neuio, f);
manager.loadItemInformation();
overlay = new NEUOverlay(manager);
+ profileViewer = new ProfileViewer(manager);
for(KeyBinding kb : manager.keybinds) {
ClientRegistry.registerKeyBinding(kb);
@@ -203,7 +240,7 @@ public class NotEnoughUpdates {
}));
//TODO: login code. Ignore this, used for testing.
- /*try {
+ try {
Field field = Minecraft.class.getDeclaredField("session");
YggdrasilUserAuthentication auth = (YggdrasilUserAuthentication)
new YggdrasilAuthenticationService(Proxy.NO_PROXY, UUID.randomUUID().toString())
@@ -232,7 +269,7 @@ public class NotEnoughUpdates {
field.setAccessible(true);
field.set(Minecraft.getMinecraft(), session);
} catch (NoSuchFieldException | AuthenticationException | IllegalAccessException e) {
- }*/
+ }
}
/**
@@ -250,6 +287,98 @@ public class NotEnoughUpdates {
}
}
+ private void displayLinks(JsonObject update) {
+ String discord_link = update.get("discord_link").getAsString();
+ String youtube_link = update.get("youtube_link").getAsString();
+ String update_link = update.get("update_link").getAsString();
+ String github_link = update.get("github_link").getAsString();
+ String other_text = update.get("other_text").getAsString();
+ String other_link = update.get("other_link").getAsString();
+
+ ChatComponentText other = null;
+ if(other_text.length() > 0) {
+ other = new ChatComponentText(EnumChatFormatting.GRAY+"["+EnumChatFormatting.BLUE+other_text+EnumChatFormatting.GRAY+"]");
+ other.setChatStyle(Utils.createClickStyle(ClickEvent.Action.OPEN_URL, other_link));
+ }
+ ChatComponentText links = new ChatComponentText("");
+ ChatComponentText separator = new ChatComponentText(
+ EnumChatFormatting.GRAY+EnumChatFormatting.BOLD.toString()+EnumChatFormatting.STRIKETHROUGH+(other==null?"---":"--"));
+ ChatComponentText discord = new ChatComponentText(EnumChatFormatting.GRAY+"["+EnumChatFormatting.BLUE+"Discord"+EnumChatFormatting.GRAY+"]");
+ discord.setChatStyle(Utils.createClickStyle(ClickEvent.Action.OPEN_URL, discord_link));
+ ChatComponentText youtube = new ChatComponentText(EnumChatFormatting.GRAY+"["+EnumChatFormatting.RED+"YouTube"+EnumChatFormatting.GRAY+"]");
+ youtube.setChatStyle(Utils.createClickStyle(ClickEvent.Action.OPEN_URL, youtube_link));
+ ChatComponentText release = new ChatComponentText(EnumChatFormatting.GRAY+"["+EnumChatFormatting.GREEN+"Release"+EnumChatFormatting.GRAY+"]");
+ release.setChatStyle(Utils.createClickStyle(ClickEvent.Action.OPEN_URL, update_link));
+ ChatComponentText github = new ChatComponentText(EnumChatFormatting.GRAY+"["+EnumChatFormatting.DARK_PURPLE+"GitHub"+EnumChatFormatting.GRAY+"]");
+ github.setChatStyle(Utils.createClickStyle(ClickEvent.Action.OPEN_URL, github_link));
+
+
+ links.appendSibling(separator);
+ links.appendSibling(discord);
+ links.appendSibling(separator);
+ links.appendSibling(youtube);
+ links.appendSibling(separator);
+ links.appendSibling(release);
+ links.appendSibling(separator);
+ links.appendSibling(github);
+ links.appendSibling(separator);
+ if(other != null) {
+ links.appendSibling(other);
+ links.appendSibling(separator);
+ }
+
+ Minecraft.getMinecraft().thePlayer.addChatMessage(links);
+ }
+
+ private boolean displayUpdateMessageIfOutOfDate() {
+ File repo = manager.repoLocation;
+ if(repo.exists()) {
+ File updateJson = new File(repo, "update.json");
+ try {
+ JsonObject o = manager.getJsonFromFile(updateJson);
+
+ String version = o.get("version").getAsString();
+
+ if(!VERSION.equalsIgnoreCase(version)) {
+ String update_msg = o.get("update_msg").getAsString();
+ String discord_link = o.get("discord_link").getAsString();
+ String youtube_link = o.get("youtube_link").getAsString();
+ String update_link = o.get("update_link").getAsString();
+ String github_link = o.get("github_link").getAsString();
+ String other_text = o.get("other_text").getAsString();
+ String other_link = o.get("other_link").getAsString();
+
+ int first_len = -1;
+ for(String line : update_msg.split("\n")) {
+ FontRenderer fr = Minecraft.getMinecraft().fontRendererObj;
+ int len = fr.getStringWidth(line);
+ if(first_len == -1) {
+ first_len = len;
+ }
+ int missing_len = first_len-len;
+ if(missing_len > 0) {
+ StringBuilder sb = new StringBuilder(line);
+ for(int i=0; i<missing_len/8; i++) {
+ sb.insert(0, " ");
+ }
+ line = sb.toString();
+ }
+ line = line.replaceAll("\\{version}", version);
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(line));
+ }
+
+ displayLinks(o);
+
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(""));
+
+ }
+
+ return true;
+ } catch(Exception ignored) {}
+ }
+ return false;
+ }
+
/**
* 1)Will send the cached message from #sendChatMessage when at least 200ms has passed since the last message.
* This is used in order to prevent the mod spamming messages.
@@ -265,80 +394,8 @@ public class NotEnoughUpdates {
if(hasSkyblockScoreboard()) {
manager.auctionManager.tick();
if(!joinedSB && manager.config.showUpdateMsg.value) {
- File repo = manager.repoLocation;
- if(repo.exists()) {
- File updateJson = new File(repo, "update.json");
- try {
- JsonObject o = manager.getJsonFromFile(updateJson);
-
- String version = o.get("version").getAsString();
-
- if(!VERSION.equalsIgnoreCase(version)) {
- String update_msg = o.get("update_msg").getAsString();
- String discord_link = o.get("discord_link").getAsString();
- String youtube_link = o.get("youtube_link").getAsString();
- String update_link = o.get("update_link").getAsString();
- String github_link = o.get("github_link").getAsString();
- String other_text = o.get("other_text").getAsString();
- String other_link = o.get("other_link").getAsString();
-
- int first_len = -1;
- for(String line : update_msg.split("\n")) {
- FontRenderer fr = Minecraft.getMinecraft().fontRendererObj;
- int len = fr.getStringWidth(line);
- if(first_len == -1) {
- first_len = len;
- }
- int missing_len = first_len-len;
- if(missing_len > 0) {
- StringBuilder sb = new StringBuilder(line);
- for(int i=0; i<missing_len/8; i++) {
- sb.insert(0, " ");
- }
- line = sb.toString();
- }
- line = line.replaceAll("\\{version}", version);
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(line));
- }
- ChatComponentText other = null;
- if(other_text.length() > 0) {
- other = new ChatComponentText(EnumChatFormatting.GRAY+"["+EnumChatFormatting.BLUE+other_text+EnumChatFormatting.GRAY+"]");
- other.setChatStyle(Utils.createClickStyle(ClickEvent.Action.OPEN_URL, other_link));
- }
- ChatComponentText links = new ChatComponentText("");
- ChatComponentText separator = new ChatComponentText(
- EnumChatFormatting.GRAY+EnumChatFormatting.BOLD.toString()+EnumChatFormatting.STRIKETHROUGH+(other==null?"---":"--"));
- ChatComponentText discord = new ChatComponentText(EnumChatFormatting.GRAY+"["+EnumChatFormatting.BLUE+"Discord"+EnumChatFormatting.GRAY+"]");
- discord.setChatStyle(Utils.createClickStyle(ClickEvent.Action.OPEN_URL, discord_link));
- ChatComponentText youtube = new ChatComponentText(EnumChatFormatting.GRAY+"["+EnumChatFormatting.RED+"YouTube"+EnumChatFormatting.GRAY+"]");
- youtube.setChatStyle(Utils.createClickStyle(ClickEvent.Action.OPEN_URL, youtube_link));
- ChatComponentText release = new ChatComponentText(EnumChatFormatting.GRAY+"["+EnumChatFormatting.GREEN+"Release"+EnumChatFormatting.GRAY+"]");
- release.setChatStyle(Utils.createClickStyle(ClickEvent.Action.OPEN_URL, update_link));
- ChatComponentText github = new ChatComponentText(EnumChatFormatting.GRAY+"["+EnumChatFormatting.DARK_PURPLE+"GitHub"+EnumChatFormatting.GRAY+"]");
- github.setChatStyle(Utils.createClickStyle(ClickEvent.Action.OPEN_URL, github_link));
-
-
- links.appendSibling(separator);
- links.appendSibling(discord);
- links.appendSibling(separator);
- links.appendSibling(youtube);
- links.appendSibling(separator);
- links.appendSibling(release);
- links.appendSibling(separator);
- links.appendSibling(github);
- links.appendSibling(separator);
- if(other != null) {
- links.appendSibling(other);
- links.appendSibling(separator);
- }
-
- Minecraft.getMinecraft().thePlayer.addChatMessage(links);
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(""));
-
- }
-
- joinedSB = true;
- } catch(Exception ignored) {}
+ if(displayUpdateMessageIfOutOfDate()) {
+ joinedSB = false;
}
}
//NEUQuesting.getInstance().tick();
@@ -387,7 +444,6 @@ public class NotEnoughUpdates {
}
}
} else {
-
for(ItemStack stack : Minecraft.getMinecraft().thePlayer.inventory.mainInventory) {
processUniqueStack(stack, newItem);
}
@@ -407,6 +463,7 @@ public class NotEnoughUpdates {
if(newItemAddMap.containsKey(internalname)) {
if(System.currentTimeMillis() - newItemAddMap.get(internalname) > 1000) {
log.add(internalname);
+ try { manager.saveConfig(); } catch(IOException ignored) {}
}
} else {
newItemAddMap.put(internalname, System.currentTimeMillis());
@@ -732,7 +789,10 @@ public class NotEnoughUpdates {
ItemStack item = lower.getStackInSlot(11+i);
String internal = manager.getInternalNameForItem(item);
if(internal != null) {
- int worth = manager.auctionManager.getLowestBin(internal);
+ float worth = manager.auctionManager.getLowestBin(internal);
+
+ if(worth == -1) worth = manager.getCraftCost(internal).craftCost;
+
if(worth > 0) {
totalValue += worth;
} else {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/auction/APIManager.java b/src/main/java/io/github/moulberry/notenoughupdates/auction/APIManager.java
index 20ac86ba..65f6545e 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/auction/APIManager.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/auction/APIManager.java
@@ -19,6 +19,7 @@ import net.minecraft.util.EnumChatFormatting;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.*;
+import java.util.concurrent.atomic.AtomicInteger;
public class APIManager {
@@ -60,6 +61,8 @@ public class APIManager {
customAH = new CustomAH(manager);
}
+ private AtomicInteger playerInfoVersion = new AtomicInteger(0);
+
public JsonObject getPlayerInformation() {
if(playerInformation == null) return null;
for(int i=0; i<playerInformation.size(); i++) {
@@ -75,6 +78,14 @@ public class APIManager {
return null;
}
+ public int getPlayerInfoVersion() {
+ return playerInfoVersion.get();
+ }
+
+ public void incPlayerInfoVersion() {
+ playerInfoVersion.incrementAndGet();
+ }
+
public TreeMap<String, Auction> getAuctionItems() {
return auctionMap;
}
@@ -158,6 +169,7 @@ public class APIManager {
manager.hypixelApi.getHypixelApiAsync(manager.config.apiKey.value, "skyblock/profiles",
args, jsonObject -> {
if(jsonObject.has("success") && jsonObject.get("success").getAsBoolean()) {
+ incPlayerInfoVersion();
playerInformation = jsonObject.get("profiles").getAsJsonArray();
if(playerInformation == null) return;
String backup = null;
@@ -332,6 +344,8 @@ public class APIManager {
if(contains) {
if(line.trim().contains(rarity + " " + typeMatches[j])) {
return j;
+ } else if(line.trim().contains(rarity + " DUNGEON " + typeMatches[j])) {
+ return j;
}
} else {
if(line.trim().endsWith(rarity + " " + typeMatches[j])) {
@@ -464,7 +478,7 @@ public class APIManager {
//Categories
String category = sbCategory;
- int itemType = checkItemType(item_lore, false,"SWORD", "FISHING ROD", "PICKAXE",
+ int itemType = checkItemType(item_lore, true,"SWORD", "FISHING ROD", "PICKAXE",
"AXE", "SHOVEL", "PET ITEM", "TRAVEL SCROLL", "REFORGE STONE", "BOW");
if(itemType >= 0 && itemType < categoryItemType.length) {
category = categoryItemType[itemType];
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java
new file mode 100644
index 00000000..81ecc9b4
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java
@@ -0,0 +1,315 @@
+package io.github.moulberry.notenoughupdates.profileviewer;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.mojang.authlib.GameProfile;
+import com.mojang.authlib.minecraft.MinecraftProfileTexture;
+import com.mojang.authlib.properties.Property;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.util.TexLoc;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.entity.EntityOtherPlayerMP;
+import net.minecraft.client.gui.Gui;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.gui.ScaledResolution;
+import net.minecraft.client.network.NetworkPlayerInfo;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.client.renderer.OpenGlHelper;
+import net.minecraft.client.renderer.RenderHelper;
+import net.minecraft.client.renderer.entity.RenderManager;
+import net.minecraft.client.resources.DefaultPlayerSkin;
+import net.minecraft.client.resources.SkinManager;
+import net.minecraft.entity.EntityLivingBase;
+import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.ResourceLocation;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.io.Charsets;
+import org.lwjgl.input.Keyboard;
+import org.lwjgl.opengl.GL11;
+
+import java.awt.*;
+import java.nio.charset.Charset;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.UUID;
+
+public class GuiProfileViewer extends GuiScreen {
+
+ public static final ResourceLocation pv_basic = new ResourceLocation("notenoughupdates:pv_basic.png");
+
+ private final ProfileViewer.Profile profile;
+ private ProfileViewerPage currentPage = ProfileViewerPage.BASIC;
+ private int sizeX;
+ private int sizeY;
+ private int guiLeft;
+ private int guiTop;
+
+ public enum ProfileViewerPage {
+ BASIC
+ }
+
+ public GuiProfileViewer(ProfileViewer.Profile profile) {
+ this.profile = profile;
+ }
+
+ @Override
+ public void drawScreen(int mouseX, int mouseY, float partialTicks) {
+ super.drawScreen(mouseX, mouseY, partialTicks);
+ drawDefaultBackground();
+
+ switch (currentPage) {
+ case BASIC:
+ drawBasicPage(mouseX, mouseY, partialTicks);
+ break;
+ }
+
+ }
+
+ private String niceUuid(String uuidStr) {
+ if(uuidStr.length()!=32) return uuidStr;
+
+ StringBuilder niceAucId = new StringBuilder();
+ niceAucId.append(uuidStr, 0, 8);
+ niceAucId.append("-");
+ niceAucId.append(uuidStr, 8, 12);
+ niceAucId.append("-");
+ niceAucId.append(uuidStr, 12, 16);
+ niceAucId.append("-");
+ niceAucId.append(uuidStr, 16, 20);
+ niceAucId.append("-");
+ niceAucId.append(uuidStr, 20, 32);
+ return niceAucId.toString();
+ }
+
+ private EntityOtherPlayerMP entityPlayer = null;
+ private ResourceLocation playerLocationSkin = null;
+ private ResourceLocation playerLocationCape = null;
+ private String skinType = null;
+
+ TexLoc tl = new TexLoc(0, 0, Keyboard.KEY_M);
+ TexLoc tl2 = new TexLoc(0, 0, Keyboard.KEY_B);
+ TexLoc tl3 = new TexLoc(0, 0, Keyboard.KEY_J);
+ private void drawBasicPage(int mouseX, int mouseY, float partialTicks) {
+ this.sizeX = 431;
+ this.sizeY = 202;
+ this.guiLeft = (this.width-this.sizeX)/2;
+ this.guiTop = (this.height-this.sizeY)/2;
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(pv_basic);
+ Utils.drawTexturedRect(guiLeft, guiTop, sizeX, sizeY, GL11.GL_NEAREST);
+
+ tl.handleKeyboardInput();
+ tl2.handleKeyboardInput();
+ tl3.handleKeyboardInput();
+
+ if(entityPlayer == null) {
+ UUID playerUUID = UUID.fromString(niceUuid(profile.getUuid()));
+ GameProfile fakeProfile = Minecraft.getMinecraft().getSessionService().fillProfileProperties(new GameProfile(playerUUID, "CoolGuy123"), false);
+ for(Property prop : fakeProfile.getProperties().get("textures")) {
+ System.out.println(new String(Base64.decodeBase64(prop.getValue()), Charsets.UTF_8));
+ }
+ entityPlayer = new EntityOtherPlayerMP(Minecraft.getMinecraft().theWorld, fakeProfile) {
+ public ResourceLocation getLocationSkin() {
+ return playerLocationSkin == null ? DefaultPlayerSkin.getDefaultSkin(this.getUniqueID()) : playerLocationSkin;
+ }
+
+ public ResourceLocation getLocationCape() {
+ return playerLocationCape;
+ }
+
+ public String getSkinType() {
+ return skinType == null ? DefaultPlayerSkin.getSkinType(this.getUniqueID()) : skinType;
+ }
+ };
+ }
+
+ JsonObject profileInfo = profile.getProfileInformation(null);
+ if(profileInfo == null) return;
+
+ JsonObject skillInfo = profile.getSkillInfo(null);
+ JsonObject inventoryInfo = profile.getInventoryInfo(null);
+ JsonObject collectionInfo =profile. getCollectionInfo(null);
+
+ if(inventoryInfo != null && inventoryInfo.has("inv_armor")) {
+ JsonArray items = inventoryInfo.get("inv_armor").getAsJsonArray();
+ for(int i=0; i<entityPlayer.inventory.armorInventory.length; i++) {
+ JsonElement itemElement = items.get(i);
+ if(itemElement != null && itemElement.isJsonObject()) {
+ entityPlayer.inventory.armorInventory[i] = NotEnoughUpdates.INSTANCE.manager.jsonToStack(itemElement.getAsJsonObject(), false);
+ }
+ }
+ }
+ if(playerLocationSkin == null) {
+ try {
+ Minecraft.getMinecraft().getSkinManager().loadProfileTextures(entityPlayer.getGameProfile(), new SkinManager.SkinAvailableCallback() {
+ public void skinAvailable(MinecraftProfileTexture.Type type, ResourceLocation location, MinecraftProfileTexture profileTexture) {
+ switch (type) {
+ case SKIN:
+ playerLocationSkin = location;
+ skinType = profileTexture.getMetadata("model");
+
+ if(skinType == null) {
+ skinType = "default";
+ }
+
+ break;
+ case CAPE:
+ playerLocationCape = location;
+ }
+ }
+ }, false);
+ } catch(Exception e){}
+ }
+
+ drawEntityOnScreen(guiLeft+63, guiTop+129, 30, guiLeft+63-mouseX, guiTop+129-mouseY, entityPlayer);
+
+
+ PlayerStats.Stats stats = profile.getStats(null);
+
+ for(int i=0; i<PlayerStats.defaultStatNames.length; i++) {
+ String statName = PlayerStats.defaultStatNames[i];
+ String statNamePretty = PlayerStats.defaultStatNamesPretty[i];
+
+ int val = Math.round(stats.get(statName));
+
+
+
+ for(int xOff=-1; xOff<=1; xOff++) {
+ for(int yOff=-1; yOff<=1; yOff++) {
+ if(Math.abs(xOff) != Math.abs(yOff)) {
+ //Utils.drawStringCenteredScaledMaxWidth(Utils.cleanColourNotModifiers(statNamePretty) + " " + val, Minecraft.getMinecraft().fontRendererObj,
+ // guiLeft+172f+xOff, guiTop+36+12.5f*i+yOff, false, 85, new Color(100, 100, 100, 100).getRGB());
+ }
+ }
+ }
+
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawStringCenteredScaledMaxWidth(statNamePretty + " " + EnumChatFormatting.WHITE + val, Minecraft.getMinecraft().fontRendererObj,
+ guiLeft+172f, guiTop+36+12.5f*i, true, 85, Color.BLACK.getRGB());
+ }
+
+ int position = 0;
+ for(Map.Entry<String, String> entry : skillToSkillNameMap.entrySet()) {
+ int yPosition = position % 7;
+ int xPosition = position / 7;
+
+ String skillName = entry.getValue();
+
+ float level = (int)skillInfo.get(entry.getKey()).getAsFloat();
+
+ for(int xOff=-1; xOff<=1; xOff++) {
+ for(int yOff=-1; yOff<=1; yOff++) {
+ if(Math.abs(xOff) != Math.abs(yOff)) {
+ //Utils.drawStringCenteredScaledMaxWidth(Utils.cleanColourNotModifiers(skillName) + " " + level, Minecraft.getMinecraft().fontRendererObj,
+ // guiLeft+tl.x+tl2.x*xPosition+xOff, guiTop+tl.y+tl2.y*yPosition+yOff, false, 85, new Color(100, 100, 100, 100).getRGB());
+ }
+ }
+ }
+
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawStringCenteredScaledMaxWidth(skillName + " " + EnumChatFormatting.WHITE + level, Minecraft.getMinecraft().fontRendererObj,
+ guiLeft+277+86*xPosition, guiTop+36+21*yPosition, true, 85, Color.BLACK.getRGB());
+
+ position++;
+ }
+ }
+
+ private static final LinkedHashMap<String, String> skillToSkillNameMap = new LinkedHashMap<>();
+ static {
+ skillToSkillNameMap.put("level_skill_taming", "Taming");
+ skillToSkillNameMap.put("level_skill_mining", "Mining");
+ skillToSkillNameMap.put("level_skill_foraging", "Foraging");
+ skillToSkillNameMap.put("level_skill_enchanting", "Enchanting");
+ skillToSkillNameMap.put("level_skill_carpentry", "Carpentry");
+ skillToSkillNameMap.put("level_skill_farming", "Farming");
+ skillToSkillNameMap.put("level_skill_combat", "Combat");
+ skillToSkillNameMap.put("level_skill_fishing", "Fishing");
+ skillToSkillNameMap.put("level_skill_alchemy", "Alchemy");
+ skillToSkillNameMap.put("level_skill_runecrafting", "Runecrafting");
+ skillToSkillNameMap.put("level_slayer_zombie", "Revenant Slayer");
+ skillToSkillNameMap.put("level_slayer_spider", "Tarantula Slayer");
+ skillToSkillNameMap.put("level_slayer_wolf", "Sven Slayer");
+ }
+
+ /*private void renderBar(float x, float y, float xSize, float ySize, float completed) {
+ this.mc.getTextureManager().bindTexture(Gui.icons);
+
+ float yScale = ySize/5;
+
+
+ if (i > 0)
+ {
+ int j = 182;
+ int k = (int)(this.mc.thePlayer.experience * (float)(j + 1));
+ int l = p_175176_1_.getScaledHeight() - 32 + 3;
+
+ Utils.drawTexturedRect(x, y, xSize, );
+
+ this.drawTexturedModalRect(p_175176_2_, l, 0, 64, j, 5);
+
+ if (k > 0)
+ {
+ this.drawTexturedModalRect(p_175176_2_, l, 0, 69, k, 5);
+ }
+ }
+
+ if (this.mc.thePlayer.experienceLevel > 0)
+ {
+ this.mc.mcProfiler.startSection("expLevel");
+ int k1 = 8453920;
+ String s = "" + this.mc.thePlayer.experienceLevel;
+ int l1 = (p_175176_1_.getScaledWidth() - this.getFontRenderer().getStringWidth(s)) / 2;
+ int i1 = p_175176_1_.getScaledHeight() - 31 - 4;
+ int j1 = 0;
+ this.getFontRenderer().drawString(s, l1 + 1, i1, 0);
+ this.getFontRenderer().drawString(s, l1 - 1, i1, 0);
+ this.getFontRenderer().drawString(s, l1, i1 + 1, 0);
+ this.getFontRenderer().drawString(s, l1, i1 - 1, 0);
+ this.getFontRenderer().drawString(s, l1, i1, k1);
+ this.mc.mcProfiler.endSection();
+ }
+ }*/
+
+ public static void drawEntityOnScreen(int posX, int posY, int scale, float mouseX, float mouseY, EntityLivingBase ent) {
+ GlStateManager.enableColorMaterial();
+ GlStateManager.pushMatrix();
+ GlStateManager.translate((float)posX, (float)posY, 50.0F);
+ GlStateManager.scale((float)(-scale), (float)scale, (float)scale);
+ GlStateManager.rotate(180.0F, 0.0F, 0.0F, 1.0F);
+ float f = ent.renderYawOffset;
+ float f1 = ent.rotationYaw;
+ float f2 = ent.rotationPitch;
+ float f3 = ent.prevRotationYawHead;
+ float f4 = ent.rotationYawHead;
+ GlStateManager.rotate(135.0F, 0.0F, 1.0F, 0.0F);
+ RenderHelper.enableStandardItemLighting();
+ GlStateManager.rotate(-135.0F, 0.0F, 1.0F, 0.0F);
+ GlStateManager.rotate(-((float)Math.atan((double)(mouseY / 40.0F))) * 20.0F, 1.0F, 0.0F, 0.0F);
+ ent.renderYawOffset = (float)Math.atan((double)(mouseX / 40.0F)) * 20.0F;
+ ent.rotationYaw = (float)Math.atan((double)(mouseX / 40.0F)) * 40.0F;
+ ent.rotationPitch = -((float)Math.atan((double)(mouseY / 40.0F))) * 20.0F;
+ ent.rotationYawHead = ent.rotationYaw;
+ ent.prevRotationYawHead = ent.rotationYaw;
+ GlStateManager.translate(0.0F, 0.0F, 0.0F);
+ RenderManager rendermanager = Minecraft.getMinecraft().getRenderManager();
+ rendermanager.setPlayerViewY(180.0F);
+ rendermanager.setRenderShadow(false);
+ rendermanager.renderEntityWithPosYaw(ent, 0.0D, 0.0D, 0.0D, 0.0F, 1.0F);
+ rendermanager.setRenderShadow(true);
+ ent.renderYawOffset = f;
+ ent.rotationYaw = f1;
+ ent.rotationPitch = f2;
+ ent.prevRotationYawHead = f3;
+ ent.rotationYawHead = f4;
+ GlStateManager.popMatrix();
+ RenderHelper.disableStandardItemLighting();
+ GlStateManager.disableRescaleNormal();
+ GlStateManager.setActiveTexture(OpenGlHelper.lightmapTexUnit);
+ GlStateManager.disableTexture2D();
+ GlStateManager.setActiveTexture(OpenGlHelper.defaultTexUnit);
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/PlayerStats.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/PlayerStats.java
new file mode 100644
index 00000000..25b7356d
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/PlayerStats.java
@@ -0,0 +1,537 @@
+package io.github.moulberry.notenoughupdates.profileviewer;
+
+import com.google.gson.*;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.nbt.*;
+import net.minecraft.util.EnumChatFormatting;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class PlayerStats {
+ public static final String HEALTH = "health";
+ public static final String DEFENCE = "defence";
+ public static final String STRENGTH = "strength";
+ public static final String SPEED = "speed";
+ public static final String CRIT_CHANCE = "crit_chance";
+ public static final String CRIT_DAMAGE = "crit_damage";
+ public static final String BONUS_ATTACK_SPEED = "bonus_attack_speed";
+ public static final String INTELLIGENCE = "intelligence";
+ public static final String SEA_CREATURE_CHANCE = "sea_creature_chance";
+ public static final String MAGIC_FIND = "magic_find";
+ public static final String PET_LUCK = "pet_luck";
+
+ public static final String[] defaultStatNames = new String[]{"health","defence","strength","speed","crit_chance",
+ "crit_damage","bonus_attack_speed","intelligence","sea_creature_chance","magic_find","pet_luck"};
+ public static final String[] defaultStatNamesPretty = new String[]{EnumChatFormatting.RED+"\u2764 Health",EnumChatFormatting.GREEN+"\u2748 Defence",
+ EnumChatFormatting.RED+"\u2741 Strength",EnumChatFormatting.WHITE+"\u2726 Speed",EnumChatFormatting.BLUE+"\u2623 Crit Chance",
+ EnumChatFormatting.BLUE+"\u2620 Crit Damage",EnumChatFormatting.YELLOW+"\u2694 Attack Speed",EnumChatFormatting.AQUA+"\u270e Intelligence",
+ EnumChatFormatting.DARK_AQUA+"\u03b1 SC Chance",EnumChatFormatting.AQUA+"\u272f Magic Find",EnumChatFormatting.LIGHT_PURPLE+"\u2663 Pet Luck"};
+
+ public static class Stats {
+ JsonObject statsJson = new JsonObject();
+
+ /*public float health;
+ public float defence;
+ public float strength;
+ public float speed;
+ public float crit_chance;
+ public float crit_damage;
+ public float bonus_attack_speed;
+ public float intelligence;
+ public float sea_creature_chance;
+ public float magic_find;
+ public float pet_luck;*/
+
+ public Stats(Stats... statses) {
+ for(Stats stats : statses) {
+ add(stats);
+ }
+ }
+
+ /*@Override
+ public String toString() {
+ return String.format("{health=%s,defence=%s,strength=%s,speed=%s,crit_chance=%s,crit_damage=%s," +
+ "bonus_attack_speed=%s,intelligence=%s,sea_creature_chance=%s,magic_find=%s,pet_luck=%s}",
+ stats.get("health"), defence, strength, speed, crit_chance, crit_damage, bonus_attack_speed, intelligence,
+ sea_creature_chance, magic_find, pet_luck);
+ }*/
+
+ public float get(String statName) {
+ if(statsJson.has(statName)) {
+ return statsJson.get(statName).getAsFloat();
+ } else {
+ return 0;
+ }
+ }
+
+ public Stats add(Stats stats) {
+ for(Map.Entry<String, JsonElement> statEntry : stats.statsJson.entrySet()) {
+ if(statEntry.getValue().isJsonPrimitive() && ((JsonPrimitive)statEntry.getValue()).isNumber()) {
+ if(!statsJson.has(statEntry.getKey())) {
+ statsJson.add(statEntry.getKey(), statEntry.getValue());
+ } else {
+ JsonPrimitive e = statsJson.get(statEntry.getKey()).getAsJsonPrimitive();
+ float statNum = e.getAsFloat() + statEntry.getValue().getAsFloat();
+ statsJson.add(statEntry.getKey(), new JsonPrimitive(statNum));
+ }
+ }
+ }
+ return this;
+ }
+
+ public void scaleAll(float scale) {
+ for(Map.Entry<String, JsonElement> statEntry : statsJson.entrySet()) {
+ statsJson.add(statEntry.getKey(), new JsonPrimitive(statEntry.getValue().getAsFloat()*scale));
+ }
+ }
+
+ public void addStat(String statName, float amount) {
+ if(!statsJson.has(statName)) {
+ statsJson.add(statName, new JsonPrimitive(amount));
+ } else {
+ JsonPrimitive e = statsJson.get(statName).getAsJsonPrimitive();
+ statsJson.add(statName, new JsonPrimitive(e.getAsFloat() + amount));
+ }
+ }
+ }
+
+ public static Stats getBaseStats() {
+ JsonObject misc = Utils.getConstant("misc");
+ if(misc == null) return null;
+
+ Stats stats = new Stats();
+ for(String statName : defaultStatNames) {
+ stats.addStat(statName, Utils.getElementAsFloat(Utils.getElement(misc, "base_stats."+statName), 0));
+ }
+ return stats;
+ }
+
+ public static Stats getFairyBonus(int fairyExchanges) {
+ Stats bonus = new Stats();
+
+ bonus.addStat(SPEED, fairyExchanges/10);
+
+ for(int i=0; i<fairyExchanges; i++) {
+ bonus.addStat(STRENGTH, (i + 1) % 5 == 0 ? 2 : 1);
+ bonus.addStat(DEFENCE, (i + 1) % 5 == 0 ? 2 : 1);
+ bonus.addStat(HEALTH, 3 + i / 2);
+ }
+
+ return bonus;
+ }
+
+ public static Stats getSkillBonus(JsonObject skillInfo) {
+ JsonObject bonuses = Utils.getConstant("bonuses");
+ if(bonuses == null) return null;
+
+ Stats skillBonus = new Stats();
+
+ for(Map.Entry<String, JsonElement> entry : skillInfo.entrySet()) {
+ if(entry.getKey().startsWith("level_")) {
+ String skill = entry.getKey().substring("level_".length());
+ JsonObject skillStatMap = Utils.getElement(bonuses, "bonus_stats."+skill).getAsJsonObject();
+
+ Stats currentBonus = new Stats();
+ for(int i=1; i<=entry.getValue().getAsFloat(); i++) {
+ if(skillStatMap.has(""+i)) {
+ currentBonus = new Stats();
+ for(Map.Entry<String, JsonElement> entry2 : skillStatMap.get(""+i).getAsJsonObject().entrySet()) {
+ currentBonus.addStat(entry2.getKey(), entry2.getValue().getAsFloat());
+ }
+ }
+ skillBonus.add(currentBonus);
+ }
+ }
+ }
+
+ return skillBonus;
+ }
+
+ public static Stats getPetBonus(JsonObject profile) {
+ JsonObject bonuses = Utils.getConstant("bonuses");
+ if(bonuses == null) return null;
+
+ JsonElement petsElement = Utils.getElement(profile, "pets");
+ if(petsElement == null) return new Stats();
+
+ JsonArray pets = petsElement.getAsJsonArray();
+
+ HashMap<String, String> highestRarityMap = new HashMap<>();
+
+ for(int i=0; i<pets.size(); i++) {
+ JsonObject pet = pets.get(i).getAsJsonObject();
+ highestRarityMap.put(pet.get("type").getAsString(), pet.get("tier").getAsString());
+ }
+
+ int petScore = 0;
+ for(String value : highestRarityMap.values()) {
+ petScore += Utils.getElementAsFloat(Utils.getElement(bonuses, "pet_value."+value.toUpperCase()), 0);
+ }
+
+ JsonElement petRewardsElement = Utils.getElement(bonuses, "pet_rewards");
+ if(petRewardsElement == null) return null;
+ JsonObject petRewards = petRewardsElement.getAsJsonObject();
+
+ Stats petBonus = new Stats();
+ for(int i=0; i<=petScore; i++) {
+ if(petRewards.has(""+i)) {
+ petBonus = new Stats();
+ for(Map.Entry<String, JsonElement> entry : petRewards.get(""+i).getAsJsonObject().entrySet()) {
+ petBonus.addStat(entry.getKey(), entry.getValue().getAsFloat());
+ }
+ }
+ }
+ return petBonus;
+ }
+
+ public static float harpBonus(JsonObject profile) {
+ String talk_to_melody = Utils.getElementAsString(Utils.getElement(profile, "objectives.talk_to_melody.status"), "INCOMPLETE");
+ if(talk_to_melody.equalsIgnoreCase("COMPLETE")) {
+ return 26;
+ } else {
+ return 0;
+ }
+ }
+
+
+ public static Stats getPassiveBonuses(JsonObject skillInfo, JsonObject profile) {
+ Stats passiveBonuses = new Stats();
+
+ //TODO: null checking
+ Stats fairyBonus = getFairyBonus((int)Utils.getElementAsFloat(Utils.getElement(profile, "fairy_exchanges"), 0));
+ Stats skillBonus = getSkillBonus(skillInfo);
+ Stats petBonus = getPetBonus(profile);
+
+ if(fairyBonus == null || skillBonus == null || petBonus == null) return null;
+
+ passiveBonuses.add(fairyBonus);
+ passiveBonuses.add(skillBonus);
+ passiveBonuses.addStat(INTELLIGENCE, harpBonus(profile));
+ passiveBonuses.add(petBonus);
+
+ return passiveBonuses;
+ }
+
+ public static String getFullset(JsonArray armor, int ignore) {
+ String fullset = null;
+ for(int i=0; i<armor.size(); i++) {
+ if(i == ignore) continue;
+
+ JsonElement itemElement = armor.get(i);
+ if(itemElement == null || !itemElement.isJsonObject()) {
+ fullset = null;
+ break;
+ }
+ JsonObject item = itemElement.getAsJsonObject();
+ String internalname = item.get("internalname").getAsString();
+
+ String[] split = internalname.split("_");
+ split[split.length-1] = "";
+ String armorname = StringUtils.join(split, "_");
+
+ if(fullset == null) {
+ fullset = armorname;
+ } else if(!fullset.equalsIgnoreCase(armorname)){
+ fullset = null;
+ break;
+ }
+ }
+ return fullset;
+ }
+
+ public static Stats getSetBonuses(Stats stats, JsonObject inventoryInfo, JsonObject collectionInfo, JsonObject skillInfo, JsonObject profile) {
+ JsonArray armor = Utils.getElement(inventoryInfo, "inv_armor").getAsJsonArray();
+
+ Stats bonuses = new Stats();
+
+ String fullset = getFullset(armor, -1);
+
+ if(fullset != null) {
+ 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;
+ case "SPEEDSTER_":
+ bonuses.addStat(SPEED, 20);
+ break;
+ case "YOUNG_DRAGON_":
+ bonuses.addStat(SPEED, 70);
+ break;
+ case "MASTIFF_":
+ bonuses.addStat(HEALTH, 50*Math.round(stats.get(CRIT_DAMAGE)));
+ break;
+ case "ANGLER_":
+ bonuses.addStat(HEALTH, 10*(float)Math.floor(Utils.getElementAsFloat(Utils.getElement(skillInfo, "level_skill_fishing"), 0)));
+ bonuses.addStat(SEA_CREATURE_CHANCE, 4);
+ break;
+ case "ARMOR_OF_MAGMA_":
+ int bonus = (int)Math.min(200, Math.floor(Utils.getElementAsFloat(Utils.getElement(profile, "stats.kills_magma_cube"), 0)/10));
+ bonuses.addStat(HEALTH, bonus);
+ bonuses.addStat(INTELLIGENCE, bonus);
+ case "OLD_DRAGON_":
+ bonuses.addStat(HEALTH, 200);
+ bonuses.addStat(DEFENCE, 40);
+ break;
+ }
+ }
+
+ JsonElement chestplateElement = armor.get(2);
+ if(chestplateElement != null && chestplateElement.isJsonObject()) {
+ JsonObject chestplate = chestplateElement.getAsJsonObject();
+ if(chestplate.get("internalname").getAsString().equals("OBSIDIAN_CHESTPLATE")) {
+ JsonArray inventory = Utils.getElement(inventoryInfo, "inv_contents").getAsJsonArray();
+ for(int i=0; i<inventory.size(); i++) {
+ JsonElement itemElement = inventory.get(i);
+ if(itemElement != null && itemElement.isJsonObject()) {
+ JsonObject item = itemElement.getAsJsonObject();
+ if(item.get("internalname").getAsString().equals("OBSIDIAN")) {
+ int count = 1;
+ if(item.has("count")) {
+ count = item.get("count").getAsInt();
+ }
+ bonuses.addStat(SPEED, count/20);
+ }
+ }
+ }
+ }
+ }
+
+ return bonuses;
+ }
+
+ private static String[] rarityArr = new String[] {
+ "COMMON", "UNCOMMON", "RARE", "EPIC", "LEGENDARY", "MYTHIC", "SPECIAL", "VERY SPECIAL",
+ };
+ public static int checkItemType(JsonArray lore, boolean contains, String... typeMatches) {
+ for(int i=lore.size()-1; i>=0; i--) {
+ String line = lore.get(i).getAsString();
+ for(String rarity : rarityArr) {
+ for(int j=0; j<typeMatches.length; j++) {
+ if(contains) {
+ if(line.trim().contains(rarity + " " + typeMatches[j])) {
+ return j;
+ } else if(line.trim().contains(rarity + " DUNGEON " + typeMatches[j])) {
+ return j;
+ }
+ } else {
+ if(line.trim().endsWith(rarity + " " + typeMatches[j])) {
+ return j;
+ } else if(line.trim().endsWith(rarity + " DUNGEON " + typeMatches[j])) {
+ return j;
+ }
+ }
+ }
+ }
+ }
+ return -1;
+ }
+
+ private static final Pattern HEALTH_PATTERN = Pattern.compile("^Health: \\+([0-9]+)");
+ private static final Pattern DEFENCE_PATTERN = Pattern.compile("^Defense: \\+([0-9]+)");
+ private static final Pattern STRENGTH_PATTERN = Pattern.compile("^Strength: \\+([0-9]+)");
+ private static final Pattern SPEED_PATTERN = Pattern.compile("^Speed: \\+([0-9]+)");
+ private static final Pattern CC_PATTERN = Pattern.compile("^Crit Chance: \\+([0-9]+)");
+ private static final Pattern CD_PATTERN = Pattern.compile("^Crit Damage: \\+([0-9]+)");
+ private static final Pattern ATKSPEED_PATTERN = Pattern.compile("^Bonus Attack Speed: \\+([0-9]+)");
+ private static final Pattern INTELLIGENCE_PATTERN = Pattern.compile("^Intelligence: \\+([0-9]+)");
+ private static final Pattern SCC_PATTERN = Pattern.compile("^Sea Creature Chance: \\+([0-9]+)");
+ private static final HashMap<String, Pattern> STAT_PATTERN_MAP = new HashMap<>();
+ static {
+ STAT_PATTERN_MAP.put("health", HEALTH_PATTERN);
+ STAT_PATTERN_MAP.put("defence", DEFENCE_PATTERN);
+ STAT_PATTERN_MAP.put("strength", STRENGTH_PATTERN);
+ STAT_PATTERN_MAP.put("speed", SPEED_PATTERN);
+ STAT_PATTERN_MAP.put("crit_chance", CC_PATTERN);
+ STAT_PATTERN_MAP.put("crit_damage", CD_PATTERN);
+ STAT_PATTERN_MAP.put("bonus_attack_speed", ATKSPEED_PATTERN);
+ STAT_PATTERN_MAP.put("intelligence", INTELLIGENCE_PATTERN);
+ STAT_PATTERN_MAP.put("sea_creature_chance", SCC_PATTERN);
+ }
+ public static Stats getStatForItem(String internalname, JsonObject item, JsonArray lore) {
+ Stats stats = new Stats();
+ for(int i=0; i<lore.size(); i++) {
+ String line = lore.get(i).getAsString();
+ for(Map.Entry<String, Pattern> entry : STAT_PATTERN_MAP.entrySet()) {
+ Matcher matcher = entry.getValue().matcher(Utils.cleanColour(line));
+ if(matcher.find()) {
+ int bonus = Integer.parseInt(matcher.group(1));
+ //System.out.println(entry.getKey() + ":" + bonus);
+ stats.addStat(entry.getKey(), bonus);
+ }
+ }
+ }
+ if(internalname.equals("DAY_CRYSTAL") || internalname.equals("NIGHT_CRYSTAL")) {
+ stats.addStat(STRENGTH, 2.5f);
+ stats.addStat(DEFENCE, 2.5f);
+ System.out.println("added day");
+ }
+ if(internalname.equals("NEW_YEAR_CAKE_BAG") && item.has("item_contents")) {
+
+ JsonArray bytesArr = item.get("item_contents").getAsJsonArray();
+ byte[] bytes = new byte[bytesArr.size()];
+ for(int i=0; i<bytesArr.size(); i++) {
+ bytes[i] = bytesArr.get(i).getAsByte();
+ }
+ try {
+ NBTTagCompound contents_nbt = CompressedStreamTools.readCompressed(new ByteArrayInputStream(bytes));
+ NBTTagList items = contents_nbt.getTagList("i", 10);
+ HashSet<Integer> cakes = new HashSet<>();
+ for(int j=0; j<items.tagCount(); j++) {
+ if(items.getCompoundTagAt(j).getKeySet().size() > 0) {
+ NBTTagCompound nbt = items.getCompoundTagAt(j).getCompoundTag("tag");
+ if(nbt != null && nbt.hasKey("ExtraAttributes", 10)) {
+ NBTTagCompound ea = nbt.getCompoundTag("ExtraAttributes");
+ if (ea.hasKey("new_years_cake")) {
+ cakes.add(ea.getInteger("new_years_cake"));
+ }
+ }
+ }
+ }
+ stats.addStat(HEALTH, cakes.size());
+ } catch(IOException e) {
+ e.printStackTrace();
+ return stats;
+ }
+ }
+ return stats;
+ }
+ public static Stats getItemBonuses(boolean talismanOnly, JsonArray... inventories) {
+ JsonObject misc = Utils.getConstant("misc");
+ if(misc == null) return null;
+ JsonElement talisman_upgrades_element = misc.get("talisman_upgrades");
+ if(talisman_upgrades_element == null) return null;
+ JsonObject talisman_upgrades = talisman_upgrades_element.getAsJsonObject();
+
+ HashMap<String, Stats> itemBonuses = new HashMap<>();
+ for(JsonArray inventory : inventories) {
+ for(int i=0; i<inventory.size(); i++) {
+ JsonElement itemElement = inventory.get(i);
+ //if(itemElement != null) System.out.println("item element:"+itemElement.getClass());
+ if(itemElement != null && itemElement.isJsonObject()) {
+ JsonObject item = itemElement.getAsJsonObject();
+ String internalname = item.get("internalname").getAsString();
+ if(itemBonuses.containsKey(internalname)) {
+ continue;
+ }
+ if(!talismanOnly || checkItemType(item.get("lore").getAsJsonArray(), true, "ACCESSORY") >= 0) {
+ Stats itemBonus = getStatForItem(internalname, item, item.get("lore").getAsJsonArray());
+
+ itemBonuses.put(internalname, itemBonus);
+
+ for(Map.Entry<String, JsonElement> talisman_upgrades_item : talisman_upgrades.entrySet()) {
+ JsonArray upgrades = talisman_upgrades_item.getValue().getAsJsonArray();
+ for(int j=0; j<upgrades.size(); j++) {
+ String upgrade = upgrades.get(j).getAsString();
+ if(upgrade.equals(internalname)) {
+ itemBonuses.put(talisman_upgrades_item.getKey(), new Stats());
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ Stats itemBonusesStats = new Stats();
+ for(Stats stats : itemBonuses.values()) {
+ itemBonusesStats.add(stats);
+ }
+ return itemBonusesStats;
+ }
+
+ public static float getStatMult(JsonObject inventoryInfo) {
+ float mult = 1f;
+
+ JsonArray armor = Utils.getElement(inventoryInfo, "inv_armor").getAsJsonArray();
+
+ String fullset = getFullset(armor, -1);
+
+ if(fullset != null && fullset.equals("SUPERIOR_DRAGON_")) {
+ mult *= 1.05f;
+ }
+
+ for(int i=0; i<armor.size(); i++) {
+ JsonElement itemElement = armor.get(i);
+ if(itemElement == null || !itemElement.isJsonObject()) continue;
+
+ JsonObject item = itemElement.getAsJsonObject();
+ String internalname = item.get("internalname").getAsString();
+
+ String reforge = Utils.getElementAsString(Utils.getElement(item, "ExtraAttributes.modifier"), "");
+
+ if(reforge.equals("renowned")) {
+ mult *= 1.01f;
+ }
+ }
+
+ return mult;
+ }
+
+ public static void applyLimits(Stats stats, JsonObject inventoryInfo) {
+ //>0
+ JsonArray armor = Utils.getElement(inventoryInfo, "inv_armor").getAsJsonArray();
+
+ String fullset = getFullset(armor, 3);
+
+ if(fullset != null) {
+ switch(fullset) {
+ case "CHEAP_TUXEDO_":
+ stats.statsJson.add(HEALTH, new JsonPrimitive(Math.min(75, stats.get(HEALTH))));
+ case "FANCY_TUXEDO_":
+ stats.statsJson.add(HEALTH, new JsonPrimitive(Math.min(150, stats.get(HEALTH))));
+ case "ELEGANT_TUXEDO_":
+ stats.statsJson.add(HEALTH, new JsonPrimitive(Math.min(250, stats.get(HEALTH))));
+ }
+ }
+
+ for(Map.Entry<String, JsonElement> statEntry : stats.statsJson.entrySet()) {
+ stats.statsJson.add(statEntry.getKey(), new JsonPrimitive(Math.max(0, statEntry.getValue().getAsFloat())));
+ }
+ }
+
+ public static Stats getStats(JsonObject skillInfo, JsonObject inventoryInfo, JsonObject collectionInfo, JsonObject profile) {
+ JsonArray armor = Utils.getElement(inventoryInfo, "inv_armor").getAsJsonArray();
+ JsonArray inventory = Utils.getElement(inventoryInfo, "inv_contents").getAsJsonArray();
+ JsonArray talisman_bag = Utils.getElement(inventoryInfo, "talisman_bag").getAsJsonArray();
+
+ Stats passiveBonuses = getPassiveBonuses(skillInfo, profile);
+ System.out.println("passive:"+new Stats(passiveBonuses, getBaseStats()));
+ Stats armorBonuses = getItemBonuses(false, armor);
+ Stats talismanBonuses = getItemBonuses(true, inventory, talisman_bag);
+
+ if(passiveBonuses == null) System.out.println("passive null");
+ if(armorBonuses == null) System.out.println("armorBonuses null");
+ if(talismanBonuses == null) System.out.println("talismanBonuses null");
+
+ if(passiveBonuses == null || armorBonuses == null || talismanBonuses == null) return null;
+
+ Stats stats = getBaseStats().add(passiveBonuses).add(armorBonuses).add(talismanBonuses);
+
+ stats.add(getSetBonuses(stats, inventoryInfo, collectionInfo, skillInfo, profile));
+
+ stats.scaleAll(getStatMult(inventoryInfo));
+
+ applyLimits(stats, inventoryInfo);
+
+ return stats;
+ }
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ProfileViewer.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ProfileViewer.java
new file mode 100644
index 00000000..db90cca8
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ProfileViewer.java
@@ -0,0 +1,370 @@
+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.google.gson.JsonPrimitive;
+import io.github.moulberry.notenoughupdates.NEUManager;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.nbt.CompressedStreamTools;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.nbt.NBTTagList;
+import net.minecraft.util.ChatComponentText;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Consumer;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class ProfileViewer {
+
+ private final NEUManager manager;
+
+ public ProfileViewer(NEUManager manager) {
+ this.manager = manager;
+ }
+
+ public class Profile {
+ private final String uuid;
+ private String latestProfile = null;
+
+ private JsonArray playerInformation = null;
+ private JsonObject basicInfo = null;
+
+ private final HashMap<String, JsonObject> profileMap = new HashMap<>();
+ private final HashMap<String, JsonObject> skillInfoMap = new HashMap<>();
+ private final HashMap<String, JsonObject> inventoryInfoMap = new HashMap<>();
+ private final HashMap<String, JsonObject> collectionInfoMap = new HashMap<>();
+ private PlayerStats.Stats stats = null;
+
+ public Profile(String uuid) {
+ this.uuid = uuid;
+ }
+
+ private AtomicBoolean updatingPlayerInfoState = new AtomicBoolean(false);
+
+ public JsonArray getPlayerInformation(Runnable runnable) {
+ if(playerInformation != null) return playerInformation;
+ if(updatingPlayerInfoState.get()) return null;
+
+ updatingPlayerInfoState.set(true);
+
+ HashMap<String, String> args = new HashMap<>();
+ args.put("uuid", ""+uuid);
+ manager.hypixelApi.getHypixelApiAsync(manager.config.apiKey.value, "skyblock/profiles",
+ args, jsonObject -> {
+ updatingPlayerInfoState.set(false);
+ if(jsonObject.has("success") && jsonObject.get("success").getAsBoolean()) {
+ playerInformation = jsonObject.get("profiles").getAsJsonArray();
+ if(playerInformation == null) return;
+ String backup = null;
+ long backupLastSave = 0;
+ for(int i=0; i<playerInformation.size(); i++) {
+ JsonObject profile = playerInformation.get(i).getAsJsonObject();
+ String cute_name = profile.get("cute_name").getAsString();
+
+ if(backup == null) backup = cute_name;
+
+ if(!profile.has("members")) continue;
+ JsonObject members = profile.get("members").getAsJsonObject();
+
+ if(members.has(uuid)) {
+ JsonObject member = members.get(uuid).getAsJsonObject();
+ long last_save = member.get("last_save").getAsLong();
+ if(last_save > backupLastSave) {
+ backupLastSave = last_save;
+ backup = cute_name;
+ }
+ }
+ }
+ System.out.println("accepting runnable");
+ runnable.run();
+ latestProfile = backup;
+ }
+ }
+ );
+
+ return null;
+ }
+
+ public JsonObject getProfileInformation(String profileId) {
+ JsonArray playerInfo = getPlayerInformation(() -> {});
+ if(playerInfo == null) return null;
+ if(profileId == null) profileId = latestProfile;
+ if(profileMap.containsKey(profileId)) return profileMap.get(profileId);
+
+ for(int i=0; i<playerInformation.size(); i++) {
+ JsonObject profile = playerInformation.get(i).getAsJsonObject();
+ if(profile.get("cute_name").getAsString().equalsIgnoreCase(profileId)) {
+ 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());
+ }
+ System.out.println("got profile");
+ profileMap.put(profileId, profileInfo);
+ return profileInfo;
+ }
+ }
+ System.out.println("couldnt get profile");
+
+ return null;
+ }
+
+ public void resetCache() {
+ playerInformation = null;
+ basicInfo = null;
+ profileMap.clear();
+ skillInfoMap.clear();
+ inventoryInfoMap.clear();
+ collectionInfoMap.clear();
+ }
+
+ public float getLevel(JsonArray levelingArray, float xp) {
+ for(int level=0; level<levelingArray.size(); level++) {
+ float levelXp = levelingArray.get(level).getAsFloat();
+ if(levelXp > xp) {
+ return level + xp/levelXp;
+ } else {
+ xp -= levelXp;
+ }
+ }
+ return levelingArray.size();
+ }
+
+ public JsonObject getSkillInfo(String profileId) {
+ JsonObject profileInfo = getProfileInformation(profileId);
+ if(profileInfo == null) return null;
+ if(profileId == null) profileId = latestProfile;
+ if(skillInfoMap.containsKey(profileId)) return skillInfoMap.get(profileId);
+ JsonObject leveling = Utils.getConstant("leveling");
+ if(leveling == null) return null;
+
+ float experience_skill_taming = Utils.getElementAsFloat(Utils.getElement(profileInfo, "experience_skill_taming"), 0);
+ float experience_skill_mining = Utils.getElementAsFloat(Utils.getElement(profileInfo, "experience_skill_mining"), 0);
+ float experience_skill_foraging = Utils.getElementAsFloat(Utils.getElement(profileInfo, "experience_skill_foraging"), 0);
+ float experience_skill_enchanting = Utils.getElementAsFloat(Utils.getElement(profileInfo, "experience_skill_enchanting"), 0);
+ float experience_skill_carpentry = Utils.getElementAsFloat(Utils.getElement(profileInfo, "experience_skill_carpentry"), 0);
+ float experience_skill_farming = Utils.getElementAsFloat(Utils.getElement(profileInfo, "experience_skill_farming"), 0);
+ float experience_skill_combat = Utils.getElementAsFloat(Utils.getElement(profileInfo, "experience_skill_combat"), 0);
+ float experience_skill_fishing = Utils.getElementAsFloat(Utils.getElement(profileInfo, "experience_skill_fishing"), 0);
+ float experience_skill_alchemy = Utils.getElementAsFloat(Utils.getElement(profileInfo, "experience_skill_alchemy"), 0);
+ float experience_skill_runecrafting = Utils.getElementAsFloat(Utils.getElement(profileInfo, "experience_skill_runecrafting"), 0);
+
+ float experience_slayer_zombie = Utils.getElementAsFloat(Utils.getElement(profileInfo, "slayer_bosses.zombie.xp"), 0);
+ float experience_slayer_spider = Utils.getElementAsFloat(Utils.getElement(profileInfo, "slayer_bosses.spider.xp"), 0);
+ float experience_slayer_wolf = Utils.getElementAsFloat(Utils.getElement(profileInfo, "slayer_bosses.zombie.xp"), 0);
+
+ float totalSkillXP = experience_skill_taming + experience_skill_mining + experience_skill_foraging
+ + experience_skill_enchanting + experience_skill_carpentry + experience_skill_farming
+ + experience_skill_combat + experience_skill_fishing + experience_skill_alchemy
+ + experience_skill_runecrafting;
+
+ if(totalSkillXP <= 0) {
+ System.out.println("couldnt get skill xp");
+ return null;
+ }
+
+ JsonObject skillInfo = new JsonObject();
+
+ skillInfo.addProperty("experience_skill_taming", experience_skill_taming);
+ skillInfo.addProperty("experience_skill_mining", experience_skill_mining);
+ skillInfo.addProperty("experience_skill_foraging", experience_skill_foraging);
+ skillInfo.addProperty("experience_skill_enchanting", experience_skill_enchanting);
+ skillInfo.addProperty("experience_skill_carpentry", experience_skill_carpentry);
+ skillInfo.addProperty("experience_skill_farming", experience_skill_farming);
+ skillInfo.addProperty("experience_skill_combat", experience_skill_combat);
+ skillInfo.addProperty("experience_skill_fishing", experience_skill_fishing);
+ skillInfo.addProperty("experience_skill_alchemy", experience_skill_alchemy);
+ skillInfo.addProperty("experience_skill_runecrafting", experience_skill_runecrafting);
+
+ skillInfo.addProperty("experience_slayer_zombie", experience_slayer_zombie);
+ skillInfo.addProperty("experience_slayer_spider", experience_slayer_spider);
+ skillInfo.addProperty("experience_slayer_wolf", experience_slayer_wolf);
+
+ skillInfo.addProperty("level_skill_taming", getLevel(Utils.getElement(leveling, "leveling_xp").getAsJsonArray(), experience_skill_taming));
+ skillInfo.addProperty("level_skill_mining", getLevel(Utils.getElement(leveling, "leveling_xp").getAsJsonArray(), experience_skill_mining));
+ skillInfo.addProperty("level_skill_foraging", getLevel(Utils.getElement(leveling, "leveling_xp").getAsJsonArray(), experience_skill_foraging));
+ skillInfo.addProperty("level_skill_enchanting", getLevel(Utils.getElement(leveling, "leveling_xp").getAsJsonArray(), experience_skill_enchanting));
+ skillInfo.addProperty("level_skill_carpentry", getLevel(Utils.getElement(leveling, "leveling_xp").getAsJsonArray(), experience_skill_carpentry));
+ skillInfo.addProperty("level_skill_farming", getLevel(Utils.getElement(leveling, "leveling_xp").getAsJsonArray(), experience_skill_farming));
+ skillInfo.addProperty("level_skill_combat", getLevel(Utils.getElement(leveling, "leveling_xp").getAsJsonArray(), experience_skill_combat));
+ skillInfo.addProperty("level_skill_fishing", getLevel(Utils.getElement(leveling, "leveling_xp").getAsJsonArray(), experience_skill_fishing));
+ skillInfo.addProperty("level_skill_alchemy", getLevel(Utils.getElement(leveling, "leveling_xp").getAsJsonArray(), experience_skill_alchemy));
+ skillInfo.addProperty("level_skill_runecrafting", getLevel(Utils.getElement(leveling, "leveling_xp").getAsJsonArray(), experience_skill_runecrafting));
+
+ skillInfo.addProperty("level_slayer_zombie", getLevel(Utils.getElement(leveling, "slayer_xp.zombie").getAsJsonArray(), experience_slayer_zombie));
+ skillInfo.addProperty("level_slayer_spider", getLevel(Utils.getElement(leveling, "slayer_xp.spider").getAsJsonArray(), experience_slayer_spider));
+ skillInfo.addProperty("level_slayer_wolf", getLevel(Utils.getElement(leveling, "slayer_xp.wolf").getAsJsonArray(), experience_slayer_wolf));
+
+ return skillInfo;
+ }
+
+ public JsonObject getInventoryInfo(String profileId) {
+ JsonObject profileInfo = getProfileInformation(profileId);
+ if(profileInfo == null) return null;
+ if(profileId == null) profileId = latestProfile;
+ if(inventoryInfoMap.containsKey(profileId)) return inventoryInfoMap.get(profileId);
+
+ //inv_armor, fishing_bag, quiver, ender_chest_contents, wardrobe_contents, potion_bag, inv_contents, talisman_bag, candy_inventory_contents
+
+ String inv_armor_bytes = Utils.getElementAsString(Utils.getElement(profileInfo, "inv_armor.data"), "Hz8IAAAAAAAAAD9iYD9kYD9kAAMAPwI/Gw0AAAA=");
+ String fishing_bag_bytes = Utils.getElementAsString(Utils.getElement(profileInfo, "fishing_bag.data"), "Hz8IAAAAAAAAAD9iYD9kYD9kAAMAPwI/Gw0AAAA=");
+ String quiver_bytes = Utils.getElementAsString(Utils.getElement(profileInfo, "quiver.data"), "Hz8IAAAAAAAAAD9iYD9kYD9kAAMAPwI/Gw0AAAA=");
+ String ender_chest_contents_bytes = Utils.getElementAsString(Utils.getElement(profileInfo, "ender_chest_contents.data"), "Hz8IAAAAAAAAAD9iYD9kYD9kAAMAPwI/Gw0AAAA=");
+ String wardrobe_contents_bytes = Utils.getElementAsString(Utils.getElement(profileInfo, "wardrobe_contents.data"), "Hz8IAAAAAAAAAD9iYD9kYD9kAAMAPwI/Gw0AAAA=");
+ String potion_bag_bytes = Utils.getElementAsString(Utils.getElement(profileInfo, "potion_bag.data"), "Hz8IAAAAAAAAAD9iYD9kYD9kAAMAPwI/Gw0AAAA=");
+ String inv_contents_bytes = Utils.getElementAsString(Utils.getElement(profileInfo, "inv_contents.data"), "Hz8IAAAAAAAAAD9iYD9kYD9kAAMAPwI/Gw0AAAA=");
+ String talisman_bag_bytes = Utils.getElementAsString(Utils.getElement(profileInfo, "talisman_bag.data"), "Hz8IAAAAAAAAAD9iYD9kYD9kAAMAPwI/Gw0AAAA=");
+ String candy_inventory_contents_bytes = Utils.getElementAsString(Utils.getElement(profileInfo, "candy_inventory_contents.data"), "Hz8IAAAAAAAAAD9iYD9kYD9kAAMAPwI/Gw0AAAA=");
+
+ JsonObject inventoryInfo = new JsonObject();
+
+ String[] inv_names = new String[]{"inv_armor", "fishing_bag", "quiver", "ender_chest_contents", "wardrobe_contents",
+ "potion_bag", "inv_contents", "talisman_bag", "candy_inventory_contents"};
+ String[] inv_bytes = new String[]{inv_armor_bytes, fishing_bag_bytes, quiver_bytes, ender_chest_contents_bytes, wardrobe_contents_bytes,
+ potion_bag_bytes, inv_contents_bytes, talisman_bag_bytes, candy_inventory_contents_bytes};
+ for(int i=0; i<inv_bytes.length; i++) {
+ try {
+ String bytes = inv_bytes[i];
+
+ JsonArray contents = new JsonArray();
+ NBTTagCompound inv_contents_nbt = CompressedStreamTools.readCompressed(new ByteArrayInputStream(Base64.getDecoder().decode(bytes)));
+ NBTTagList items = inv_contents_nbt.getTagList("i", 10);
+ for(int j=0; j<items.tagCount(); j++) {
+ JsonObject item = manager.getJsonFromNBTEntry(items.getCompoundTagAt(j));
+ contents.add(item);
+ }
+ inventoryInfo.add(inv_names[i], contents);
+ } catch(IOException e) {
+ inventoryInfo.add(inv_names[i], new JsonArray());
+ }
+ }
+
+ return inventoryInfo;
+ }
+
+ private final Pattern COLL_TIER_PATTERN = Pattern.compile("_(-?[0-9]+)");
+ public JsonObject getCollectionInfo(String profileId) {
+ JsonObject profileInfo = getProfileInformation(profileId);
+ if(profileInfo == null) return null;
+ if(profileId == null) profileId = latestProfile;
+ if(collectionInfoMap.containsKey(profileId)) return collectionInfoMap.get(profileId);
+
+
+ JsonElement unlocked_coll_tiers_element = Utils.getElement(profileInfo, "unlocked_coll_tiers");
+ if(unlocked_coll_tiers_element == null) {
+ JsonObject collectionInfo = new JsonObject();
+ collectionInfo.add("collection_tiers", new JsonObject());
+ return collectionInfo;
+ }
+ JsonArray unlocked_coll_tiers = unlocked_coll_tiers_element.getAsJsonArray();
+
+ JsonElement collectionInfoElement = Utils.getElement(profileInfo, "collections");
+ if(collectionInfoElement == null) {
+ JsonObject collectionInfo = new JsonObject();
+ collectionInfo.add("collection_tiers", new JsonObject());
+ return collectionInfo;
+ }
+ JsonObject collectionInfo = collectionInfoElement.getAsJsonObject();
+ JsonObject collectionTiers = new JsonObject();
+
+ 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);
+ }
+ }
+ }
+
+ collectionInfo.add("collection_tiers", collectionInfo);
+
+ return collectionInfo;
+ }
+
+ public PlayerStats.Stats getStats(String profileId) {
+ if(stats != null) return stats;
+ JsonObject profileInfo = getProfileInformation(profileId);
+ if(profileInfo == null) return PlayerStats.getBaseStats();
+
+ stats = PlayerStats.getStats(getSkillInfo(profileId), getInventoryInfo(profileId), getCollectionInfo(profileId), profileInfo);
+ return stats;
+ }
+
+ public String getUuid() {
+ return uuid;
+ }
+
+ public JsonObject getHypixelProfile() {
+ if(uuidToHypixelProfile.containsKey(uuid)) return uuidToHypixelProfile.get(uuid);
+ return null;
+ }
+ }
+
+ private HashMap<String, JsonObject> nameToHypixelProfile = new HashMap<>();
+ private HashMap<String, JsonObject> uuidToHypixelProfile = new HashMap<>();
+ private HashMap<String, Profile> uuidToProfileMap = new HashMap<>();
+
+ public void getHypixelProfile(String name, Consumer<JsonObject> callback) {
+ HashMap<String, String> args = new HashMap<>();
+ args.put("name", ""+name);
+ manager.hypixelApi.getHypixelApiAsync(manager.config.apiKey.value, "player",
+ args, jsonObject -> {
+ if(jsonObject.has("success") && jsonObject.get("success").getAsBoolean()) {
+ nameToHypixelProfile.put(name, jsonObject.get("player").getAsJsonObject());
+ uuidToHypixelProfile.put(jsonObject.get("player").getAsJsonObject().get("uuid").getAsString(), jsonObject.get("player").getAsJsonObject());
+ if(callback != null) callback.accept(jsonObject);
+ }
+ }
+ );
+ }
+
+ public Profile getProfileByName(String name, Consumer<Profile> callback) {
+ if(nameToHypixelProfile.containsKey(name)) {
+ return getProfileReset(nameToHypixelProfile.get(name).get("uuid").getAsString(), callback);
+ } else {
+ getHypixelProfile(name, jsonObject -> {
+ System.out.println("getting profile with callback");
+ getProfileReset(jsonObject.get("player").getAsJsonObject().get("uuid").getAsString(), callback);
+ });
+ return null;
+ }
+ }
+
+ public Profile getProfile(String uuid, Consumer<Profile> callback) {
+ Profile profile = uuidToProfileMap.computeIfAbsent(uuid, k -> new Profile(uuid));
+ if(profile.playerInformation != null) {
+ System.out.println("getting profile with callback1");
+ callback.accept(profile);
+ } else {
+ System.out.println("getting profile with callback3");
+ profile.getPlayerInformation(() -> callback.accept(profile));
+ }
+ return profile;
+ }
+
+ public Profile getProfileReset(String uuid, Consumer<Profile> callback) {
+ Profile profile = getProfile(uuid, callback);
+ profile.resetCache();
+ return profile;
+ }
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/questing/requirements/RequirementApi.java b/src/main/java/io/github/moulberry/notenoughupdates/questing/requirements/RequirementApi.java
index 951cfa50..27f9f293 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/questing/requirements/RequirementApi.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/questing/requirements/RequirementApi.java
@@ -40,7 +40,6 @@ public class RequirementApi extends Requirement {
private static JsonElement getElement(JsonElement element, String path) {
List<String> path_split = PATH_SPLITTER.splitToList(path);
if(element instanceof JsonObject) {
- System.out.println(path_split.get(0));
JsonElement e = element.getAsJsonObject().get(path_split.get(0));
if(path_split.size() > 1) {
return getElement(e, path_split.get(1));
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/HypixelApi.java b/src/main/java/io/github/moulberry/notenoughupdates/util/HypixelApi.java
index c271d63a..133619ae 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/util/HypixelApi.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/HypixelApi.java
@@ -62,11 +62,11 @@ public class HypixelApi {
}
public String generateApiUrl(String apiKey, String method, HashMap<String, String> args) {
- String url = "https://api.hypixel.net/" + method + "?key=" + apiKey;
+ StringBuilder url = new StringBuilder("https://api.hypixel.net/" + method + "?key=" + apiKey);
for(Map.Entry<String, String> entry : args.entrySet()) {
- url += "&" + entry.getKey() + "=" + entry.getValue();
+ url.append("&").append(entry.getKey()).append("=").append(entry.getValue());
}
- return url;
+ return url.toString();
}
}
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 57b89a0a..66400c00 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java
@@ -1,5 +1,9 @@
package io.github.moulberry.notenoughupdates.util;
+import com.google.common.base.Splitter;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonPrimitive;
import com.mojang.authlib.Agent;
import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService;
import com.mojang.authlib.yggdrasil.YggdrasilUserAuthentication;
@@ -376,6 +380,50 @@ public class Utils {
drawHoveringText(textLines, mouseX, mouseY, screenWidth, screenHeight, maxTextWidth, font, true);
}
+ public static JsonObject getConstant(String constant) {
+ File repo = NotEnoughUpdates.INSTANCE.manager.repoLocation;
+ if(repo.exists()) {
+ File jsonFile = new File(repo, "constants/"+constant+".json");
+ try {
+ return NotEnoughUpdates.INSTANCE.manager.getJsonFromFile(jsonFile);
+ } catch (Exception ignored) {
+ }
+ }
+ System.out.println(constant + " = null");
+ return null;
+ }
+
+ public static float getElementAsFloat(JsonElement element, float def) {
+ if(element == null) return def;
+ if(!element.isJsonPrimitive()) return def;
+ JsonPrimitive prim = element.getAsJsonPrimitive();
+ if(!prim.isNumber()) return def;
+ return prim.getAsFloat();
+ }
+
+ public static String getElementAsString(JsonElement element, String def) {
+ if(element == null) return def;
+ if(!element.isJsonPrimitive()) return def;
+ JsonPrimitive prim = element.getAsJsonPrimitive();
+ if(!prim.isString()) return def;
+ return prim.getAsString();
+ }
+
+ public static Splitter PATH_SPLITTER = Splitter.on(".").omitEmptyStrings().limit(2);
+ public static JsonElement getElement(JsonElement element, String path) {
+ List<String> path_split = PATH_SPLITTER.splitToList(path);
+ if(element instanceof JsonObject) {
+ JsonElement e = element.getAsJsonObject().get(path_split.get(0));
+ if(path_split.size() > 1) {
+ return getElement(e, path_split.get(1));
+ } else {
+ return e;
+ }
+ } else {
+ return element;
+ }
+ }
+
public static ChatStyle createClickStyle(ClickEvent.Action action, String value) {
ChatStyle style = new ChatStyle();
style.setChatClickEvent(new ClickEvent(action, value));
diff --git a/src/main/resources/assets/notenoughupdates/pv_basic.png b/src/main/resources/assets/notenoughupdates/pv_basic.png
new file mode 100644
index 00000000..8e9c8d85
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/pv_basic.png
Binary files differ