diff options
10 files changed, 759 insertions, 25 deletions
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java index c6a0c04f..16e513a9 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java @@ -243,6 +243,9 @@ public class NotEnoughUpdates { if (config.profileViewer.pageLayout.size() == 10) { config.profileViewer.pageLayout.add(10); } + if (config.profileViewer.pageLayout.size() == 11) { + config.profileViewer.pageLayout.add(11); + } // Remove after 2.1 ig if ("dangerous".equals(config.apiData.repoBranch)) { 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 42a52639..9064ea49 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 @@ -75,10 +75,11 @@ public class ProfileViewer { "\u00a7eTrophy Fish", "\u00a7eBestiary", "\u00a7eCrimson Isle", + "\u00a7eMuseum", }, allowDeleting = false ) - public List<Integer> pageLayout = new ArrayList<>(Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); + public List<Integer> pageLayout = new ArrayList<>(Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)); @Expose @ConfigOption( 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 8a994a17..fb1b3364 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ExtraPage.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ExtraPage.java @@ -36,10 +36,6 @@ 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.ArrayList; import java.util.Arrays; import java.util.HashSet; @@ -47,7 +43,6 @@ 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 { @@ -562,24 +557,7 @@ public class ExtraPage extends GuiProfileViewerPage { 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 Utils.timeSinceMillisecond(lastSaveElement.getAsLong()); } return null; } 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 e7476979..78c810a3 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java @@ -211,6 +211,7 @@ public class GuiProfileViewer extends GuiScreen { pages.put(ProfileViewerPage.TROPHY_FISH, new TrophyFishPage(this)); pages.put(ProfileViewerPage.BESTIARY, new BestiaryPage(this)); pages.put(ProfileViewerPage.CRIMSON_ISLE, new CrimsonIslePage(this)); + pages.put(ProfileViewerPage.MUSEUM, new MuseumPage(this)); } public static int getGuiLeft() { @@ -1202,7 +1203,8 @@ public class GuiProfileViewer extends GuiScreen { BINGO(7, Items.filled_map, "§zBingo"), TROPHY_FISH(8, Items.fishing_rod, "§3Trophy Fish"), BESTIARY(9, Items.iron_sword, "§cBestiary"), - CRIMSON_ISLE(10, Item.getItemFromBlock(Blocks.netherrack), "§4Crimson Isle"); + CRIMSON_ISLE(10, Item.getItemFromBlock(Blocks.netherrack), "§4Crimson Isle"), + MUSEUM(11, Items.leather_chestplate, "§6Museum"); public final ItemStack stack; public final int id; diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/MuseumPage.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/MuseumPage.java new file mode 100644 index 00000000..0b68f798 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/MuseumPage.java @@ -0,0 +1,536 @@ +/* + * Copyright (C) 2023 NotEnoughUpdates contributors + * + * This file is part of NotEnoughUpdates. + * + * NotEnoughUpdates is free software: you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * NotEnoughUpdates is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>. + */ + +package io.github.moulberry.notenoughupdates.profileviewer; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import 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.client.renderer.GlStateManager; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.ResourceLocation; +import org.apache.commons.lang3.tuple.Pair; +import org.lwjgl.input.Keyboard; +import org.lwjgl.input.Mouse; +import org.lwjgl.opengl.GL11; + +import java.io.IOException; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import static io.github.moulberry.notenoughupdates.profileviewer.GuiProfileViewer.pv_elements; + +public class MuseumPage extends GuiProfileViewerPage { + private static final ResourceLocation pv_inventories = + new ResourceLocation("notenoughupdates:pv_inventories.png"); + private static final ResourceLocation pv_museum = new ResourceLocation("notenoughupdates:pv_museum.png"); + private static final LinkedHashMap<String, ItemStack> museumCategories = new LinkedHashMap<String, ItemStack>() { + { + put("weapons", Utils.createItemStack(Items.diamond_sword, EnumChatFormatting.GOLD + "Weapons")); + put("armor", Utils.createItemStack(Items.diamond_chestplate, EnumChatFormatting.GOLD + "Armor Sets")); + put( + "rarities", Utils.createSkull( + EnumChatFormatting.GOLD + "Rarities", + "b569ed03-94ae-3da9-a01d-9726633d5b8b", + "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODZhZGRiZDVkZWRhZDQwOTk5NDczYmU0YTdmNDhmNjIzNmE3OWEwZGNlOTcxYjVkYmQ3MzcyMDE0YWUzOTRkIn19fQ" + ) + ); + put("special", Utils.createItemStack(Items.cake, EnumChatFormatting.GOLD + "Special Items")); + } + }; + private static final ResourceLocation CHEST_GUI_TEXTURE = + new ResourceLocation("textures/gui/container/generic_54.png"); + private static String selectedMuseumCategory = "weapons"; + JsonObject museum = Constants.MUSEUM; + int pageArrowsHeight = 164; + int pages = 0; + int onPage = 0; + String currentItemSelected = null; + JsonArray selectedItem = null; + + public MuseumPage(GuiProfileViewer instance) {super(instance);} + + @Override + public void drawPage(int mouseX, int mouseY, float partialTicks) { + int guiLeft = GuiProfileViewer.getGuiLeft(); + int guiTop = GuiProfileViewer.getGuiTop(); + + SkyblockProfiles.SkyblockProfile selectedProfile = getSelectedProfile(); + if (selectedProfile == null) { + return; + } + + Minecraft.getMinecraft().getTextureManager().bindTexture(pv_museum); + Utils.drawTexturedRect(guiLeft, guiTop, getInstance().sizeX, getInstance().sizeY, GL11.GL_NEAREST); + + SkyblockProfiles.SkyblockProfile.MuseumData museumData = selectedProfile.getMuseumData(); + long value = museumData.getValue(); + + if (value == -2) { + String message = EnumChatFormatting.RED + "Museum API Disabled!"; + Utils.drawStringCentered(message, guiLeft + 250, guiTop + 101, true, 0); + return; + } + if (value == -1) { + String message = EnumChatFormatting.YELLOW + "Museum Data Loading!"; + Utils.drawStringCentered(message, guiLeft + 250, guiTop + 101, true, 0); + return; + } + if (value == -3 || museum == null) { + String message = EnumChatFormatting.RED + "Missing Repo Data!"; + Utils.drawStringCentered(message, guiLeft + 250, guiTop + 101, true, 0); + return; + } + + int xIndex = 0; + for (Map.Entry<String, ItemStack> entry : museumCategories.entrySet()) { + Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements); + + if (entry.getKey().equals(selectedMuseumCategory)) { + Utils.drawTexturedRect( + guiLeft + 16 + 34 * xIndex, + guiTop + 172, + 20, + 20, + 20 / 256f, + 0, + 20 / 256f, + 0, + GL11.GL_NEAREST + ); + Utils.drawItemStackWithText(entry.getValue(), guiLeft + 19 + 34 * xIndex, guiTop + 175, "" + (xIndex + 1)); + } else { + Utils.drawTexturedRect( + guiLeft + 16 + 34 * xIndex, + guiTop + 172, + 20, + 20, + 0, + 20 / 256f, + 0, + 20 / 256f, + GL11.GL_NEAREST + ); + Utils.drawItemStackWithText(entry.getValue(), guiLeft + 18 + 34 * xIndex, guiTop + 174, "" + (xIndex + 1)); + } + xIndex++; + } + + Utils.renderAlignedString( + EnumChatFormatting.GOLD + "Museum Value", + EnumChatFormatting.WHITE + StringUtils.shortNumberFormat(value), + guiLeft + 21, + guiTop + 25, + 114 + ); + + int donated = + museumData.getWeaponItems().size() + museumData.getArmorItems().size() + museumData.getRaritiesItems().size(); + Utils.renderAlignedString( + EnumChatFormatting.BLUE + "Total Donations", + EnumChatFormatting.WHITE + "" + donated, + guiLeft + 21, + guiTop + 45, + 114 + ); + int maximum = getMaximum("total"); + getInstance().renderBar(guiLeft + 20, guiTop + 55, 116, (float) donated / maximum); + + donated = museumData.getWeaponItems().size(); + Utils.renderAlignedString( + EnumChatFormatting.BLUE + "Weapons Donated", + EnumChatFormatting.WHITE + "" + donated, + guiLeft + 21, + guiTop + 70, + 114 + ); + maximum = getMaximum("weapons"); + getInstance().renderBar(guiLeft + 20, guiTop + 80, 116, (float) donated / maximum); + + donated = museumData.getArmorItems().size(); + Utils.renderAlignedString( + EnumChatFormatting.BLUE + "Armor Donated", + EnumChatFormatting.WHITE + "" + donated, + guiLeft + 21, + guiTop + 95, + 114 + ); + maximum = getMaximum("armor"); + getInstance().renderBar(guiLeft + 20, guiTop + 105, 116, (float) donated / maximum); + + donated = museumData.getRaritiesItems().size(); + Utils.renderAlignedString( + EnumChatFormatting.BLUE + "Rarities Donated", + EnumChatFormatting.WHITE + "" + donated, + guiLeft + 21, + guiTop + 120, + 114 + ); + maximum = getMaximum("rarities"); + getInstance().renderBar(guiLeft + 20, guiTop + 130, 116, (float) donated / maximum); + + donated = museumData.getSpecialItems().size(); + Utils.renderAlignedString( + EnumChatFormatting.BLUE + "Special Items Donated", + EnumChatFormatting.WHITE + String.valueOf(donated), + guiLeft + 21, + guiTop + 145, + 114 + ); + + Utils.drawStringCentered( + museumCategories.get(selectedMuseumCategory).getDisplayName(), + guiLeft + 251, guiTop + 14, true, 4210752 + ); + + if (pages == 0) { + setPage(selectedMuseumCategory); + } + + boolean leftHovered = false; + boolean rightHovered = false; + if (Mouse.isButtonDown(0)) { + if (mouseY > guiTop + pageArrowsHeight && mouseY < guiTop + pageArrowsHeight + 16) { + if (mouseX > guiLeft + 251 - 12 && mouseX < guiLeft + 251 + 12) { + if (mouseX < guiLeft + 251) { + leftHovered = true; + } else { + rightHovered = true; + } + } + } + } + Minecraft.getMinecraft().getTextureManager().bindTexture(GuiProfileViewer.resource_packs); + + if (onPage > 0) { + Utils.drawTexturedRect( + guiLeft + 251 - 12, + guiTop + pageArrowsHeight, + 12, + 16, + 29 / 256f, + 53 / 256f, + !leftHovered ? 0 : 32 / 256f, + !leftHovered ? 32 / 256f : 64 / 256f, + GL11.GL_NEAREST + ); + } + if (onPage < pages && pages > 1) { + Utils.drawTexturedRect( + guiLeft + 251, + guiTop + pageArrowsHeight, + 12, + 16, + 5 / 256f, + 29 / 256f, + !rightHovered ? 0 : 32 / 256f, + !rightHovered ? 32 / 256f : 64 / 256f, + GL11.GL_NEAREST + ); + } + + GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); + Minecraft.getMinecraft().getTextureManager().bindTexture(CHEST_GUI_TEXTURE); + + int inventoryRows = 4; + int invSizeY = inventoryRows * 18 + 17 + 7; + + int inventoryX = guiLeft + 251 - 176 / 2; + int inventoryY = guiTop + 101 - invSizeY / 2; + getInstance().drawTexturedModalRect(inventoryX, inventoryY, 0, 0, 176, inventoryRows * 18 + 17); + getInstance().drawTexturedModalRect(inventoryX, inventoryY + inventoryRows * 18 + 17, 0, 215, 176, 7); + + JsonArray categoryItems = new JsonArray(); + Map<String, JsonArray> categoryDonated = new HashMap<>(); + switch (selectedMuseumCategory) { + case "weapons": + categoryItems = museum.get("weapons").getAsJsonArray(); + categoryDonated = museumData.getWeaponItems(); + break; + case "armor": + categoryItems = museum.get("armor").getAsJsonArray(); + categoryDonated = museumData.getArmorItems(); + break; + case "rarities": + categoryItems = museum.get("rarities").getAsJsonArray(); + categoryDonated = museumData.getRaritiesItems(); + break; + case "special": + pages = (int) Math.floor(donated / 28.0); + + List<JsonArray> specialItems = museumData.getSpecialItems(); + + int startIndex = onPage * 28; + int endIndex = Math.min(startIndex + 28, specialItems.size()); + + int row = 0; + int slot = 0; + for (int i = startIndex; i < endIndex; i++) { + JsonArray items = specialItems.get(i); + JsonObject item = (JsonObject) items.get(0); + ItemStack stack = NotEnoughUpdates.INSTANCE.manager.jsonToStack(item, true); + + if (slot % 7 == 0 && slot > 1) { + slot = 0; + row++; + } + + int x = guiLeft + (inventoryX - guiLeft) + 8 + (slot * 18) + 18; + int y = guiTop + 71 + (row * 18); + slot++; + + if ((mouseX >= x && mouseX <= x + 16) && + (mouseY >= y && mouseY <= y + 16)) { + getInstance().tooltipToDisplay = stack.getTooltip(Minecraft.getMinecraft().thePlayer, false); + String itemID = item.get("internalname").getAsString(); + if (Mouse.isButtonDown(0) && museumData.getSavedItems().containsKey(itemID)) { + selectedItem = items; + currentItemSelected = itemID; + } + } + Utils.drawItemStack(stack, x, y); + } + break; + default: + } + + if (categoryItems != null) { + int row = 0; + int slot = 0; + int startIndex = onPage * 28; + int endIndex = Math.min(startIndex + 28, categoryItems.size()); + for (int i = startIndex; i < endIndex; i++) { + boolean actualItem = false; + JsonElement donatedItem = categoryItems.get(i); + String itemID = donatedItem.getAsString(); + + if (slot % 7 == 0 && slot > 1) { + slot = 0; + row++; + } + + int x = guiLeft + (inventoryX - guiLeft) + 8 + (slot * 18) + 18; + int y = guiTop + 71 + (row * 18); + slot++; + + JsonObject nameMappings = museum.get("armor_to_id").getAsJsonObject(); + String mappedName = itemID; + if (nameMappings.has(itemID)) { + mappedName = nameMappings.get(itemID).getAsString(); + } + String displayName = NotEnoughUpdates.INSTANCE.manager.getDisplayName(mappedName); + + ItemStack stack = Utils.createItemStack(Items.dye, displayName, 8, EnumChatFormatting.RED + "Missing"); + JsonArray items = new JsonArray(); + if (categoryDonated.containsKey(itemID)) { + items = categoryDonated.get(itemID); + JsonObject item = (JsonObject) items.get(0); + if (!Objects.equals(item.get("internalname").getAsString(), "_")) { + actualItem = true; + } + stack = NotEnoughUpdates.INSTANCE.manager.jsonToStack(item, true); + } + + if ((mouseX >= x && mouseX <= x + 16) && + (mouseY >= y && mouseY <= y + 16)) { + if (Mouse.isButtonDown(0) && museumData.getSavedItems().containsKey(itemID) && actualItem) { + selectedItem = items; + currentItemSelected = itemID; + } + getInstance().tooltipToDisplay = stack.getTooltip(Minecraft.getMinecraft().thePlayer, false); + } + Utils.drawItemStack(stack, x, y); + } + } + + if (currentItemSelected != null) { + int size = selectedItem.size(); + int startX = guiLeft + 375 + 5; + Minecraft.getMinecraft().getTextureManager().bindTexture(pv_inventories); + switch (size) { + case 1: + Utils.drawTexturedRect( + guiLeft + 375, + guiTop + 100, + 26, + 32, + 75 / 101f, + 1, + 69 / 101f, + 1, + GL11.GL_NEAREST + ); + break; + case 3: + Utils.drawTexturedRect( + guiLeft + 375, + guiTop + 100, + 26, + 68, + 75 / 101f, + 1, + 0, + 68 / 101f, + GL11.GL_NEAREST + ); + break; + case 4: + Utils.drawTexturedRect( + guiLeft + 375, + guiTop + 100, + 26, + 86, + 47 / 101f, + 73 / 101f, + 0, + 86 / 101f, + GL11.GL_NEAREST + ); + break; + case 8: + Utils.drawTexturedRect( + guiLeft + 365, + guiTop + 100, + 45, + 86, + 0, + 45 / 101f, + 0, + 86 / 101f, + GL11.GL_NEAREST + ); + startX = guiLeft + 365 + 5; + break; + default: + } + + int startY = guiTop + 100 + 8; + int row = 0; + int column = 0; + for (int i = 0; i < size; i++) { + JsonObject item = (JsonObject) selectedItem.get(i); + + if (row % 4 == 0 && row > 1) { + column = 1; + row = 0; + } + + int x = startX + (column * 18); + int y = startY + (row * 18); + + ItemStack stack = NotEnoughUpdates.INSTANCE.manager.jsonToStack(item, true); + Utils.drawItemStack(stack, x, y); + + if ((mouseX >= x && mouseX <= x + 16) && + (mouseY >= y && mouseY <= y + 16)) { + getInstance().tooltipToDisplay = stack.getTooltip(Minecraft.getMinecraft().thePlayer, false); + } + row++; + } + + Pair<Long, Boolean> itemData = museumData.getSavedItems().get(currentItemSelected); + String donationStatus = + itemData.getRight() ? EnumChatFormatting.YELLOW + "Borrowing" : EnumChatFormatting.GREEN + "In Museum"; + String donationTime = Utils.timeSinceMillisecond(itemData.getLeft()); + + Utils.drawStringCentered(EnumChatFormatting.BLUE + "Donated", guiLeft + 391, guiTop + 35, true, 4210752); + Utils.drawStringCentered(EnumChatFormatting.WHITE + donationTime, guiLeft + 391, guiTop + 47, true, 4210752); + Utils.drawStringCentered(EnumChatFormatting.BLUE + "Currently", guiLeft + 391, guiTop + 70, true, 4210752); + Utils.drawStringCentered(donationStatus, guiLeft + 391, guiTop + 82, true, 4210752); + } + } + + @Override + public void mouseReleased(int mouseX, int mouseY, int mouseButton) { + int guiLeft = GuiProfileViewer.getGuiLeft(); + int guiTop = GuiProfileViewer.getGuiTop(); + int xIndex = 0; + for (Map.Entry<String, ItemStack> entry : museumCategories.entrySet()) { + if (mouseX > guiLeft + 16 + 34 * xIndex && mouseX < guiLeft + 16 + 34 * xIndex + 20) { + if (mouseY > guiTop + 172 && mouseY < guiTop + 172 + 20) { + setPage(entry.getKey()); + Utils.playPressSound(); + return; + } + } + xIndex++; + } + + if (mouseY > guiTop + pageArrowsHeight && mouseY < guiTop + pageArrowsHeight + 16) { + if (mouseX > guiLeft + 251 - 12 && mouseX < guiLeft + 251 + 12) { + if (mouseX < guiLeft + 251) { + if (onPage > 0) onPage--; + } else { + if (onPage < pages) onPage++; + } + } + } + } + + @Override + public void keyTyped(char typedChar, int keyCode) throws IOException { + switch (keyCode) { + case Keyboard.KEY_1: + case Keyboard.KEY_NUMPAD1: + setPage("weapons"); + break; + case Keyboard.KEY_2: + case Keyboard.KEY_NUMPAD2: + setPage("armor"); + break; + case Keyboard.KEY_3: + case Keyboard.KEY_NUMPAD3: + setPage("rarities"); + break; + case Keyboard.KEY_4: + case Keyboard.KEY_NUMPAD4: + setPage("special"); + break; + default: + return; + } + Utils.playPressSound(); + } + + private void setPage(String pageName) { + selectedMuseumCategory = pageName; + onPage = 0; + pages = (int) Math.floor(getMaximum(pageName) / 28.0); + } + + private int getMaximum(String name) { + if (museum != null && museum.has("max_values")) { + JsonObject maxValues = museum.get("max_values").getAsJsonObject(); + if (maxValues.has(name)) { + return maxValues.get(name).getAsInt(); + } + } + return 0; + } +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/SkyblockProfiles.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/SkyblockProfiles.java index 1d8def80..88251d32 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/SkyblockProfiles.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/SkyblockProfiles.java @@ -31,11 +31,13 @@ import io.github.moulberry.notenoughupdates.util.Constants; import io.github.moulberry.notenoughupdates.util.Utils; import io.github.moulberry.notenoughupdates.util.hypixelapi.ProfileCollectionInfo; import lombok.Getter; +import net.minecraft.init.Items; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompressedStreamTools; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.util.EnumChatFormatting; +import org.apache.commons.lang3.tuple.Pair; import javax.annotation.Nullable; import java.io.ByteArrayInputStream; @@ -48,6 +50,7 @@ import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; public class SkyblockProfiles { @@ -484,6 +487,180 @@ public class SkyblockProfiles { private PlayerStats.Stats stats; private Long networth = null; private SoopyNetworth soopyNetworth = null; + private MuseumData museumData = null; + private final AtomicBoolean updatingMuseumData = new AtomicBoolean(false); + + public class MuseumData { + private long museumValue; + private final Map<String, JsonArray> weaponItems = new HashMap<>(); + private final Map<String, JsonArray> armorItems = new HashMap<>(); + private final Map<String, JsonArray> raritiesItems = new HashMap<>(); + private final List<JsonArray> specialItems = new ArrayList<>(); + private final Map<String, Pair<Long, Boolean>> savedItems = new HashMap<>(); + + private MuseumData(JsonObject museumJson) { + JsonObject museum = Constants.MUSEUM; + if (museum == null) { + Utils.showOutdatedRepoNotification(); + museumValue = -3; + return; + } + if (museumJson == null || museumJson.isJsonNull() || museumJson.get("members").isJsonNull()) { + museumValue = -2; + return; + } + JsonObject members = museumJson.get("members").getAsJsonObject(); + if (members == null || members.isJsonNull() || !members.has(uuid)) { + museumValue = -2; + return; + } + JsonObject member = members.get(uuid).getAsJsonObject(); + if (member == null || member.isJsonNull() || !member.has("value")) { + museumValue = -2; + return; + } + museumValue = member.get("value").getAsLong(); + if (member.has("items")) { + JsonObject museumItemsData = member.get("items").getAsJsonObject(); + if (museumItemsData != null) { + for (Map.Entry<String, JsonElement> entry : museumItemsData.entrySet()) { + JsonObject itemJson = entry.getValue().getAsJsonObject(); + JsonArray contents = parseNbt(itemJson); + String itemName = entry.getKey(); + Long donationTime = itemJson.get("donated_time").getAsLong(); + boolean borrowing = false; + if (itemJson.has("borrowing")) { + borrowing = itemJson.get("borrowing").getAsBoolean(); + } + + getDataAndChildren(itemName, Pair.of(donationTime, borrowing)); + processItems(itemName, contents); + } + } + } + + if (member.has("special")) { + JsonArray specialItemsData = member.get("special").getAsJsonArray(); + if (specialItemsData != null) { + for (JsonElement element : specialItemsData) { + JsonObject itemData = element.getAsJsonObject(); + JsonArray contents = parseNbt(itemData); + + long donationTime = itemData.get("donated_time").getAsLong(); + JsonObject firstItem = contents.get(0).getAsJsonObject(); + String itemID = firstItem.get("internalname").getAsString(); + getDataAndChildren(itemID, Pair.of(donationTime, false)); + + specialItems.add(contents); + } + } + } + } + + private JsonArray parseNbt(JsonObject nbt) { + JsonArray contents = new JsonArray(); + JsonObject contentItems = nbt.get("items").getAsJsonObject(); + String contentBytes = contentItems.get("data").getAsString(); + + try { + NBTTagList items = CompressedStreamTools.readCompressed( + new ByteArrayInputStream(Base64.getDecoder().decode(contentBytes)) + ).getTagList("i", 10); + for (int j = 0; j < items.tagCount(); j++) { + JsonObject item = profileViewer.getManager().getJsonFromNBTEntry(items.getCompoundTagAt(j)); + if (item == null) { + continue; + } + contents.add(item); + } + } catch (IOException ignored) { + } + return contents; + } + + private void processItems(String itemName, JsonArray contents) { + JsonObject museum = Constants.MUSEUM; + storeItem(itemName, contents, museum.get("weapons").getAsJsonArray(), weaponItems); + storeItem(itemName, contents, museum.get("armor").getAsJsonArray(), armorItems); + storeItem(itemName, contents, museum.get("rarities").getAsJsonArray(), raritiesItems); + } + + private void storeItem(String itemName, JsonArray contents, JsonArray items, Map<String, JsonArray> itemMap) { + for (JsonElement item : items) { + if (Objects.equals(item.getAsString(), itemName)) { + itemMap.put(itemName, contents); + return; + } + } + } + + private void getDataAndChildren(String name, Pair<Long, Boolean> itemData) { + JsonObject children = Constants.MUSEUM.get("children").getAsJsonObject(); + if (savedItems.containsKey(name)) return; + savedItems.put(name, itemData); + if (children.has(name)) { + String childId = children.get(name).getAsString(); + String childName = childId; + JsonObject nameMappings = Constants.MUSEUM.get("armor_to_id").getAsJsonObject(); + if (nameMappings.has(childId)) { + childName = nameMappings.get(childId).getAsString(); + } + String displayName = NotEnoughUpdates.INSTANCE.manager.getDisplayName(childName); + ItemStack stack = Utils.createItemStack(Items.dye, displayName, 10, "Donated as higher tier"); + JsonObject item = profileViewer.getManager().getJsonForItem(stack); + item.add("internalname", new JsonPrimitive("_")); + JsonArray itemArray = new JsonArray(); + itemArray.add(item); + processItems(childId, itemArray); + + getDataAndChildren(childId, itemData); + } + } + + private MuseumData asLoading() { + museumValue = -1; + return this; + } + + public long getValue() { + return museumValue; + } + public Map<String, JsonArray> getWeaponItems() { + return weaponItems; + } + public Map<String, JsonArray> getArmorItems() { + return armorItems; + } + public Map<String, JsonArray> getRaritiesItems() { + return raritiesItems; + } + public List<JsonArray> getSpecialItems() { + return specialItems; + } + public Map<String, Pair<Long, Boolean>> getSavedItems() { + return savedItems; + } + } + + private void loadMuseumData() { + if (updatingMuseumData.get()) { + return; + } + + updatingMuseumData.set(true); + String profileId = getOuterProfileJson().get("profile_id").getAsString(); + profileViewer.getManager().apiUtils.newHypixelApiRequest("skyblock/museum") + .queryArgument("profile", profileId) + .requestJson() + .handle((museumJson, throwable) -> { + if (museumJson != null && museumJson.has("success") + && museumJson.get("success").getAsBoolean() && museumJson.has("members")) { + museumData = new MuseumData(museumJson); + return null; + } + return null; + }); + } public SkyblockProfile(JsonObject outerProfileJson) { this.outerProfileJson = outerProfileJson; @@ -986,5 +1163,14 @@ public class SkyblockProfiles { loadSoopyData(callback); return new SoopyNetworth(null).asLoading(); } + + public MuseumData getMuseumData() { + if (museumData != null) { + return museumData; + } + + loadMuseumData(); + return new MuseumData(null).asLoading(); + } } } 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 6819ccc4..5f1cc247 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/util/Constants.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/util/Constants.java @@ -82,6 +82,7 @@ public class Constants { public static JsonObject ABIPHONE; public static JsonObject ESSENCESHOPS; public static JsonObject SBLEVELS; + public static JsonObject MUSEUM; private static final ReentrantLock lock = new ReentrantLock(); @@ -107,6 +108,7 @@ public class Constants { ABIPHONE = Utils.getConstant("abiphone", gson); ESSENCESHOPS = Utils.getConstant("essenceshops", gson); SBLEVELS = Utils.getConstant("sblevels", gson); + MUSEUM = Utils.getConstant("museum", 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 54888935..7f607ab7 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java @@ -85,11 +85,16 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.text.DecimalFormat; import java.time.Duration; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; +import java.util.TimeZone; import java.util.UUID; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -2257,4 +2262,25 @@ public class Utils { slot, 0, 0, Minecraft.getMinecraft().thePlayer ); } + + public static String timeSinceMillisecond(long time) { + Instant lastSave = Instant.ofEpochMilli(time); + 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; + } } diff --git a/src/main/resources/assets/notenoughupdates/pv_inventories.png b/src/main/resources/assets/notenoughupdates/pv_inventories.png Binary files differnew file mode 100644 index 00000000..a4308e49 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/pv_inventories.png diff --git a/src/main/resources/assets/notenoughupdates/pv_museum.png b/src/main/resources/assets/notenoughupdates/pv_museum.png Binary files differnew file mode 100644 index 00000000..eb988155 --- /dev/null +++ b/src/main/resources/assets/notenoughupdates/pv_museum.png |