diff options
10 files changed, 220 insertions, 15 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.java b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.java index 48d49ec87..055c645f7 100644 --- a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.java +++ b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.java @@ -133,6 +133,7 @@ public class SkyHanniMod { loadModule(new ToolTipData()); loadModule(new GuiEditManager()); loadModule(UpdateManager.INSTANCE); + loadModule(new CropAccessoryData()); // APIs loadModule(new BazaarApi()); diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/Bazaar.java b/src/main/java/at/hannibal2/skyhanni/config/features/Bazaar.java index 48d32fc15..e988c7b67 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/Bazaar.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/Bazaar.java @@ -18,7 +18,7 @@ public class Bazaar { public boolean bestSellMethod = false; @Expose - public Position bestSellMethodPos = new Position(10, 10, false, true); + public Position bestSellMethodPos = new Position(394, 142, false, true); @Expose @ConfigOption(name = "Cancelled Buy Order Clipboard", desc = "Saves missing items from cancelled buy orders to clipboard for faster re-entry.") diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/Garden.java b/src/main/java/at/hannibal2/skyhanni/config/features/Garden.java index 45189cec8..4a2ac82a2 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/Garden.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/Garden.java @@ -772,6 +772,16 @@ public class Garden { public boolean farmingFortuneDisplay = true; @Expose + @ConfigOption( + name = "Show As Drop Multiplier", + desc = "Adds 100 to the displayed farming fortune so that it represents a drop multiplier rather than" + + " the chance for bonus drops. " + ) + @ConfigEditorBoolean + @ConfigAccordionId(id = 18) + public boolean farmingFortuneDropMultiplier = false; + + @Expose public Position farmingFortunePos = new Position(-375, -200, false, true); @Expose diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/Hidden.java b/src/main/java/at/hannibal2/skyhanni/config/features/Hidden.java index 1aa26dd72..59133d122 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/Hidden.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/Hidden.java @@ -1,5 +1,6 @@ package at.hannibal2.skyhanni.config.features; +import at.hannibal2.skyhanni.features.garden.CropAccessory; import at.hannibal2.skyhanni.features.garden.CropType; import com.google.gson.annotations.Expose; @@ -47,6 +48,9 @@ public class Hidden { public int gardenExp = -1; @Expose + public CropAccessory savedCropAccessory = null; + + @Expose public Map<String, Integer> gardenDicerRngDrops = new HashMap<>(); @Expose diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/Misc.java b/src/main/java/at/hannibal2/skyhanni/config/features/Misc.java index 8b9ea625a..7808e0df7 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/Misc.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/Misc.java @@ -276,4 +276,7 @@ public class Misc { @ConfigOption(name = "Config Button", desc = "Add a button to the pause menu to configure SkyHanni.") @ConfigEditorBoolean public boolean configButtonOnPause = true; + + @Expose + public Position inventoryLoadPos = new Position(394, 124, false, true); } diff --git a/src/main/java/at/hannibal2/skyhanni/data/CropAccessoryData.kt b/src/main/java/at/hannibal2/skyhanni/data/CropAccessoryData.kt new file mode 100644 index 000000000..ea50257c3 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/CropAccessoryData.kt @@ -0,0 +1,124 @@ +package at.hannibal2.skyhanni.data + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.events.GuiContainerEvent +import at.hannibal2.skyhanni.events.InventoryOpenEvent +import at.hannibal2.skyhanni.events.ProfileApiDataLoadedEvent +import at.hannibal2.skyhanni.events.ProfileJoinEvent +import at.hannibal2.skyhanni.features.garden.CropAccessory +import at.hannibal2.skyhanni.utils.InventoryUtils +import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.NEUItems +import com.google.gson.JsonElement +import net.minecraft.item.ItemStack +import net.minecraft.nbt.CompressedStreamTools +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import net.minecraftforge.fml.common.gameevent.TickEvent +import java.io.ByteArrayInputStream +import java.util.* + +class CropAccessoryData { + private val accessoryBagNamePattern = "Accessory Bag \\((\\d)/(\\d)\\)".toRegex() + private var loadedAccessoryThisProfile = false + private var ticks = 0 + private var accessoryInBag: CropAccessory? = null + private var accessoryInInventory = CropAccessory.NONE + + private var accessoryBagPageNumber = 0 + + // Handle API detection + @SubscribeEvent + fun onProfileJoin(event: ProfileJoinEvent) { + loadedAccessoryThisProfile = false + } + + @SubscribeEvent + fun onProfileDataLoad(event: ProfileApiDataLoadedEvent) { + if (loadedAccessoryThisProfile) return + val inventoryData = event.profileData["inv_contents"] ?: return + val accessories = getCropAccessories(event.profileData["talisman_bag"]).also { + it.addAll(getCropAccessories(inventoryData)) + } + cropAccessory = accessories.maxOrNull() ?: CropAccessory.NONE + loadedAccessoryThisProfile = true + } + + // Handle accessory bag detection + @SubscribeEvent + fun onGuiDraw(event: InventoryOpenEvent) { + val groups = accessoryBagNamePattern.matchEntire(event.inventoryName)?.groups ?: return + accessoryBagPageCount = groups[2]!!.value.toInt() + accessoryBagPageNumber = groups[1]!!.value.toInt() + isLoadingAccessories = true + + val bestCropAccessoryPage = bestCropAccessory(event.inventoryItems.values) + accessoryPage[accessoryBagPageNumber] = bestCropAccessoryPage + if (accessoryBagPageCount == accessoryPage.size) { + accessoryInBag = accessoryPage.values.max().also { + cropAccessory = maxOf(it, accessoryInInventory) + } + loadedAccessoryThisProfile = true + } + } + + @SubscribeEvent + fun onCloseWindow(event: GuiContainerEvent.CloseWindowEvent) { + isLoadingAccessories = false + } + + // Handle inventory detection + @SubscribeEvent + fun onTick(event: TickEvent.ClientTickEvent) { + if (event.phase != TickEvent.Phase.START || ticks++ % 20 != 0) return + if (!LorenzUtils.inSkyBlock) return + accessoryInInventory = bestCropAccessory(InventoryUtils.getItemsInOwnInventory()) + if (accessoryInInventory == CropAccessory.NONE) return + if (accessoryInInventory > (accessoryInBag ?: CropAccessory.NONE)) { + cropAccessory = accessoryInInventory + } + } + + + private fun bestCropAccessory(items: Iterable<ItemStack>): CropAccessory { + return items.mapNotNull { item -> CropAccessory.getByName(item.getInternalName()) } + .maxOrNull() ?: CropAccessory.NONE + } + + companion object { + var accessoryBagPageCount = 0 + private set + + private var accessoryPage = mutableMapOf<Int, CropAccessory>() + + var isLoadingAccessories = false + private set + + val pagesLoaded get() = accessoryPage.size + + var cropAccessory: CropAccessory? + get() = SkyHanniMod.feature.hidden.savedCropAccessory + private set(accessory) { + SkyHanniMod.feature.hidden.savedCropAccessory = accessory + } + + // Derived partially from NotEnoughUpdates/NotEnoughUpdates, ProfileViewer.Profile#getInventoryInfo + private fun getCropAccessories(inventory: JsonElement?): MutableList<CropAccessory> { + if (inventory == null) return mutableListOf() + val cropAccessories = mutableListOf<CropAccessory>() + val data = inventory.asJsonObject["data"]?.asString + val accessoryBagItems = CompressedStreamTools.readCompressed( + ByteArrayInputStream(Base64.getDecoder().decode(data)) + ).getTagList("i", 10) + for (j in 0 until accessoryBagItems.tagCount()) { + val itemStackTag = accessoryBagItems.getCompoundTagAt(j) + if (!itemStackTag.hasKey("tag")) continue + val itemTag = itemStackTag.getCompoundTag("tag") + val itemName = NEUItems.getInternalNameOrNull(itemTag) ?: continue + val itemAsCropAccessory = CropAccessory.getByName(itemName) ?: continue + cropAccessories.add(itemAsCropAccessory) + } + return cropAccessories + } + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/CropAccessory.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/CropAccessory.kt new file mode 100644 index 000000000..441453ded --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/CropAccessory.kt @@ -0,0 +1,21 @@ +package at.hannibal2.skyhanni.features.garden + +enum class CropAccessory(val internalName: String, private val affectedCrops: Set<CropType>, private val fortune: Double) { + NONE("NONE", emptySet(), 0.0), + CROPIE("CROPIE_TALISMAN", setOf(CropType.WHEAT, CropType.POTATO, CropType.CARROT), 10.0), + SQUASH( + "SQUASH_RING", + setOf(CropType.WHEAT, CropType.POTATO, CropType.CARROT, CropType.COCOA_BEANS, CropType.MELON, CropType.PUMPKIN), + 20.0 + ), + FERMENTO("FERMENTO_ARTIFACT", CropType.values().toSet(), 30.0), + ; + + fun getFortune(cropType: CropType): Double { + return if (this.affectedCrops.contains(cropType)) this.fortune else 0.0 + } + + companion object { + fun getByName(internalName: String) = values().firstOrNull { it.internalName == internalName } + } +}
\ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/FarmingFortuneDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/FarmingFortuneDisplay.kt index a838eecc5..60d70e691 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/FarmingFortuneDisplay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/FarmingFortuneDisplay.kt @@ -1,6 +1,7 @@ package at.hannibal2.skyhanni.features.garden import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.data.CropAccessoryData import at.hannibal2.skyhanni.data.GardenCropMilestones import at.hannibal2.skyhanni.data.GardenCropMilestones.Companion.getCounter import at.hannibal2.skyhanni.data.GardenCropUpgrades.Companion.getUpgradeLevel @@ -12,7 +13,9 @@ import at.hannibal2.skyhanni.features.garden.GardenAPI.Companion.getCropType import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName import at.hannibal2.skyhanni.utils.ItemUtils.getLore import at.hannibal2.skyhanni.utils.LorenzUtils -import at.hannibal2.skyhanni.utils.RenderUtils.renderSingleLineWithItems +import at.hannibal2.skyhanni.utils.LorenzUtils.addAsSingletonList +import at.hannibal2.skyhanni.utils.RenderUtils.renderString +import at.hannibal2.skyhanni.utils.RenderUtils.renderStringsAndItems import at.hannibal2.skyhanni.utils.SkyBlockItemModifierUtils.getEnchantments import at.hannibal2.skyhanni.utils.SkyBlockItemModifierUtils.getHoeCounter import net.minecraft.item.ItemStack @@ -27,12 +30,18 @@ class FarmingFortuneDisplay { private val tabFortunePattern = " Farming Fortune: §r§6☘(\\d+)".toRegex() - private var display = listOf<Any>() + private var display = listOf<List<Any>>() + private var accessoryProgressDisplay = "" private var currentCrop: CropType? = null private var tabFortune: Double = 0.0 private var toolFortune: Double = 0.0 + private val baseFortune: Double get() = if (config.farmingFortuneDropMultiplier) 100.0 else 0.0 private val upgradeFortune: Double? get() = currentCrop?.getUpgradeLevel()?.let { it * 5.0 } + private val accessoryFortune: Double? + get() = currentCrop?.let { + CropAccessoryData.cropAccessory?.getFortune(it) + } private var lastToolSwitch: Long = 0 private var ticks: Int = 0 @@ -73,23 +82,47 @@ class FarmingFortuneDisplay { @SubscribeEvent fun onRenderOverlay(event: GuiRenderEvent.GameOverlayRenderEvent) { if (!isEnabled()) return - config.farmingFortunePos.renderSingleLineWithItems(display, posLabel = "True Farming Fortune") + config.farmingFortunePos.renderStringsAndItems(display, posLabel = "True Farming Fortune") + } + + @SubscribeEvent + fun onRenderOverlay(event: GuiRenderEvent.ChestBackgroundRenderEvent) { + if (!isEnabled()) return + if (!CropAccessoryData.isLoadingAccessories) return + SkyHanniMod.feature.misc.inventoryLoadPos.renderString(accessoryProgressDisplay, posLabel = "Load Accessory Bags") } @SubscribeEvent fun onTick(event: TickEvent.ClientTickEvent) { if (event.phase != TickEvent.Phase.START || ticks++ % 5 != 0) return val displayCrop = currentCrop ?: return - val updatedDisplay = mutableListOf<Any>() - updatedDisplay.addCropIcon(displayCrop) - val recentlySwitchedTool = System.currentTimeMillis() < lastToolSwitch + 1000 - val displayString = upgradeFortune?.let { - "§6Farming Fortune§7: §e" + if (!recentlySwitchedTool) { - val totalFortune = it + tabFortune + toolFortune - LorenzUtils.formatDouble(totalFortune, 0) - } else "?" - } ?: "§cOpen §e/cropupgrades§c to use!" - updatedDisplay.add(displayString) + + val updatedDisplay = mutableListOf<List<Any>>() + updatedDisplay.add(mutableListOf<Any>().also { + it.addCropIcon(displayCrop) + val recentlySwitchedTool = System.currentTimeMillis() < lastToolSwitch + 1000 + it.add( + "§6Farming Fortune§7: §e" + if (!recentlySwitchedTool) { + val upgradeFortune = upgradeFortune ?: 0.0 + val accessoryFortune = accessoryFortune ?: 0.0 + val totalFortune = baseFortune + upgradeFortune + tabFortune + toolFortune + accessoryFortune + LorenzUtils.formatDouble(totalFortune, 0) + } else "?") + }) + + if (this.upgradeFortune == null) { + updatedDisplay.addAsSingletonList("§cOpen §e/cropupgrades§c for more exact data!") + } + if (accessoryFortune == null) { + updatedDisplay.addAsSingletonList("§cOpen Accessory Bag for more exact data!") + if (CropAccessoryData.isLoadingAccessories) { + accessoryProgressDisplay = + "§e${CropAccessoryData.pagesLoaded}/${CropAccessoryData.accessoryBagPageCount} pages viewed" + } + } else { + accessoryProgressDisplay = "" + } + display = updatedDisplay } @@ -104,9 +137,11 @@ class FarmingFortuneDisplay { private fun isEnabled(): Boolean = GardenAPI.inGarden() && config.farmingFortuneDisplay + companion object { private val collectionPattern = "§7You have §6\\+([\\d]{1,3})☘ Farming Fortune".toRegex() + fun getToolFortune(tool: ItemStack?): Double { val internalName = tool?.getInternalName() ?: return 0.0 return if (internalName.startsWith("THEORETICAL_HOE")) { @@ -148,5 +183,7 @@ class FarmingFortuneDisplay { ) return dedicationMultiplier * cropMilestone } + + } }
\ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenNextJacobContest.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenNextJacobContest.kt index 398b6818f..e056ba510 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenNextJacobContest.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenNextJacobContest.kt @@ -218,7 +218,7 @@ class GardenNextJacobContest { if (!inCalendar) return if (display.isNotEmpty()) { - config.nextJacobContestPos.renderSingleLineWithItems(display, posLabel = "Garden Next Jacob Contest") + SkyHanniMod.feature.misc.inventoryLoadPos.renderSingleLineWithItems(display, posLabel = "Load SkyBlock Calendar") } } diff --git a/src/main/java/at/hannibal2/skyhanni/utils/NEUItems.kt b/src/main/java/at/hannibal2/skyhanni/utils/NEUItems.kt index 25d67bb07..2549c215b 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/NEUItems.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/NEUItems.kt @@ -12,6 +12,7 @@ import net.minecraft.client.renderer.GlStateManager import net.minecraft.client.renderer.RenderHelper import net.minecraft.init.Items import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound object NEUItems { private val manager: NEUManager get() = NotEnoughUpdates.INSTANCE.manager @@ -47,6 +48,10 @@ object NEUItems { .resolveInternalName() ?: "" } + fun getInternalNameOrNull(nbt: NBTTagCompound): String? { + return ItemResolutionQuery(manager).withItemNBT(nbt).resolveInternalName() + } + fun getPriceOrNull(internalName: String, useSellingPrice: Boolean = false): Double? { val price = getPrice(internalName, useSellingPrice) if (price == -1.0) { |