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