diff options
author | hannibal2 <24389977+hannibal00212@users.noreply.github.com> | 2023-06-10 14:33:20 +0200 |
---|---|---|
committer | hannibal2 <24389977+hannibal00212@users.noreply.github.com> | 2023-06-10 14:33:20 +0200 |
commit | 698ebfb1a5673e52f97c681d41a1eb4becf92df7 (patch) | |
tree | 42bcd3a46d2e6814940a0924593d642a2982c15b /src/main/java/at/hannibal2 | |
parent | 90b7eba90154668696d69766aed7be1aae61b9a6 (diff) | |
download | skyhanni-698ebfb1a5673e52f97c681d41a1eb4becf92df7.tar.gz skyhanni-698ebfb1a5673e52f97c681d41a1eb4becf92df7.tar.bz2 skyhanni-698ebfb1a5673e52f97c681d41a1eb4becf92df7.zip |
+ Changed Slayer Profit Tracker
+ Option to change price between npc/instant sell and sell offer
+ Save data in config
+ Added option to hide an item from the display
+ Showing the profit per boss
= Different tiers of same slayer type no longer gets merged together
Diffstat (limited to 'src/main/java/at/hannibal2')
9 files changed, 191 insertions, 55 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/config/Storage.java b/src/main/java/at/hannibal2/skyhanni/config/Storage.java index 2de960a30..ec37aa1f7 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/Storage.java +++ b/src/main/java/at/hannibal2/skyhanni/config/Storage.java @@ -189,5 +189,35 @@ public class Storage { @Expose public long nextCityProjectParticipationTime = 0L; + + @Expose + public Map<String, SlayerProfitList> slayerProfitData = new HashMap<>(); + + public static class SlayerProfitList { + + @Expose + public Map<String, SlayerItemProfit> items = new HashMap<>(); + + @Expose + public long mobKillCoins = 0; + + @Expose + public long slayerSpawnCost = 0; + + @Expose + public int slayerCompletedCount = 0; + + public static class SlayerItemProfit { + @Expose + public String internalName; + @Expose + public long timesDropped; + @Expose + public long totalAmount; + @Expose + public boolean hidden; + } + } + } }
\ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/Slayer.java b/src/main/java/at/hannibal2/skyhanni/config/features/Slayer.java index a5dad699c..0f69f6a20 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/Slayer.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/Slayer.java @@ -105,6 +105,11 @@ public class Slayer { public boolean priceInChat = false; @Expose + @ConfigOption(name = "Show Price From", desc = "Show price from Bazaar or NPC.") + @ConfigEditorDropdown(values = {"Instant Sell", "Sell Offer", "NPC"}) + public int priceFrom = 0; + + @Expose @ConfigOption(name = "Minimum Price", desc = "Items below this price will not show up in chat.") @ConfigEditorSlider(minValue = 1, maxValue = 5_000_000, minStep = 1) public int minimumPrice = 100_000; diff --git a/src/main/java/at/hannibal2/skyhanni/data/SlayerAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/SlayerAPI.kt index 0d063146d..b5c287d5a 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/SlayerAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/SlayerAPI.kt @@ -2,6 +2,7 @@ package at.hannibal2.skyhanni.data import at.hannibal2.skyhanni.events.LorenzChatEvent import at.hannibal2.skyhanni.events.SlayerChangeEvent +import at.hannibal2.skyhanni.events.SlayerQuestCompleteEvent import at.hannibal2.skyhanni.features.bazaar.BazaarApi import at.hannibal2.skyhanni.features.slayer.SlayerType import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName @@ -82,9 +83,15 @@ object SlayerAPI { @SubscribeEvent fun onChat(event: LorenzChatEvent) { + if (!LorenzUtils.inSkyBlock) return + if (event.message.contains("§r§5§lSLAYER QUEST STARTED!")) { questStartTime = System.currentTimeMillis() } + + if (event.message == " §r§a§lSLAYER QUEST COMPLETE!") { + SlayerQuestCompleteEvent().postAndCatch() + } } @SubscribeEvent diff --git a/src/main/java/at/hannibal2/skyhanni/events/HypixelTIck.kt b/src/main/java/at/hannibal2/skyhanni/events/HypixelTIck.kt deleted file mode 100644 index 42f015ff5..000000000 --- a/src/main/java/at/hannibal2/skyhanni/events/HypixelTIck.kt +++ /dev/null @@ -1,3 +0,0 @@ -package at.hannibal2.skyhanni.events - -class HypixelTickEvent: LorenzEvent()
\ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/events/SlayerQuestCompleteEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/SlayerQuestCompleteEvent.kt new file mode 100644 index 000000000..5ed7ecac2 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/events/SlayerQuestCompleteEvent.kt @@ -0,0 +1,3 @@ +package at.hannibal2.skyhanni.events + +class SlayerQuestCompleteEvent: LorenzEvent()
\ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/features/slayer/SlayerItemProfitTracker.kt b/src/main/java/at/hannibal2/skyhanni/features/slayer/SlayerItemProfitTracker.kt index e4ca7ca28..2e733a398 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/slayer/SlayerItemProfitTracker.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/slayer/SlayerItemProfitTracker.kt @@ -1,23 +1,27 @@ package at.hannibal2.skyhanni.features.slayer import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.config.Storage +import at.hannibal2.skyhanni.data.ProfileStorageData import at.hannibal2.skyhanni.data.SlayerAPI import at.hannibal2.skyhanni.events.* +import at.hannibal2.skyhanni.features.bazaar.BazaarApi +import at.hannibal2.skyhanni.features.bazaar.BazaarData +import at.hannibal2.skyhanni.test.PriceSource +import at.hannibal2.skyhanni.utils.* import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName import at.hannibal2.skyhanni.utils.ItemUtils.name import at.hannibal2.skyhanni.utils.ItemUtils.nameWithEnchantment -import at.hannibal2.skyhanni.utils.LorenzLogger -import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.LorenzUtils.addAsSingletonList -import at.hannibal2.skyhanni.utils.LorenzUtils.editCopy +import at.hannibal2.skyhanni.utils.LorenzUtils.addSelector import at.hannibal2.skyhanni.utils.LorenzUtils.sortedDesc -import at.hannibal2.skyhanni.utils.NEUItems -import at.hannibal2.skyhanni.utils.NumberUtil import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators import at.hannibal2.skyhanni.utils.RenderUtils.renderStringsAndItems import at.hannibal2.skyhanni.utils.StringUtils.removeColor +import at.hannibal2.skyhanni.utils.renderables.Renderable import com.google.common.cache.CacheBuilder import net.minecraft.client.Minecraft +import net.minecraft.client.gui.inventory.GuiInventory import net.minecraft.entity.item.EntityItem import net.minecraft.network.play.server.S0DPacketCollectItem import net.minecraftforge.fml.common.eventhandler.EventPriority @@ -30,17 +34,13 @@ class SlayerItemProfitTracker { private var itemLogCategory = "" private var display = listOf<List<Any>>() - private var itemLogs = mapOf<String, ItemLog>() - private val logger = LorenzLogger("slayer_item_profit_tracker") + private val logger = LorenzLogger("slayer/item_profit_tracker") + private var inventoryOpen = false + private var lastClickDelay = 0L - private fun addSlayerCosts(price: Double) { + private fun addSlayerCosts(price: Int) { val itemLog = currentLog() ?: return - - val name = "Slayer Spawn Costs" - itemLog.items = itemLog.items.editCopy { - val (oldCoins, oldAmount) = getOrDefault(name, 0.0 to 0) - this[name] = oldCoins + price to oldAmount + 1 - } + itemLog.slayerSpawnCost += price update() } @@ -51,54 +51,56 @@ class SlayerItemProfitTracker { if (event.reason == PurseChangeCause.GAIN_MOB_KILL) { if (SlayerAPI.isInSlayerArea) { logger.log("Coins gained for killing mobs: ${coins.addSeparators()}") - addMobKillCoins(coins) + addMobKillCoins(coins.toInt()) } } if (event.reason == PurseChangeCause.LOSE_SLAYER_QUEST_STARTED) { logger.log("Coins paid for starting slayer quest: ${coins.addSeparators()}") - addSlayerCosts(coins) + addSlayerCosts(coins.toInt()) } } @SubscribeEvent fun onSlayerChange(event: SlayerChangeEvent) { val newSlayer = event.newSlayer - itemLogCategory = if (newSlayer == "") { - "" - } else { - newSlayer.split(" ").dropLast(1).joinToString(" ") - } + itemLogCategory = newSlayer.removeColor() update() } - private fun addMobKillCoins(coins: Double) { + private fun addMobKillCoins(coins: Int) { val itemLog = currentLog() ?: return itemLog.mobKillCoins += coins update() } - private fun addItemPickup(totalPrice: Double, displayName: String, stackSize: Int) { + private fun addItemPickup(internalName: String, stackSize: Int) { val itemLog = currentLog() ?: return - itemLog.items = itemLog.items.editCopy { - val (oldCoins, oldAmount) = getOrDefault(displayName, 0.0 to 0) - this[displayName] = oldCoins + totalPrice to oldAmount + stackSize - } + val slayerItemProfit = + itemLog.items.getOrPut(internalName) { Storage.ProfileSpecific.SlayerProfitList.SlayerItemProfit() } + + slayerItemProfit.timesDropped++ + slayerItemProfit.totalAmount += stackSize update() } - private fun currentLog(): ItemLog? { + private fun currentLog(): Storage.ProfileSpecific.SlayerProfitList? { if (itemLogCategory == "") return null - itemLogs[itemLogCategory]?.let { - return it + val profileSpecific = ProfileStorageData.profileSpecific ?: return null + + return profileSpecific.slayerProfitData.getOrPut(itemLogCategory) { + Storage.ProfileSpecific.SlayerProfitList() } + } - val itemLog = ItemLog(itemLogCategory) - itemLogs = itemLogs.editCopy { this[itemLogCategory] = itemLog } + @SubscribeEvent + fun onQuestComplete(event: SlayerQuestCompleteEvent) { + val itemLog = currentLog() ?: return - return itemLog + itemLog.slayerCompletedCount++ + update() } @SubscribeEvent(priority = EventPriority.LOW, receiveCanceled = true) @@ -123,8 +125,7 @@ class SlayerItemProfitTracker { if (internalName == "") return val (itemName, price) = SlayerAPI.getItemNameAndPrice(itemStack) - val displayName = NEUItems.getItemStack(internalName).nameWithEnchantment ?: "internalName" - addItemPickup(price, displayName, itemStack.stackSize) + addItemPickup(internalName, itemStack.stackSize) logger.log("Coins gained for picking up an item ($itemName) ${price.addSeparators()}") if (config.priceInChat) { if (config.minimumPrice < price) { @@ -140,31 +141,99 @@ class SlayerItemProfitTracker { private fun drawDisplay() = buildList<List<Any>> { val itemLog = currentLog() ?: return@buildList - val displayName = itemLog.displayName.removeColor() - addAsSingletonList("§e§l$displayName Profit Tracker") + addAsSingletonList("§e§l$itemLogCategory Profit Tracker") var profit = 0.0 - val map = mutableMapOf<String, Double>() - for ((name, value) in itemLog.items) { - val (price, amount) = value - val profitPrefix = if (price < 0) "§c" else "§6" + val map = mutableMapOf<Renderable, Long>() + for ((internalName, itemProfit) in itemLog.items) { + val amount = itemProfit.totalAmount + + val bazaarData = BazaarApi.getBazaarDataByInternalName(internalName) ?: continue + val price = (getPrice(bazaarData) * amount).toLong() + var name = NEUItems.getItemStack(internalName).nameWithEnchantment ?: internalName val priceFormat = NumberUtil.format(price) - map["§7${amount.addSeparators()}x $name§7: $profitPrefix$priceFormat"] = price + val hidden = itemProfit.hidden + if (hidden) { +// text += " §c(hidden)" + name = StringUtils.addFormat(name, "§m") + } + val text = " §7${amount.addSeparators()}x $name§7: §6$priceFormat" + + val timesDropped = itemProfit.timesDropped + val percentage = timesDropped.toDouble() / itemLog.slayerCompletedCount + val perBoss = LorenzUtils.formatPercentage(percentage.coerceAtMost(1.0)) + + + val renderable = if (inventoryOpen) Renderable.clickAndHover( + text, listOf( + "§7Dropped §e$timesDropped §7times.", + "§7Your drop rate: §c$perBoss", + "", + "§eClick to " + (if (hidden) "show" else "hide") + "!" + ) + ) { + if (System.currentTimeMillis() > lastClickDelay + 150) { + lastClickDelay = System.currentTimeMillis() + itemProfit.hidden = !hidden + update() + } + } else Renderable.string(text) + if (inventoryOpen || !hidden) { + map[renderable] = price + } profit += price } val mobKillCoins = itemLog.mobKillCoins - if (mobKillCoins != 0.0) { + if (mobKillCoins != 0L) { val mobKillCoinsFormat = NumberUtil.format(mobKillCoins) - map["§7Mob kill coins: §6$mobKillCoinsFormat"] = mobKillCoins + map[Renderable.hoverTips(" §7Mob kill coins: §6$mobKillCoinsFormat", + listOf("§7Killing mobs gives you coins (more with scavenger)", + "§7You got §e$mobKillCoinsFormat §7coins in total this way"))] = mobKillCoins + profit += mobKillCoins + } + val slayerSpawnCost = itemLog.slayerSpawnCost + if (slayerSpawnCost != 0L) { + val mobKillCoinsFormat = NumberUtil.format(slayerSpawnCost) + map[Renderable.hoverTips(" §7Slayer Spawn Costs: §c$mobKillCoinsFormat", + listOf("§7You paid §c$mobKillCoinsFormat §7in total", "§7for starting the slayer quests."))] = slayerSpawnCost + profit += slayerSpawnCost } for (text in map.sortedDesc().keys) { - addAsSingletonList(" $text") + addAsSingletonList(text) } + val slayerCompletedCount = itemLog.slayerCompletedCount + addAsSingletonList(Renderable.hoverTips("§7Bosses killed: §e$slayerCompletedCount", + listOf("§7You killed the $itemLogCategory boss", "§e$slayerCompletedCount §7times."))) + profit += mobKillCoins val profitFormat = NumberUtil.format(profit) val profitPrefix = if (profit < 0) "§c" else "§6" - addAsSingletonList("§eTotal Profit: $profitPrefix$profitFormat") + + val profitPerBoss = profit / itemLog.slayerCompletedCount + val profitPerBossFormat = NumberUtil.format(profitPerBoss) + + val text = "§eTotal Profit: $profitPrefix$profitFormat" + addAsSingletonList(Renderable.hoverTips(text, listOf("§7Profit per boss: $profitPrefix$profitPerBossFormat"))) + + if (inventoryOpen) { + addSelector(" ", PriceSource.values(), + getName = { type -> type.displayName }, + isCurrent = { it.ordinal == config.priceFrom }, + onChange = { + config.priceFrom = it.ordinal + update() + }) + } + } + + private fun getPrice(bazaarData: BazaarData): Double { + return when (config.priceFrom) { + 0 -> bazaarData.sellPrice + 1 -> bazaarData.buyPrice + + else -> bazaarData.npcPrice + } } @SubscribeEvent @@ -172,14 +241,15 @@ class SlayerItemProfitTracker { if (!isEnabled()) return if (!SlayerAPI.isInSlayerArea) return + val currentlyOpen = Minecraft.getMinecraft().currentScreen is GuiInventory + if (inventoryOpen != currentlyOpen) { + inventoryOpen = currentlyOpen + update() + } + + config.pos.renderStringsAndItems(display, posLabel = "Slayer Item Profit Tracker") } fun isEnabled() = LorenzUtils.inSkyBlock && config.enabled - - class ItemLog(val displayName: String) { - // display name -> (totalCoins, amount) - var items = mapOf<String, Pair<Double, Int>>() - var mobKillCoins = 0.0 - } } diff --git a/src/main/java/at/hannibal2/skyhanni/test/PriceSource.kt b/src/main/java/at/hannibal2/skyhanni/test/PriceSource.kt new file mode 100644 index 000000000..684440ba1 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/test/PriceSource.kt @@ -0,0 +1,8 @@ +package at.hannibal2.skyhanni.test + +enum class PriceSource(val displayName: String) { + BAZAAR_INSTANT_SELL("Instant Sell"), + BAZAAR_SELL_OFFER("Sell Offer"), + NPC("Npc Price"), + ; +}
\ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/utils/StringUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/StringUtils.kt index fc043e26b..90dcddf9b 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/StringUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/StringUtils.kt @@ -93,4 +93,16 @@ object StringUtils { fun encodeBase64(input: String) = Base64.getEncoder().encodeToString(input.toByteArray()) fun decodeBase64(input: String) = Base64.getDecoder().decode(input).decodeToString() + + fun addFormat(text: String, format: String): String { + if (text.length < 2) return text + + val rawText = text.substring(2) + return if (rawText == text.removeColor()) { + val originalColor = text.substring(0, 2) + "$originalColor$format$rawText" + } else { + "$format$text" + } + } }
\ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt b/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt index 9917799f7..5047c4744 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt @@ -48,6 +48,10 @@ interface Renderable { return clickable(hoverable(underlined(renderable), renderable, condition), onClick, 0, condition) } + fun clickAndHover(text: String, tips: List<String>, onClick: () -> Unit): Renderable { + return clickable(hoverTips(text, tips), onClick) + } + fun clickable(render: Renderable, onClick: () -> Unit, button: Int = 0, condition: () -> Boolean = { true }) = object : Renderable { override val width: Int |