/* * Copyright (C) 2022 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 . */ package io.github.moulberry.notenoughupdates.profileviewer; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; import io.github.moulberry.notenoughupdates.NotEnoughUpdates; import io.github.moulberry.notenoughupdates.core.util.StringUtils; import io.github.moulberry.notenoughupdates.util.Constants; import io.github.moulberry.notenoughupdates.util.Utils; import net.minecraft.client.Minecraft; import net.minecraft.util.EnumChatFormatting; import net.minecraft.util.ResourceLocation; import org.apache.commons.lang3.text.WordUtils; import org.lwjgl.input.Mouse; import org.lwjgl.opengl.GL11; import java.io.IOException; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.TimeZone; import java.util.TreeMap; public class ExtraPage extends GuiProfileViewerPage { private static final ResourceLocation pv_extra = new ResourceLocation("notenoughupdates:pv_extra.png"); private TreeMap> topKills = null; private TreeMap> topDeaths = null; private int deathScroll = 0; private int killScroll = 0; private int mouseDWheel = 0; public ExtraPage(GuiProfileViewer instance) { super(instance); getInstance().killDeathSearchTextField.setSize(80, 12); } @Override public void keyTyped(char typedChar, int keyCode) throws IOException { super.keyTyped(typedChar, keyCode); if (getInstance().killDeathSearchTextField.getFocus()) { getInstance().killDeathSearchTextField.keyTyped(typedChar, keyCode); killScroll = 0; deathScroll = 0; } } @Override public boolean mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException { super.mouseClicked(mouseX, mouseY, mouseButton); //Note: don't know why it made me make it return a boolean, but it fixed the error, so I left it alone. //Dimensions: X: guiLeft + xStart + xOffset * 3, Y: guiTop + yStartBottom + 77, Width: 80, Height: 12 if (mouseX >= GuiProfileViewer.getGuiLeft() + 22 + 103 * 3 && mouseX <= GuiProfileViewer.getGuiLeft() + 22 + 103 * 3 + 80 && mouseY >= GuiProfileViewer.getGuiTop() + 105 + 77 && mouseY <= GuiProfileViewer.getGuiTop() + 105 + 77 + 12) { getInstance().killDeathSearchTextField.mouseClicked(mouseX, mouseY, mouseButton); getInstance().playerNameTextField.otherComponentClick(); return true; } getInstance().killDeathSearchTextField.otherComponentClick(); return false; } // pls update in the future tyvm !!! final static HashMap slayers = new HashMap() { { put("zombie", 5); put("spider", 4); put("wolf", 4); put("enderman", 4); put("blaze", 4); } }; public void drawEssence( JsonObject profileInfo, float xStart, float yStartTop, float xOffset, float yOffset) { int guiLeft = GuiProfileViewer.getGuiLeft(); int guiTop = GuiProfileViewer.getGuiTop(); yStartTop = yStartTop + 78; if (Constants.PARENTS == null || !Constants.PARENTS.has("ESSENCE_WITHER")) { Utils.showOutdatedRepoNotification(); return; } JsonObject parents = Constants.PARENTS; JsonArray essenceArray = parents.get("ESSENCE_WITHER").getAsJsonArray(); for (int i = 0; i < essenceArray.size(); i++) { JsonElement jsonElement = essenceArray.get(i); String essenceName = jsonElement.getAsString(); TreeMap itemInformation = NotEnoughUpdates.INSTANCE.manager.getItemInformation(); if (!itemInformation.containsKey(essenceName)) { Utils.showOutdatedRepoNotification(); return; } String displayName = itemInformation.get(essenceName).getAsJsonObject().get("displayname").getAsString(); if (profileInfo.has(essenceName.toLowerCase())) { int essenceNumber = profileInfo.get(essenceName.toLowerCase()).getAsInt(); Utils.renderAlignedString( EnumChatFormatting.GOLD + displayName, EnumChatFormatting.WHITE + StringUtils.shortNumberFormat(essenceNumber, 0), guiLeft + xStart + xOffset, guiTop + yStartTop + yOffset * i, 76 ); } } } @Override public void drawPage(int mouseX, int mouseY, float partialTicks) { int guiLeft = GuiProfileViewer.getGuiLeft(); int guiTop = GuiProfileViewer.getGuiTop(); Minecraft.getMinecraft().getTextureManager().bindTexture(pv_extra); Utils.drawTexturedRect(guiLeft, guiTop, getInstance().sizeX, getInstance().sizeY, GL11.GL_NEAREST); ProfileViewer.Profile profile = GuiProfileViewer.getProfile(); String profileId = GuiProfileViewer.getProfileId(); JsonObject profileInfo = profile.getProfileInformation(profileId); if (profileInfo == null) return; Map skyblockInfo = profile.getSkyblockInfo(profileId); float xStart = 22; float xOffset = 103; float yStartTop = 27; float yStartBottom = 105; float yOffset = 10; float bankBalance = Utils.getElementAsFloat(Utils.getElement(profileInfo, "banking.balance"), 0); float purseBalance = Utils.getElementAsFloat(Utils.getElement(profileInfo, "coin_purse"), 0); Utils.renderAlignedString( EnumChatFormatting.GOLD + "Bank Balance", EnumChatFormatting.WHITE + StringUtils.shortNumberFormat(bankBalance), guiLeft + xStart, guiTop + yStartTop, 76 ); Utils.renderAlignedString( EnumChatFormatting.GOLD + "Purse", EnumChatFormatting.WHITE + StringUtils.shortNumberFormat(purseBalance), guiLeft + xStart, guiTop + yStartTop + yOffset, 76 ); { String first_join = getTimeSinceString(profileInfo, "first_join"); if (first_join != null) { Utils.renderAlignedString( EnumChatFormatting.AQUA + "Joined", EnumChatFormatting.WHITE + first_join, guiLeft + xStart, guiTop + yStartTop + yOffset * 2, 76 ); } } JsonObject guildInfo = profile.getGuildInformation(null); boolean shouldRenderGuild = guildInfo != null && guildInfo.has("name"); { if (shouldRenderGuild) { Utils.renderAlignedString( EnumChatFormatting.AQUA + "Guild", EnumChatFormatting.WHITE + guildInfo.get("name").getAsString(), guiLeft + xStart, guiTop + yStartTop + yOffset * 3, 76 ); } } { GuiProfileViewer.pronouns.peekValue().flatMap(it -> it).ifPresent(choice -> Utils.renderAlignedString( EnumChatFormatting.GREEN + "Pronouns", EnumChatFormatting.WHITE + String.join(" / ", choice.render()), guiLeft + xStart, guiTop + yStartTop + yOffset * (shouldRenderGuild ? 4 : 3), 76 )); } float fairySouls = Utils.getElementAsFloat(Utils.getElement(profileInfo, "fairy_souls_collected"), 0); int fairySoulMax = 227; if (Constants.FAIRYSOULS != null && Constants.FAIRYSOULS.has("Max Souls")) { fairySoulMax = Constants.FAIRYSOULS.get("Max Souls").getAsInt(); } Utils.renderAlignedString( EnumChatFormatting.LIGHT_PURPLE + "Fairy Souls", EnumChatFormatting.WHITE.toString() + (int) fairySouls + "/" + fairySoulMax, guiLeft + xStart, guiTop + yStartBottom, 76 ); if (skyblockInfo != null) { float totalSkillLVL = 0; float totalTrueSkillLVL = 0; float totalSlayerLVL = 0; float totalSkillCount = 0; float totalSlayerCount = 0; float totalSlayerXP = 0; List skills = Arrays.asList( "taming", "mining", "foraging", "enchanting", "farming", "combat", "fishing", "alchemy", "carpentry" ); for (Map.Entry entry : skyblockInfo.entrySet()) { if (skills.contains(entry.getKey())) { totalSkillLVL += entry.getValue().level; totalTrueSkillLVL += Math.floor(entry.getValue().level); totalSkillCount++; } else if (slayers.containsKey(entry.getKey())) { totalSlayerLVL += entry.getValue().level; totalSlayerCount++; totalSlayerXP += entry.getValue().totalXp; } } float avgSkillLVL = totalSkillLVL / totalSkillCount; float avgTrueSkillLVL = totalTrueSkillLVL / totalSkillCount; float avgSlayerLVL = totalSlayerLVL / totalSlayerCount; Utils.renderAlignedString( EnumChatFormatting.RED + "AVG Skill Level", EnumChatFormatting.WHITE.toString() + Math.floor(avgSkillLVL * 10) / 10, guiLeft + xStart, guiTop + yStartBottom + yOffset, 76 ); Utils.renderAlignedString( EnumChatFormatting.RED + "True AVG Skill Level", EnumChatFormatting.WHITE.toString() + Math.floor(avgTrueSkillLVL * 10) / 10, guiLeft + xStart, guiTop + yStartBottom + yOffset * 2, 76 ); Utils.renderAlignedString( EnumChatFormatting.RED + "AVG Slayer Level", EnumChatFormatting.WHITE.toString() + Math.floor(avgSlayerLVL * 10) / 10, guiLeft + xStart, guiTop + yStartBottom + yOffset * 3, 76 ); Utils.renderAlignedString( EnumChatFormatting.RED + "Total Slayer XP", EnumChatFormatting.WHITE + StringUtils.shortNumberFormat(totalSlayerXP), guiLeft + xStart, guiTop + yStartBottom + yOffset * 4, 76 ); } float auctions_bids = Utils.getElementAsFloat(Utils.getElement(profileInfo, "stats.auctions_bids"), 0); float auctions_highest_bid = Utils.getElementAsFloat( Utils.getElement(profileInfo, "stats.auctions_highest_bid"), 0 ); float auctions_won = Utils.getElementAsFloat(Utils.getElement(profileInfo, "stats.auctions_won"), 0); float auctions_created = Utils.getElementAsFloat(Utils.getElement(profileInfo, "stats.auctions_created"), 0); float auctions_gold_spent = Utils.getElementAsFloat(Utils.getElement(profileInfo, "stats.auctions_gold_spent"), 0); float auctions_gold_earned = Utils.getElementAsFloat( Utils.getElement(profileInfo, "stats.auctions_gold_earned"), 0 ); Utils.renderAlignedString( EnumChatFormatting.DARK_PURPLE + "Auction Bids", EnumChatFormatting.WHITE.toString() + (int) auctions_bids, guiLeft + xStart + xOffset, guiTop + yStartTop, 76 ); Utils.renderAlignedString( EnumChatFormatting.DARK_PURPLE + "Highest Bid", EnumChatFormatting.WHITE + StringUtils.shortNumberFormat(auctions_highest_bid), guiLeft + xStart + xOffset, guiTop + yStartTop + yOffset, 76 ); Utils.renderAlignedString( EnumChatFormatting.DARK_PURPLE + "Auctions Won", EnumChatFormatting.WHITE.toString() + (int) auctions_won, guiLeft + xStart + xOffset, guiTop + yStartTop + yOffset * 2, 76 ); Utils.renderAlignedString( EnumChatFormatting.DARK_PURPLE + "Auctions Created", EnumChatFormatting.WHITE.toString() + (int) auctions_created, guiLeft + xStart + xOffset, guiTop + yStartTop + yOffset * 3, 76 ); Utils.renderAlignedString( EnumChatFormatting.DARK_PURPLE + "Gold Spent", EnumChatFormatting.WHITE + StringUtils.shortNumberFormat(auctions_gold_spent), guiLeft + xStart + xOffset, guiTop + yStartTop + yOffset * 4, 76 ); Utils.renderAlignedString( EnumChatFormatting.DARK_PURPLE + "Gold Earned", EnumChatFormatting.WHITE + StringUtils.shortNumberFormat(auctions_gold_earned), guiLeft + xStart + xOffset, guiTop + yStartTop + yOffset * 5, 76 ); float pet_milestone_ores_mined = Utils.getElementAsFloat(Utils.getElement( profileInfo, "stats.pet_milestone_ores_mined" ), 0); float pet_milestone_sea_creatures_killed = Utils.getElementAsFloat( Utils.getElement(profileInfo, "stats.pet_milestone_sea_creatures_killed"), 0 ); float items_fished = Utils.getElementAsFloat(Utils.getElement(profileInfo, "stats.items_fished"), 0); float items_fished_treasure = Utils.getElementAsFloat( Utils.getElement(profileInfo, "stats.items_fished_treasure"), 0 ); float items_fished_large_treasure = Utils.getElementAsFloat(Utils.getElement( profileInfo, "stats.items_fished_large_treasure" ), 0); Utils.renderAlignedString( EnumChatFormatting.GREEN + "Ores Mined", EnumChatFormatting.WHITE.toString() + (int) pet_milestone_ores_mined, guiLeft + xStart + xOffset * 2, guiTop + yStartTop, 76 ); Utils.renderAlignedString( EnumChatFormatting.GREEN + "Sea Creatures Killed", EnumChatFormatting.WHITE.toString() + (int) pet_milestone_sea_creatures_killed, guiLeft + xStart + xOffset * 2, guiTop + yStartTop + yOffset, 76 ); Utils.renderAlignedString( EnumChatFormatting.GREEN + "Items Fished", EnumChatFormatting.WHITE.toString() + (int) items_fished, guiLeft + xStart + xOffset * 2, guiTop + yStartTop + yOffset * 3, 76 ); Utils.renderAlignedString( EnumChatFormatting.GREEN + "Treasures Fished", EnumChatFormatting.WHITE.toString() + (int) items_fished_treasure, guiLeft + xStart + xOffset * 2, guiTop + yStartTop + yOffset * 4, 76 ); Utils.renderAlignedString( EnumChatFormatting.GREEN + "Large Treasures", EnumChatFormatting.WHITE.toString() + (int) items_fished_large_treasure, guiLeft + xStart + xOffset * 2, guiTop + yStartTop + yOffset * 5, 76 ); drawEssence(profileInfo, xStart, yStartTop, xOffset, yOffset); if (topKills == null) { topKills = new TreeMap<>(); JsonObject stats = profileInfo.get("stats").getAsJsonObject(); for (Map.Entry entry : stats.entrySet()) { if (entry.getKey().startsWith("kills_")) { if (entry.getValue().isJsonPrimitive()) { JsonPrimitive prim = (JsonPrimitive) entry.getValue(); if (prim.isNumber()) { String name = WordUtils.capitalizeFully(entry.getKey().substring("kills_".length()).replace("_", " ")); Set kills = topKills.computeIfAbsent(prim.getAsInt(), k -> new HashSet<>()); kills.add(name); } } } } } if (topDeaths == null) { topDeaths = new TreeMap<>(); JsonObject stats = profileInfo.get("stats").getAsJsonObject(); for (Map.Entry entry : stats.entrySet()) { if (entry.getKey().startsWith("deaths_")) { if (entry.getValue().isJsonPrimitive()) { JsonPrimitive prim = (JsonPrimitive) entry.getValue(); if (prim.isNumber()) { String name = WordUtils.capitalizeFully(entry.getKey().substring("deaths_".length()).replace("_", " ")); Set deaths = topDeaths.computeIfAbsent(prim.getAsInt(), k -> new HashSet<>()); deaths.add(name); } } } } } getInstance().killDeathSearchTextField.render((int) (guiLeft + xStart + xOffset * 3), (int) (guiTop + yStartBottom + 77)); float killDeathX = guiLeft + xStart + xOffset * 3; if(mouseX >= killDeathX && mouseX <= killDeathX+76) { if(mouseY >= guiTop + yStartTop && mouseY <= guiTop + yStartTop + 65) { if(mouseDWheel != 0) {if(mouseDWheel > 0) {killScroll-=1;} else {killScroll+=1;}} mouseDWheel = Mouse.getDWheel(); if(killScroll < 0) {killScroll = 0;} } else if(mouseY >= guiTop + yStartBottom && mouseY <= guiTop + yStartBottom + 65) { if(mouseDWheel != 0) {if(mouseDWheel > 0) {deathScroll-=1;} else {deathScroll+=1;}} mouseDWheel = Mouse.getDWheel(); if(deathScroll < 0) {deathScroll = 0;} } } int index = 0; int skipCount = 0; for (int killCount : topKills.descendingKeySet()) { Set kills = topKills.get(killCount); for (String killType : kills) { boolean isSearch = getInstance().killDeathSearchTextField.getText().isEmpty() || killType.toLowerCase(Locale.ROOT).contains(getInstance().killDeathSearchTextField.getText().toLowerCase(Locale.ROOT)); float killY = guiTop + yStartTop + yOffset * ((index-skipCount) - killScroll); if(!isSearch) skipCount++; if(isSearch && killY+6 < guiTop+yStartTop+65 && killY >= guiTop + yStartTop) { Utils.renderAlignedString( EnumChatFormatting.YELLOW + killType + " Kills", EnumChatFormatting.WHITE.toString() + killCount, killDeathX, killY, 76 ); } index++; } } index = 0; skipCount = 0; for (int deathCount : topDeaths.descendingKeySet()) { Set deaths = topDeaths.get(deathCount); for (String deathType : deaths) { boolean isSearch = getInstance().killDeathSearchTextField.getText().isEmpty() || deathType.toLowerCase(Locale.ROOT).contains(getInstance().killDeathSearchTextField.getText().toLowerCase(Locale.ROOT)); float deathY = guiTop + yStartBottom + yOffset * ((index-skipCount) - deathScroll); if(!isSearch) skipCount++; if(isSearch && deathY+6 < guiTop+yStartBottom+65 && deathY >= guiTop + yStartBottom) { Utils.renderAlignedString( EnumChatFormatting.YELLOW + "Deaths: " + deathType, EnumChatFormatting.WHITE.toString() + deathCount, killDeathX, deathY, 76 ); } index++; } } } private String getTimeSinceString(JsonObject profileInfo, String path) { JsonElement lastSaveElement = Utils.getElement(profileInfo, path); if (lastSaveElement != null && lastSaveElement.isJsonPrimitive()) { Instant lastSave = Instant.ofEpochMilli(lastSaveElement.getAsLong()); LocalDateTime lastSaveTime = LocalDateTime.ofInstant(lastSave, TimeZone.getDefault().toZoneId()); long timeDiff = System.currentTimeMillis() - lastSave.toEpochMilli(); LocalDateTime sinceOnline = LocalDateTime.ofInstant(Instant.ofEpochMilli(timeDiff), ZoneId.of("UTC")); String renderText; if (timeDiff < 60000L) { renderText = sinceOnline.getSecond() + " seconds ago."; } else if (timeDiff < 3600000L) { renderText = sinceOnline.getMinute() + " minutes ago."; } else if (timeDiff < 86400000L) { renderText = sinceOnline.getHour() + " hours ago."; } else if (timeDiff < 31556952000L) { renderText = sinceOnline.getDayOfYear() + " days ago."; } else { renderText = lastSaveTime.format(DateTimeFormatter.ofPattern("dd-MM-yyyy")); } return renderText; } return null; } }