aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCalMWolfs <94038482+CalMWolfs@users.noreply.github.com>2024-08-05 00:03:57 +1000
committerGitHub <noreply@github.com>2024-08-04 16:03:57 +0200
commit3ce20a6e3f644719c47358c422021f6e926a4b1b (patch)
treed055fca1e23a57a7967349aa8c97085e150b0dfe
parentd2ea5ba43970e4beef98d6ba2b1bfb49ba73ab1d (diff)
downloadnotenoughupdates-3ce20a6e3f644719c47358c422021f6e926a4b1b.tar.gz
notenoughupdates-3ce20a6e3f644719c47358c422021f6e926a4b1b.tar.bz2
notenoughupdates-3ce20a6e3f644719c47358c422021f6e926a4b1b.zip
Add Garden Page in PV (#1263)
Co-authored-by: nopo <nopotheemail@gmail.com>
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java3
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/separatesections/ProfileViewer.java5
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java7
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/data/APIDataJson.java2
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/Constants.java2
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java4
-rw-r--r--src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/profileviewer/GardenDataJson.kt129
-rw-r--r--src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/profileviewer/GardenPage.kt517
-rw-r--r--src/main/kotlin/io/github/moulberry/notenoughupdates/util/UrsaClient.kt4
-rw-r--r--src/main/resources/assets/notenoughupdates/profile_viewer/garden/background.pngbin0 -> 5505 bytes
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)
}