diff options
| author | CalMWolfs <94038482+CalMWolfs@users.noreply.github.com> | 2024-08-05 00:03:57 +1000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-08-04 16:03:57 +0200 |
| commit | 3ce20a6e3f644719c47358c422021f6e926a4b1b (patch) | |
| tree | d055fca1e23a57a7967349aa8c97085e150b0dfe | |
| parent | d2ea5ba43970e4beef98d6ba2b1bfb49ba73ab1d (diff) | |
| download | notenoughupdates-3ce20a6e3f644719c47358c422021f6e926a4b1b.tar.gz notenoughupdates-3ce20a6e3f644719c47358c422021f6e926a4b1b.tar.bz2 notenoughupdates-3ce20a6e3f644719c47358c422021f6e926a4b1b.zip | |
Add Garden Page in PV (#1263)
Co-authored-by: nopo <nopotheemail@gmail.com>
10 files changed, 669 insertions, 4 deletions
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java index 8c80c7b9..56ae4a1d 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java @@ -265,6 +265,9 @@ public class NotEnoughUpdates { if (config.profileViewer.pageLayout.size() == 12) { config.profileViewer.pageLayout.add(12); } + if (config.profileViewer.pageLayout.size() == 13) { + config.profileViewer.pageLayout.add(13); + } if ((config.apiData.repoUser.isEmpty() || config.apiData.repoName.isEmpty() || config.apiData.repoBranch.isEmpty()) && config.apiData.autoupdate_new) { config.apiData.repoUser = "NotEnoughUpdates"; diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/separatesections/ProfileViewer.java b/src/main/java/io/github/moulberry/notenoughupdates/options/separatesections/ProfileViewer.java index 08ddadf8..a511178b 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/options/separatesections/ProfileViewer.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/options/separatesections/ProfileViewer.java @@ -64,11 +64,12 @@ public class ProfileViewer { "\u00a7eBestiary", "\u00a7eCrimson Isle", "\u00a7eMuseum", - "\u00a7eRift" + "\u00a7eRift", + "\u00a7eGarden" }, allowDeleting = false ) - public List<Integer> pageLayout = new ArrayList<>(Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)); + public List<Integer> pageLayout = new ArrayList<>(Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13)); @Expose @ConfigOption( 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 c57fd729..2fbe948b 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java @@ -24,6 +24,7 @@ import io.github.moulberry.notenoughupdates.NotEnoughUpdates; import io.github.moulberry.notenoughupdates.core.util.StringUtils; import io.github.moulberry.notenoughupdates.cosmetics.ShaderManager; import io.github.moulberry.notenoughupdates.itemeditor.GuiElementTextField; +import io.github.moulberry.notenoughupdates.miscfeatures.profileviewer.GardenPage; import io.github.moulberry.notenoughupdates.miscfeatures.profileviewer.bestiary.BestiaryPage; import io.github.moulberry.notenoughupdates.profileviewer.rift.RiftPage; import io.github.moulberry.notenoughupdates.profileviewer.trophy.TrophyFishPage; @@ -220,6 +221,7 @@ public class GuiProfileViewer extends GuiScreen { pages.put(ProfileViewerPage.CRIMSON_ISLE, new CrimsonIslePage(this)); pages.put(ProfileViewerPage.MUSEUM, new MuseumPage(this)); pages.put(ProfileViewerPage.RIFT, new RiftPage(this)); + pages.put(ProfileViewerPage.GARDEN, new GardenPage(this)); } catch (Exception ex) { pages.put(ProfileViewerPage.CRASH_RECOVERY, new CrashRecoveryPage(this, ex, currentPage)); currentPage = ProfileViewerPage.CRASH_RECOVERY; @@ -1246,6 +1248,8 @@ public class GuiProfileViewer extends GuiScreen { return (level.totalXp / 1000000) * 100; } else if (skillName.equalsIgnoreCase("social")) { return (level.totalXp / 272800) * 100; + } else if (skillName.equalsIgnoreCase("garden")) { + return (level.totalXp / 60120) * 100; } else { if (level.maxLevel == 60) { return (level.totalXp / SkillsWeight.SKILLS_LEVEL_60) * 100; @@ -1292,7 +1296,8 @@ public class GuiProfileViewer extends GuiScreen { BESTIARY(9, Items.iron_sword, "§cBestiary"), CRIMSON_ISLE(10, Item.getItemFromBlock(Blocks.netherrack), "§4Crimson Isle"), MUSEUM(11, Items.leather_chestplate, "§6Museum"), - RIFT(12, Items.ender_eye, "§5Rift"); + RIFT(12, Items.ender_eye, "§5Rift"), + GARDEN(13, Item.getItemFromBlock(Blocks.grass), "§2Garden"); public final ItemStack stack; public final int id; diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/data/APIDataJson.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/data/APIDataJson.java index 7e534d33..a8400b0d 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/data/APIDataJson.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/data/APIDataJson.java @@ -28,7 +28,6 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Objects; import static io.github.moulberry.notenoughupdates.profileviewer.rift.RiftPage.readBase64; @@ -278,6 +277,7 @@ public class APIDataJson { public static class GardenPlayerData { public int larva_consumed = 0; + public int copper = 0; } public GlacitePlayerData glacite_player_data = new GlacitePlayerData(); 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 7b495c52..a2cd4bb0 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/util/Constants.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/util/Constants.java @@ -88,6 +88,7 @@ public class Constants { public static JsonObject HOPPITY; public static JsonObject DYES; public static JsonObject GEMSTONES; + public static JsonObject GARDEN; private static final ReentrantLock lock = new ReentrantLock(); @@ -119,6 +120,7 @@ public class Constants { HOPPITY = Utils.getConstant("hoppity", gson); DYES = Utils.getConstant("dyes", gson); GEMSTONES = Utils.getConstant("gemstones", gson); + GARDEN = Utils.getConstant("garden", 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 61a0deb1..5a2018ed 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java @@ -1121,6 +1121,10 @@ public class Utils { drawStringCenteredScaledMaxWidth(str, x, y + 4, false, maxLength, 421075); } + public static void renderShadowedString(String str, int x, int y, int maxLength) { + renderShadowedString(str, (float) x, (float) y, maxLength); + } + public static void renderAlignedString(String first, String second, float x, float y, int length) { FontRenderer fontRendererObj = Minecraft.getMinecraft().fontRendererObj; if (fontRendererObj.getStringWidth(first + " " + second) >= length) { diff --git a/src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/profileviewer/GardenDataJson.kt b/src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/profileviewer/GardenDataJson.kt new file mode 100644 index 00000000..54212ca0 --- /dev/null +++ b/src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/profileviewer/GardenDataJson.kt @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2024 NotEnoughUpdates contributors + * + * This file is part of NotEnoughUpdates. + * + * NotEnoughUpdates is free software: you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * NotEnoughUpdates is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>. + */ + +package io.github.moulberry.notenoughupdates.miscfeatures.profileviewer + +import com.google.gson.annotations.SerializedName + +data class GardenDataJson( + val success: Boolean, + val garden: GardenData, +) + +data class GardenData( + @SerializedName("unlocked_plots_ids") val unlockedPlotIds: List<String>, + @SerializedName("commission_data") val commissionData: VisitorCommissions, + @SerializedName("resources_collected") val resourcesCollected: Map<CropType, Long>, + @SerializedName("garden_experience") val gardenExperience: Int, + @SerializedName("composter_data") val composterData: ComposterData, + @SerializedName("selected_barn_skin") val selectedBarnSkin: String, + @SerializedName("crop_upgrade_levels") val cropUpgradeLevels: Map<CropType, Int>, +) + +data class VisitorCommissions( + val visits: Map<String, Int>, + val completed: Map<String, Int>, + @SerializedName("total_completed") val totalCompleted: Int, + @SerializedName("unique_npcs_served") val uniqueNpcsServed: Int, +) + +data class ComposterData( + val upgrades: APIComposterUpgrades, +) + +data class APIComposterUpgrades( + val speed: Int, + @SerializedName("multi_drop") val multiDrop: Int, + @SerializedName("fuel_cap") val fuelCap: Int, + @SerializedName("organic_matter_cap") val organicMatterCap: Int, + @SerializedName("cost_reduction") val costReduction: Int, +) + +data class ComposterUpgrade( + val upgrade: Int, + val items: Map<String, Int>, + val copper: Int, +) + +data class GardenRepoJson( + @SerializedName("garden_exp") val gardenExperience: List<Int>, + @SerializedName("crop_milestones") val cropMilestones: Map<CropType, List<Int>>, + @SerializedName("visitors") val visitors: Map<String, VisitorRarity>, + val plots: Map<String, PlotData>, + @SerializedName("plot_costs") val plotCosts: Map<String, List<PlotCost>>, + @SerializedName("barn") val barn: Map<String, BarnSkin>, + @SerializedName("crop_upgrades") val cropUpgrades: List<Int>, + @SerializedName("composter_upgrades") val composterUpgrades: Map<String, Map<Int, ComposterUpgrade>>, + @SerializedName("composter_tooltips") val composterTooltips: Map<String, String>, +) + +data class PlotData( + val name: String, + val x: Int, + val y: Int, +) + +data class PlotCost( + val item: String, + val amount: Int, +) + +data class BarnSkin( + val name: String, + val item: String, +) + +data class EliteWeightJson( + val totalWeight: Double, + val cropWeight: Map<CropType, Double>, + val bonusWeight: Map<String, Double>, +) + +enum class CropType(val itemId: String, val apiName: String, val displayName: String) { + WHEAT("ENCHANTED_HAY_BLOCK", "WHEAT", "Wheat"), + NETHER_WART("ENCHANTED_NETHER_STALK", "NETHER_STALK", "Nether Wart"), + SUGAR_CANE("ENCHANTED_SUGAR", "SUGAR_CANE", "Sugar Cane"), + CARROT("ENCHANTED_CARROT", "CARROT_ITEM", "Carrot"), + POTATO("ENCHANTED_POTATO", "POTATO_ITEM", "Potato"), + COCOA_BEANS("ENCHANTED_COCOA", "INK_SACK:3", "Cocoa Beans"), + PUMPKIN("ENCHANTED_PUMPKIN", "PUMPKIN", "Pumpkin"), + MELON("ENCHANTED_MELON", "MELON", "Melon"), + CACTUS("ENCHANTED_CACTUS_GREEN", "CACTUS", "Cactus"), + MUSHROOM("ENCHANTED_BROWN_MUSHROOM", "MUSHROOM_COLLECTION", "Mushroom"), + ; + + companion object { + fun fromApiName(apiName: String): CropType? { + val fixedInput = apiName.uppercase().replace(" ", "_") + val fromApiName = values().firstOrNull { it.apiName == fixedInput } + if (fromApiName != null) return fromApiName + return values().firstOrNull { it.name == fixedInput } + } + } +} + +enum class VisitorRarity(val displayName: String) { + UNCOMMON("§aUncommon"), + RARE("§9Rare"), + LEGENDARY("§6Legendary"), + MYTHIC("§dMythic"), + SPECIAL("§cSpecial"), + TOTAL("§7Total"), + ; +} diff --git a/src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/profileviewer/GardenPage.kt b/src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/profileviewer/GardenPage.kt new file mode 100644 index 00000000..fea818bd --- /dev/null +++ b/src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/profileviewer/GardenPage.kt @@ -0,0 +1,517 @@ +/* + * Copyright (C) 2024 NotEnoughUpdates contributors + * + * This file is part of NotEnoughUpdates. + * + * NotEnoughUpdates is free software: you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * NotEnoughUpdates is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>. + */ + +package io.github.moulberry.notenoughupdates.miscfeatures.profileviewer + +import com.google.gson.Gson +import com.google.gson.GsonBuilder +import com.google.gson.JsonArray +import com.google.gson.TypeAdapter +import com.google.gson.stream.JsonReader +import com.google.gson.stream.JsonWriter +import io.github.moulberry.notenoughupdates.NotEnoughUpdates +import io.github.moulberry.notenoughupdates.core.util.StringUtils +import io.github.moulberry.notenoughupdates.profileviewer.GuiProfileViewer +import io.github.moulberry.notenoughupdates.profileviewer.GuiProfileViewerPage +import io.github.moulberry.notenoughupdates.profileviewer.ProfileViewer.Level +import io.github.moulberry.notenoughupdates.profileviewer.ProfileViewerUtils +import io.github.moulberry.notenoughupdates.profileviewer.SkyblockProfiles +import io.github.moulberry.notenoughupdates.profileviewer.data.APIDataJson +import io.github.moulberry.notenoughupdates.util.Constants +import io.github.moulberry.notenoughupdates.util.MC +import io.github.moulberry.notenoughupdates.util.UrsaClient +import io.github.moulberry.notenoughupdates.util.Utils +import io.github.moulberry.notenoughupdates.util.kotlin.Coroutines +import net.minecraft.client.Minecraft +import net.minecraft.client.renderer.GlStateManager +import net.minecraft.init.Blocks +import net.minecraft.item.ItemStack +import net.minecraft.util.ResourceLocation +import org.lwjgl.opengl.GL11 + +class GardenPage(pvInstance: GuiProfileViewer) : GuiProfileViewerPage(pvInstance) { + private val manager get() = NotEnoughUpdates.INSTANCE.manager + + private var guiLeft = GuiProfileViewer.getGuiLeft() + private var guiTop = GuiProfileViewer.getGuiTop() + + private var currentProfile: SkyblockProfiles.SkyblockProfile? = null + private var gardenData: GardenData? = null + private var eliteData: EliteWeightJson? = null + private var currentlyFetching = false + private lateinit var repoData: GardenRepoJson + private var apiData: APIDataJson? = null + + private var mouseX: Int = 0 + private var mouseY: Int = 0 + + private val visitorRarityToVisits: MutableMap<VisitorRarity, Int> = mutableMapOf() + private val visitorRarityToCompleted: MutableMap<VisitorRarity, Int> = mutableMapOf() + + val background: ResourceLocation = ResourceLocation("notenoughupdates:profile_viewer/garden/background.png") + + companion object { + private val cropTypeAdapter = object : TypeAdapter<CropType>() { + override fun write(writer: JsonWriter, value: CropType) { + writer.value(value.name) + } + + override fun read(reader: JsonReader): CropType? { + return CropType.fromApiName(reader.nextString()) + } + } + + val gson: Gson = + GsonBuilder().setPrettyPrinting().registerTypeAdapter(CropType::class.java, cropTypeAdapter.nullSafe()) + .create() + } + + override fun drawPage(mouseX: Int, mouseY: Int, partialTicks: Float) { + guiLeft = GuiProfileViewer.getGuiLeft() + guiTop = GuiProfileViewer.getGuiTop() + + this.mouseX = mouseX + this.mouseY = mouseY + + if (currentlyFetching) { + Utils.drawStringCentered("§eLoading Data", guiLeft + 220, guiTop + 101, true, 0) + return + } + + if (Constants.GARDEN == null) { + Utils.drawStringCentered("§cMissing Repo Data", guiLeft + 220, guiTop + 101, true, 0) + Utils.showOutdatedRepoNotification("garden.json") + return + } + + val newProfile = selectedProfile + if (newProfile != currentProfile) { + getData() + currentProfile = selectedProfile + return + } + + if (gardenData == null || gardenData?.gardenExperience == 0) { + Utils.drawStringCentered("§cMissing Profile Data", guiLeft + 220, guiTop + 101, true, 0) + return + } + val selectedProfile = GuiProfileViewer.getSelectedProfile() ?: return + apiData = selectedProfile.APIDataJson ?: return + + MC.textureManager.bindTexture(background) + Utils.drawTexturedRect( + guiLeft.toFloat(), + guiTop.toFloat(), + instance.sizeX.toFloat(), + instance.sizeY.toFloat(), + GL11.GL_NEAREST + ) + + renderPlots() + renderGardenLevel() + renderFarmingWeight() + renderCropUpgrades() + renderCropMilestones() + renderVisitorStats() + renderCompost() + } + + private fun getData() { + currentlyFetching = true + val profileId = selectedProfile?.outerProfileJson?.get("profile_id")?.asString?.replace("-", "") + Coroutines.launchCoroutine { + gardenData = loadGardenData(profileId) + getVisitorData() + currentlyFetching = false + } + Coroutines.launchCoroutine { + eliteData = loadFarmingWeight(GuiProfileViewer.getProfile()?.uuid, profileId) + } + } + + private fun loadGardenData(profileId: String?): GardenData? { + profileId ?: return null + val data = manager.ursaClient.get(UrsaClient.gardenForProfile(profileId)).get() + repoData = gson.fromJson(Constants.GARDEN, GardenRepoJson::class.java) + return gson.fromJson(data, GardenDataJson::class.java).garden + } + + private fun getVisitorData() { + for ((visitor, amount) in gardenData?.commissionData?.visits ?: return) { + val rarity = repoData.visitors[visitor] + if (rarity == null) { + println("Unknown visitor: $visitor") + continue + } + visitorRarityToVisits[rarity] = visitorRarityToVisits.getOrDefault(rarity, 0) + amount + } + for ((visitor, amount) in gardenData?.commissionData?.completed ?: return) { + val rarity = repoData.visitors[visitor] ?: continue + visitorRarityToCompleted[rarity] = visitorRarityToCompleted.getOrDefault(rarity, 0) + amount + } + } + + private fun loadFarmingWeight(uuid: String?, profileId: String?): EliteWeightJson? { + uuid ?: return null + profileId ?: return null + val data = manager.apiUtils.request() + .url("https://api.elitebot.dev/weight/$uuid/$profileId") + .requestJson().get() + return gson.fromJson(data, EliteWeightJson::class.java) + } + + private fun renderPlots() { + val top = guiTop + 79 + val left = guiLeft + 192 + GlStateManager.color(1f, 1f, 1f, 1f) + for (value in repoData.plots) { + Minecraft.getMinecraft().textureManager.bindTexture(GuiProfileViewer.pv_elements) + val x = left + value.value.x * 22 + val y = top + value.value.y * 22 + Utils.drawTexturedRect( + x.toFloat(), + y.toFloat(), + 20f, + 20f, + 0f, + 20 / 256f, + 0f, + 20 / 256f, + GL11.GL_NEAREST + ) + if (gardenData?.unlockedPlotIds?.contains(value.key) != true) { + Utils.drawItemStack(ItemStack(Blocks.barrier), x + 2, y + 2) + if (mouseX >= x && mouseX <= x + 20 && mouseY >= y && mouseY <= y + 20) { + instance.tooltipToDisplay = listOf("§cLocked " + value.value.name) + } + continue + } + Utils.drawItemStack(ItemStack(Blocks.grass), x + 2, y + 2) + if (mouseX >= x && mouseX <= x + 20 && mouseY >= y && mouseY <= y + 20) { + instance.tooltipToDisplay = listOf(value.value.name) + } + } + + Minecraft.getMinecraft().textureManager.bindTexture(GuiProfileViewer.pv_elements) + Utils.drawTexturedRect( + (left + 2 * 22).toFloat(), + (top + 2 * 22).toFloat(), + 20f, + 20f, + 0f, + 20 / 256f, + 0f, + 20 / 256f, + GL11.GL_NEAREST + ) + val x = left + 2 * 22 + 2 + val y = top + 2 * 22 + 2 + var error = true + repoData.barn[gardenData?.selectedBarnSkin]?.let { + val itemStack = NotEnoughUpdates.INSTANCE.manager.createItemResolutionQuery().withKnownInternalName(it.item) + .resolveToItemStack() + Utils.drawItemStack(itemStack, x, y) + if (mouseX >= x && mouseX <= x + 20 && mouseY >= y && mouseY <= y + 20) { + instance.tooltipToDisplay = + listOf("§7Barn Skin: ${it.name}") + } + error = false + } + if (error) { + Utils.drawItemStack(ItemStack(Blocks.barrier), x, y) + if (mouseX >= x && mouseX <= x + 20 && mouseY >= y && mouseY <= y + 20) { + instance.tooltipToDisplay = listOf( + "§cUnknown barn Skin: ${gardenData?.selectedBarnSkin}", + "§cIf you expected it to be there please send a message in", + "§c§l#neu-support §r§con §ldiscord.gg/moulberry" + ) + } + } + + } + + private fun renderCropUpgrades() { + val startHeight = guiTop + 105 + var yPos = startHeight + var xPos = guiLeft + 26 + + Utils.renderShadowedString("§eCrop Upgrades", xPos + 70, yPos + 5, 105) + + for ((index, crop) in CropType.values().withIndex()) { + if (index == 5) { + yPos = startHeight + xPos += 70 + } + yPos += 14 + + val upgradeLevel = gardenData?.cropUpgradeLevels?.get(crop) ?: 0 + + val itemStack = manager.createItem(crop.itemId) + Utils.drawItemStack(itemStack, xPos + 2, yPos) + Utils.renderAlignedString( + "§e${crop.displayName}", + "§f$upgradeLevel", + (xPos + 20).toFloat(), + (yPos + 5).toFloat(), + 50 + ) + + if (mouseX >= xPos + 20 && mouseX <= xPos + 70 && mouseY >= yPos && mouseY <= yPos + 20) { + val tooltip = ArrayList<String>() + tooltip.add("§7${crop.displayName} Fortune: §6+${upgradeLevel*5}☘") + if (repoData.cropUpgrades.size == upgradeLevel) { + tooltip.add("§6Maxed") + } else { + tooltip.add("§7${repoData.cropUpgrades[upgradeLevel]} §cCopper To Upgrade") + val totalCopper = repoData.cropUpgrades.sum() + val sum = totalCopper - repoData.cropUpgrades.subList(0, upgradeLevel).sum() + tooltip.add("§7$sum §cCopper Until Max") + } + instance.tooltipToDisplay = tooltip + } + } + } + + private fun renderCropMilestones() { + val startHeight = guiTop + 10 + var yPos = startHeight + var xPos = guiLeft + 26 + + Utils.renderShadowedString("§eCrop Milestones", xPos + 70, yPos + 5, 105) + + for ((index, crop) in CropType.values().withIndex()) { + if (index == 5) { + yPos = startHeight + xPos += 70 + } + yPos += 14 + + val itemStack = manager.createItem(crop.itemId) + Utils.drawItemStack(itemStack, xPos + 2, yPos) + val levelsInfo = repoData.cropMilestones[crop] ?: continue + val currentCollection = gardenData?.resourcesCollected?.get(crop) ?: 0 + val levelInfo = getLevel(levelsInfo, currentCollection) + val collectionLevel = levelInfo.level.toInt() + val formattedAmount = StringUtils.formatNumber(currentCollection.toDouble()) + var nextLevel = 0 + var nextLevelString = "§6MAXED" + var maxLevel = 0 + var maxLevelString = "" + if (!levelInfo.maxed) { + for (i in 0..45) { + maxLevel += levelsInfo[i] + if (i < (levelInfo.level.toInt() + 1)) nextLevel += levelsInfo[i] + } + maxLevelString = StringUtils.formatNumber(maxLevel) + nextLevelString = "§f$formattedAmount§7/§f${StringUtils.formatNumber(nextLevel)} §7Until Next §eMilestone" + } + val tooltip = ArrayList<String>() + tooltip.add("§7Farmed: §f$formattedAmount") + tooltip.add(nextLevelString) + if (!levelInfo.maxed) { + tooltip.add("§f$formattedAmount§7/§f$maxLevelString §7Until §6Max §eMilestone") + } + drawAlignedStringWithHover( + "§e${crop.displayName}", + "§f$collectionLevel", + xPos + 20, + yPos + 5, + 50, + tooltip + ) + } + } + + private fun renderVisitorStats() { + val xPos = guiLeft + 322 + var yPos = guiTop + 20 + + Utils.renderShadowedString("§eVisitors", xPos + 40, yPos - 3, 80) + + // todo progress bar! + Utils.renderAlignedString( + "§eUnique Visitors", + "§f${gardenData?.commissionData?.uniqueNpcsServed ?: 0}/${repoData.visitors.size}", + xPos.toFloat(), + (yPos + 10).toFloat(), + 80 + ) + yPos += 20 + + for (rarity in VisitorRarity.values()) { + val formattedVisits = StringUtils.formatNumber(visitorRarityToVisits.getOrDefault(rarity, 0)) + val formattedCompleted = StringUtils.formatNumber(visitorRarityToCompleted.getOrDefault(rarity, 0)) + val tooltip = listOf( + "§7Visits: §f$formattedVisits", + "§7Completed: §f$formattedCompleted", + ) + val rarityStats = "§f$formattedCompleted/$formattedVisits" + drawAlignedStringWithHover(rarity.displayName, rarityStats, xPos, yPos, 80, tooltip) + yPos += 12 + } + } + + private fun renderGardenLevel() { + val top = guiTop + 20 + val left = guiLeft + 190 + val level = getLevel(repoData.gardenExperience, gardenData?.gardenExperience?.toLong()) + if (level.maxed) { + instance.renderGoldBar((left).toFloat(), (top + 10).toFloat(), 80f) + } else { + instance.renderBar(left.toFloat(), (top + 10).toFloat(), 80f, level.level % 1) + } + + val maxXp = level.maxXpForLevel.toInt() + val totalXpS = StringUtils.formatNumber(level.totalXp.toLong()) + val gardenTooltip = ArrayList<String>() + gardenTooltip.add("§2Garden") + if (level.maxed) { + gardenTooltip.add("§7Progress: §6MAXED!") + } else { + gardenTooltip.add( + "§7Progress: §5" + + StringUtils.shortNumberFormat(Math.round((level.level % 1) * maxXp)) + + "/" + + StringUtils.shortNumberFormat(maxXp) + ) + } + gardenTooltip.add( + "§7Total XP: §5${totalXpS}§8 (" + + StringUtils.formatToTenths(instance.getPercentage("garden", level)) + + "% to ${level.maxLevel})" + ) + drawAlignedStringWithHover("§2Garden", "§f${level.level.toInt()}", left + 20, top, 60, gardenTooltip) + Utils.drawItemStack(ItemStack(Blocks.grass), left, top - 6) + + val copper = apiData?.garden_player_data?.copper ?: 0 + Utils.renderAlignedString( + "§cCopper:", + "§f" + StringUtils.formatNumber(copper), + (left).toFloat(), + (top + 20).toFloat(), + 80 + ) + } + + private fun renderFarmingWeight() { + val top = guiTop + 51 + val left = guiLeft + 190 + + if (eliteData == null) { + drawAlignedStringWithHover("§eFarming Weight", "§eLoading...", left, top, 100, listOf("§eLoading...", "§eTry again soon!")) + return + } + + val totalWeight = eliteData?.totalWeight ?: 0.0 + val bonusWeight = eliteData?.bonusWeight?.values?.sum() ?: 0.0 + + val tooltip = buildList{ + add("§7Total Weight: §f${StringUtils.formatNumber(totalWeight)}") + add("§7Bonus Weight: §f${StringUtils.formatNumber(bonusWeight)}") + + for (crop in CropType.values()) { + val cropWeight = eliteData?.cropWeight?.get(crop) ?: 0.0 + add("§7${crop.displayName}: §f${StringUtils.formatNumber(cropWeight)}") + } + } + + drawAlignedStringWithHover("§eFarming Weight", "§f${StringUtils.formatNumber(totalWeight)}", left, top, 100, tooltip) + } + + private fun renderCompost() { + val xPos = guiLeft + 322 + var yPos = guiTop + 118 + + Utils.renderShadowedString("§eCompost Upgrades", xPos + 40, yPos, 80) + yPos += 12 + + val (speed, multiDrop, fuelCap, organicMatterCap, costReduction) = gardenData?.composterData?.upgrades ?: return + for (i in 0..4) { + val upgradeName = when (i) { + 0 -> "§aSpeed" + 1 -> "§aMulti Drop" + 2 -> "§aFuel Cap" + 3 -> "§aOrganic Matter Cap" + 4 -> "§aCost Reduction" + else -> 0 + } + val upgradeAmount = when (i) { + 0 -> speed + 1 -> multiDrop + 2 -> fuelCap + 3 -> organicMatterCap + 4 -> costReduction + else -> 0 + } + val repoName = when (i) { + 0 -> "speed" + 1 -> "multi_drop" + 2 -> "fuel_cap" + 3 -> "organic_matter_cap" + 4 -> "cost_reduction" + else -> 0 + } + val tooltip = ArrayList<String>() + val upgradeValues = repoData.composterUpgrades[repoName]?.get(upgradeAmount + 1) + val upgradeValuesCurrent = repoData.composterUpgrades[repoName]?.get(upgradeAmount)?.upgrade ?: 0 + val upgradeValuesCurrentSt = StringUtils.formatNumber(upgradeValuesCurrent) + if (upgradeValues != null) { + repoData.composterTooltips[repoName]?.replace("{}", "$upgradeValuesCurrentSt -> ${StringUtils.formatNumber(upgradeValues.upgrade)}") + ?.let { tooltip.add(it) } + for (item in upgradeValues.items) { + val itemStack = manager.createItem(item.key.uppercase()) + if (itemStack == null) { + println("Item not found: ${item.key}") + tooltip.add("§cUnknown Item: ${item.key}") + } else { + tooltip.add("§7${item.value}x ${itemStack.displayName}") + } + } + tooltip.add("§7${upgradeValues.copper} §cCopper") + } else { + repoData.composterTooltips[repoName]?.replace("{}", upgradeValuesCurrentSt) + ?.let { tooltip.add(it) } + tooltip.add("§6Maxed") + } + + drawAlignedStringWithHover("§e$upgradeName", "§f$upgradeAmount", xPos, yPos, 80, tooltip) + yPos += 12 + } + } + + private fun getLevel(experienceList: List<Int>, currentExp: Long?): Level { + val array = JsonArray() + experienceList.forEach { array.add(gson.toJsonTree(it)) } + return ProfileViewerUtils.getLevel(array, (currentExp ?: 0).toFloat(), experienceList.size, false) + } + + private fun drawAlignedStringWithHover( + first: String, + second: String, + x: Int, + y: Int, + length: Int, + hover: List<String>, + ) { + Utils.renderAlignedString(first, second, x.toFloat(), y.toFloat(), length) + if (mouseX in x..(x + length) && mouseY in y..(y + 13)) { + instance.tooltipToDisplay = hover + } + } +} diff --git a/src/main/kotlin/io/github/moulberry/notenoughupdates/util/UrsaClient.kt b/src/main/kotlin/io/github/moulberry/notenoughupdates/util/UrsaClient.kt index 4a6bc0e1..c2b94be2 100644 --- a/src/main/kotlin/io/github/moulberry/notenoughupdates/util/UrsaClient.kt +++ b/src/main/kotlin/io/github/moulberry/notenoughupdates/util/UrsaClient.kt @@ -226,6 +226,10 @@ class UrsaClient(val apiUtil: ApiUtil) { KnownRequest("v1/hypixel/v2/museum/${profileUuid}", JsonObject::class.java) @JvmStatic + fun gardenForProfile(profileUuid: String) = + KnownRequest("v1/hypixel/v2/garden/${profileUuid}", JsonObject::class.java) + + @JvmStatic fun status(uuid: UUID) = KnownRequest("v1/hypixel/v2/status/${uuid}", JsonObject::class.java) } |
