From 593c01992afe4e8d5d4cd8aa61abbfb1d82e2a30 Mon Sep 17 00:00:00 2001 From: CalMWolfs <94038482+CalMWolfs@users.noreply.github.com> Date: Sun, 10 Sep 2023 18:40:56 +1000 Subject: SackAPI event and storing data #410 * implement SackChangeEvent * move SackAPI * handling events * fixed small errors * fetching item data * moved over sack display * it should work * saving gemstones * saving gemstones * new config file for sacks * saving last change amount * fix conflicts fully * implement SackChangeEvent * move SackAPI * handle 'other items' correctly * move sackAPI again * handling events * fixed small errors * fetching item data * moved over sack display * it should work * saving gemstones * saving gemstones * new config file for sacks * saving last change amount * Merge branch 'beta' into sack_storage * fix conflicts fully * Merge remote-tracking branch 'origin/sack_storage' into sack_storage * Merge branch 'hannibal002:beta' into sack_storage * Merge remote-tracking branch 'origin/sack_storage' into sack_storage * remove unnecessary thing --- src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt | 11 +- .../at/hannibal2/skyhanni/config/ConfigManager.kt | 48 ++++ .../at/hannibal2/skyhanni/config/SackData.java | 26 ++ .../hannibal2/skyhanni/data/ProfileStorageData.kt | 26 +- .../java/at/hannibal2/skyhanni/data/SackAPI.kt | 291 ++++++++++++++++++++- .../skyhanni/features/inventory/SackDisplay.kt | 290 +++----------------- 6 files changed, 430 insertions(+), 262 deletions(-) create mode 100644 src/main/java/at/hannibal2/skyhanni/config/SackData.java (limited to 'src') diff --git a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt index bc391ff91..d7c4a566a 100644 --- a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt +++ b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt @@ -3,6 +3,7 @@ package at.hannibal2.skyhanni import at.hannibal2.skyhanni.api.CollectionAPI import at.hannibal2.skyhanni.config.ConfigManager import at.hannibal2.skyhanni.config.Features +import at.hannibal2.skyhanni.config.SackData import at.hannibal2.skyhanni.config.commands.Commands.init import at.hannibal2.skyhanni.data.* import at.hannibal2.skyhanni.data.repo.RepoManager @@ -187,7 +188,7 @@ class SkyHanniMod { loadModule(SlayerAPI) loadModule(PurseAPI()) loadModule(RiftAPI) - loadModule(SackAPI()) + loadModule(SackAPI) // features loadModule(BazaarOrderHelper()) @@ -334,7 +335,7 @@ class SkyHanniMod { loadModule(BingoCardTips()) loadModule(GardenVisitorDropStatistics) loadModule(CaptureFarmingGear()) - loadModule(SackDisplay()) + loadModule(SackDisplay) loadModule(GardenStartLocation) loadModule(PetCandyUsedDisplay()) loadModule(ServerRestartTitle()) @@ -420,7 +421,10 @@ class SkyHanniMod { configManager = ConfigManager() configManager.firstLoad() initLogging() - Runtime.getRuntime().addShutdownHook(Thread { configManager.saveConfig("shutdown-hook") }) + Runtime.getRuntime().addShutdownHook(Thread { + configManager.saveConfig("shutdown-hook") + configManager.saveSackData("shutdown-hook") + }) repo = RepoManager(configManager.configDirectory) try { repo.loadRepoInformation() @@ -455,6 +459,7 @@ class SkyHanniMod { @JvmStatic val feature: Features get() = configManager.features + val sackData: SackData get() = configManager.sackData lateinit var repo: RepoManager lateinit var configManager: ConfigManager val logger: Logger = LogManager.getLogger("SkyHanni") diff --git a/src/main/java/at/hannibal2/skyhanni/config/ConfigManager.kt b/src/main/java/at/hannibal2/skyhanni/config/ConfigManager.kt index 31c02efab..a882af5d4 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/ConfigManager.kt +++ b/src/main/java/at/hannibal2/skyhanni/config/ConfigManager.kt @@ -81,11 +81,14 @@ class ConfigManager { } lateinit var features: Features + lateinit var sackData: SackData + private set private val logger = LorenzLogger("config_manager") var configDirectory = File("config/skyhanni") private var configFile: File? = null + private var sackFile: File? = null lateinit var processor: MoulConfigProcessor fun firstLoad() { @@ -95,6 +98,7 @@ class ConfigManager { configDirectory.mkdir() configFile = File(configDirectory, "config.json") + sackFile = File(configDirectory, "sacks.json") fixedRateTimer(name = "skyhanni-config-auto-save", period = 60_000L, initialDelay = 60_000L) { saveConfig("auto-save-60s") @@ -134,12 +138,40 @@ class ConfigManager { } } + if (sackFile!!.exists()) { + try { + val inputStreamReader = InputStreamReader(FileInputStream(sackFile!!), StandardCharsets.UTF_8) + val bufferedReader = BufferedReader(inputStreamReader) + val builder = StringBuilder() + for (line in bufferedReader.lines()) { + builder.append(line) + builder.append("\n") + } + + + logger.log("load-sacks-now") + sackData = gson.fromJson( + builder.toString(), + SackData::class.java + ) + logger.log("Loaded sacks from file") + } catch (error: Exception) { + error.printStackTrace() + } + } + if (!::features.isInitialized) { logger.log("Creating blank config and saving to file") features = Features() saveConfig("blank config") } + if (!::sackData.isInitialized) { + logger.log("Creating blank sack data and saving") + sackData = SackData() + saveSackData("blank config") + } + val features = SkyHanniMod.feature processor = MoulConfigProcessor(SkyHanniMod.feature) BuiltinMoulConfigGuis.addProcessors(processor) @@ -179,4 +211,20 @@ class ConfigManager { e.printStackTrace() } } + + fun saveSackData(reason: String) { + logger.log("saveSackData: $reason") + val file = sackFile ?: throw Error("Can not save sacks, sackFile is null!") + try { + logger.log("Saving sack file") + file.parentFile.mkdirs() + file.createNewFile() + BufferedWriter(OutputStreamWriter(FileOutputStream(file), StandardCharsets.UTF_8)).use { writer -> + writer.write(gson.toJson(SkyHanniMod.sackData)) + } + } catch (e: IOException) { + logger.log("Could not save sacks file to $file") + e.printStackTrace() + } + } } \ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/config/SackData.java b/src/main/java/at/hannibal2/skyhanni/config/SackData.java new file mode 100644 index 000000000..61febed74 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/SackData.java @@ -0,0 +1,26 @@ +package at.hannibal2.skyhanni.config; + +import at.hannibal2.skyhanni.data.SackItem; +import at.hannibal2.skyhanni.utils.NEUInternalName; +import com.google.gson.annotations.Expose; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public class SackData { + + @Expose + public Map players = new HashMap<>(); + + public static class PlayerSpecific { + @Expose + public Map profiles = new HashMap<>(); + } + + public static class ProfileSpecific { + + @Expose + public Map sackContents = new HashMap<>(); + } +} \ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/data/ProfileStorageData.kt b/src/main/java/at/hannibal2/skyhanni/data/ProfileStorageData.kt index 36940104b..3524f03db 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/ProfileStorageData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/ProfileStorageData.kt @@ -1,6 +1,7 @@ package at.hannibal2.skyhanni.data import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.config.SackData import at.hannibal2.skyhanni.config.Storage import at.hannibal2.skyhanni.events.* import at.hannibal2.skyhanni.utils.LorenzUtils @@ -17,6 +18,10 @@ object ProfileStorageData { private var nextProfile: String? = null + + private var sackPlayers: SackData.PlayerSpecific? = null + var sackProfiles: SackData.ProfileSpecific? = null + @SubscribeEvent(priority = EventPriority.HIGHEST) fun onChat(event: LorenzChatEvent) { "§7Switching to profile (?.*)\\.\\.\\.".toPattern().matchMatcher(event.message) { @@ -32,25 +37,35 @@ object ProfileStorageData { nextProfile = null val playerSpecific = playerSpecific + val sackPlayers = sackPlayers if (playerSpecific == null) { LorenzUtils.error("profileSpecific after profile swap can not be set: playerSpecific is null!") return } - loadProfileSpecific(playerSpecific, profileName, "profile swap (chat message)") + if (sackPlayers == null) { + LorenzUtils.error("sackPlayers after profile swap can not be set: sackPlayers is null!") + return + } + loadProfileSpecific(playerSpecific, sackPlayers, profileName, "profile swap (chat message)") ConfigLoadEvent().postAndCatch() } @SubscribeEvent(priority = EventPriority.HIGHEST) fun onProfileJoin(event: ProfileJoinEvent) { val playerSpecific = playerSpecific + val sackPlayers = sackPlayers if (playerSpecific == null) { LorenzUtils.error("playerSpecific is null in ProfileJoinEvent!") return } + if (sackPlayers == null) { + LorenzUtils.error("sackPlayers is null in sackPlayers!") + return + } if (profileSpecific == null) { val profileName = event.name - loadProfileSpecific(playerSpecific, profileName, "first join (chat message)") + loadProfileSpecific(playerSpecific, sackPlayers, profileName, "first join (chat message)") } } @@ -58,11 +73,12 @@ object ProfileStorageData { fun onTabListUpdate(event: TabListUpdateEvent) { if (profileSpecific != null) return val playerSpecific = playerSpecific ?: return + val sackPlayers = sackPlayers ?: return for (line in event.tabList) { val pattern = "§e§lProfile: §r§a(?.*)".toPattern() pattern.matchMatcher(line) { val profileName = group("name").lowercase() - loadProfileSpecific(playerSpecific, profileName, "tab list") + loadProfileSpecific(playerSpecific, sackPlayers, profileName, "tab list") nextProfile = null return } @@ -87,9 +103,10 @@ object ProfileStorageData { } } - private fun loadProfileSpecific(playerSpecific: Storage.PlayerSpecific, profileName: String, reason: String) { + private fun loadProfileSpecific(playerSpecific: Storage.PlayerSpecific, sackProfile: SackData.PlayerSpecific, profileName: String, reason: String) { noTabListTime = -1 profileSpecific = playerSpecific.profiles.getOrPut(profileName) { Storage.ProfileSpecific() } + sackProfiles = sackProfile.profiles.getOrPut(profileName) { SackData.ProfileSpecific() } tryMigrateProfileSpecific() loaded = true ConfigLoadEvent().postAndCatch() @@ -99,6 +116,7 @@ object ProfileStorageData { fun onHypixelJoin(event: HypixelJoinEvent) { val playerUuid = LorenzUtils.getRawPlayerUuid() playerSpecific = SkyHanniMod.feature.storage.players.getOrPut(playerUuid) { Storage.PlayerSpecific() } + sackPlayers = SkyHanniMod.sackData.players.getOrPut(playerUuid) { SackData.PlayerSpecific() } migratePlayerSpecific() ConfigLoadEvent().postAndCatch() } diff --git a/src/main/java/at/hannibal2/skyhanni/data/SackAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/SackAPI.kt index 3990e13d6..4534e49a5 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/SackAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/SackAPI.kt @@ -1,13 +1,192 @@ package at.hannibal2.skyhanni.data +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.events.InventoryCloseEvent +import at.hannibal2.skyhanni.events.InventoryFullyOpenedEvent import at.hannibal2.skyhanni.events.LorenzChatEvent import at.hannibal2.skyhanni.events.SackChangeEvent +import at.hannibal2.skyhanni.features.fishing.trophy.TrophyFishManager +import at.hannibal2.skyhanni.features.fishing.trophy.TrophyRarity +import at.hannibal2.skyhanni.features.inventory.SackDisplay +import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName +import at.hannibal2.skyhanni.utils.ItemUtils.getLore +import at.hannibal2.skyhanni.utils.ItemUtils.name +import at.hannibal2.skyhanni.utils.LorenzUtils.editCopy import at.hannibal2.skyhanni.utils.NEUInternalName +import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.asInternalName +import at.hannibal2.skyhanni.utils.NEUItems.getNpcPriceOrNull +import at.hannibal2.skyhanni.utils.NEUItems.getPrice +import at.hannibal2.skyhanni.utils.NumberUtil.formatNumber +import at.hannibal2.skyhanni.utils.StringUtils.matchMatcher import at.hannibal2.skyhanni.utils.StringUtils.removeColor +import com.google.gson.annotations.Expose +import net.minecraft.item.ItemStack import net.minecraftforge.fml.common.eventhandler.SubscribeEvent -class SackAPI { +object SackAPI { + private val sackDisplayConfig get() = SkyHanniMod.feature.inventory.sackDisplay + private var lastOpenedInventory = "" + + var inSackInventory = false + private val sackPattern = "^(.* Sack|Enchanted .* Sack)$".toPattern() + private val numPattern = + "(?:(?:§[0-9a-f](?I{1,3})§7:)?|(?:§7Stored:)?) (?§[0-9a-f])(?[0-9.,kKmMbB]+)§7/(?\\d+(?:[0-9.,]+)?[kKmMbB]?)".toPattern() + private val gemstonePattern = + " §[0-9a-f](?[A-z]*): §[0-9a-f](?\\d+(?:\\.\\d+)?(?:(?:,\\d+)?)+[kKmM]?)(?: §[0-9a-f]\\(\\d+(?:\\.\\d+)?(?:(?:,\\d+)?)+[kKmM]?\\))?".toPattern() + + private var isRuneSack = false + private var isGemstoneSack = false + var isTrophySack = false + private var sackRarity: TrophyRarity? = null + + val sackItem = mutableMapOf() + val runeItem = mutableMapOf() + val gemstoneItem = mutableMapOf() + private val stackList = mutableMapOf() + + @SubscribeEvent + fun onInventoryClose(event: InventoryCloseEvent) { + inSackInventory = false + isRuneSack = false + isGemstoneSack = false + isTrophySack = false + runeItem.clear() + gemstoneItem.clear() + sackItem.clear() + stackList.clear() + } + + @SubscribeEvent + fun onInventoryOpen(event: InventoryFullyOpenedEvent) { + val inventoryName = event.inventoryName + val isNewInventory = inventoryName != lastOpenedInventory + lastOpenedInventory = inventoryName + val match = sackPattern.matcher(inventoryName).matches() + if (!match) return + val stacks = event.inventoryItems + isRuneSack = inventoryName == "Runes Sack" + isGemstoneSack = inventoryName == "Gemstones Sack" + isTrophySack = inventoryName.contains("Trophy Fishing Sack") + sackRarity = inventoryName.getTrophyRarity() + inSackInventory = true + stackList.putAll(stacks) + SackDisplay.update(isNewInventory) + } + + private fun String.getTrophyRarity(): TrophyRarity? { + return if (this.startsWith("Bronze")) + TrophyRarity.BRONZE + else + if (this.startsWith("Silver")) + TrophyRarity.SILVER + else null + } + + private fun NEUInternalName.sackPrice(stored: String) = when (sackDisplayConfig.priceFrom) { + 0 -> (getPrice(true) * stored.formatNumber()).toInt().let { if (it < 0) 0 else it } + + 1 -> try { + val npcPrice = getNpcPriceOrNull() ?: 0.0 + (npcPrice * stored.formatNumber()).toInt() + } catch (e: Exception) { + 0 + } + + else -> 0 + } + + fun getSacksData(savingSacks: Boolean) { + if (savingSacks) sackData = ProfileStorageData.sackProfiles?.sackContents ?: return + for ((_, stack) in stackList) { + val name = stack.name ?: continue + val lore = stack.getLore() + val gem = SackGemstone() + val rune = SackRune() + val item = SackOtherItem() + loop@ for (line in lore) { + if (isGemstoneSack) { + gemstonePattern.matchMatcher(line) { + val rarity = group("gemrarity") + val stored = group("stored") + gem.internalName = gemstoneMap[name.removeColor()] ?: NEUInternalName.NONE + if (gemstoneMap.containsKey(name.removeColor())) { + val internalName = "${rarity.uppercase()}_${ + name.uppercase().split(" ")[0].removeColor() + }_GEM".asInternalName() + + when (rarity) { + "Rough" -> { + gem.rough = stored + gem.roughPrice = internalName.sackPrice(stored) + if (savingSacks) setSackItem(internalName, stored.formatNumber().toInt()) + } + + "Flawed" -> { + gem.flawed = stored + gem.flawedPrice = internalName.sackPrice(stored) + if (savingSacks) setSackItem(internalName, stored.formatNumber().toInt()) + } + + "Fine" -> { + gem.fine = stored + gem.finePrice = internalName.sackPrice(stored) + if (savingSacks) setSackItem(internalName, stored.formatNumber().toInt()) + } + + "Flawless" -> { + gem.flawless = stored + gem.flawlessPrice = internalName.sackPrice(stored) + if (savingSacks) setSackItem(internalName, stored.formatNumber().toInt()) + } + } + gemstoneItem[name] = gem + } + } + } else { + numPattern.matchMatcher(line) { + val stored = group("stored") + val internalName = stack.getInternalName() + item.internalName = internalName + item.colorCode = group("color") + item.stored = stored + item.total = group("total") + if (savingSacks) setSackItem(item.internalName, item.stored.formatNumber().toInt()) + item.price = if (isTrophySack) { + val trophyName = + internalName.asString().lowercase().substringBeforeLast("_").replace("_", "") + val filletValue = + TrophyFishManager.getInfoByName(trophyName)?.getFilletValue(sackRarity!!) ?: 0 + val storedNumber = stored.formatNumber().toInt() + "MAGMA_FISH".asInternalName().sackPrice((filletValue * storedNumber).toString()) + } else internalName.sackPrice(stored).coerceAtLeast(0) + + if (isRuneSack) { + val level = group("level") + rune.stack = stack + if (level == "I") { + rune.lvl1 = stored + continue@loop + } + if (level == "II") { + rune.lvl2 = stored + continue@loop + } + if (level == "III") { + rune.lvl3 = stored + } + runeItem.put(name, rune) + } else { + sackItem.put(name, item) + } + } + } + } + } + if (savingSacks) saveSackData() + } + + private var sackData = mapOf() data class SackChange(val delta: Int, val internalName: NEUInternalName, val sacks: List) @@ -16,7 +195,7 @@ class SackAPI { @SubscribeEvent fun onChat(event: LorenzChatEvent) { if (!event.message.removeColor().startsWith("[Sacks]")) return - + val sackAddText = event.chatComponent.siblings.firstNotNullOfOrNull { sibling -> sibling.chatStyle?.chatHoverEvent?.value?.formattedText?.removeColor()?.takeIf { it.startsWith("Added") @@ -45,4 +224,112 @@ class SackAPI { } SackChangeEvent(sackChanges, otherItemsAdded, otherItemsRemoved).postAndCatch() } + + @SubscribeEvent + fun sackChange(event: SackChangeEvent) { + sackData = ProfileStorageData.sackProfiles?.sackContents ?: return + + // if it gets added and subtracted but only 1 shows it will be outdated + val justChanged = mutableMapOf() + + for (change in event.sackChanges) { + if (change.internalName in justChanged) { + justChanged[change.internalName] = (justChanged[change.internalName] ?: 0) + change.delta + } else { + justChanged[change.internalName] = change.delta + } + } + + for (item in justChanged) { + if (sackData.containsKey(item.key)) { + val oldData = sackData[item.key] + var newAmount = oldData!!.amount + item.value + var changed = newAmount - oldData.amount + if (newAmount < 0) { + newAmount = 0 + changed = 0 + } + sackData = sackData.editCopy { this[item.key] = SackItem(newAmount, changed, oldData.outdatedStatus) } + } else { + val newAmount = if (item.value > 0) item.value else 0 + sackData = sackData.editCopy { this[item.key] = SackItem(newAmount, newAmount, 2) } + } + } + + if (event.otherItemsAdded || event.otherItemsRemoved) { + for (item in sackData) { + if (item.key in justChanged) continue + val oldData = sackData[item.key] + sackData = sackData.editCopy { this[item.key] = SackItem(oldData!!.amount, 0, 1) } + } + } + saveSackData() + } + + private fun setSackItem(item: NEUInternalName, amount: Int) { + sackData = sackData.editCopy { this[item] = SackItem(amount, 0, 0) } + } + + fun fetchSackItem(item: NEUInternalName): SackItem? { + sackData = ProfileStorageData.sackProfiles?.sackContents ?: return SackItem(0, 0, -1) + + if (sackData.containsKey(item)) { + return sackData[item] + } + + sackData = sackData.editCopy { this[item] = SackItem(0, 0, 2) } + return sackData[item] + } + + private fun saveSackData() { + ProfileStorageData.sackProfiles?.sackContents = sackData + SkyHanniMod.configManager.saveSackData("shutdown-hook") + } + + data class SackGemstone( + var internalName: NEUInternalName = NEUInternalName.NONE, + var rough: String = "0", + var flawed: String = "0", + var fine: String = "0", + var flawless: String = "0", + var roughPrice: Int = 0, + var flawedPrice: Int = 0, + var finePrice: Int = 0, + var flawlessPrice: Int = 0, + ) + + data class SackRune( + var stack: ItemStack? = null, + var lvl1: String = "0", + var lvl2: String = "0", + var lvl3: String = "0", + ) + + data class SackOtherItem( + var internalName: NEUInternalName = NEUInternalName.NONE, + var colorCode: String = "", + var stored: String = "0", + var total: String = "0", + var price: Int = 0, + ) } + +// status -1 = fetching data failed, 0 = < 1% of being wrong, 1 = 10% of being wrong, 2 = is 100% wrong +// lastChange is set to 0 when value is refreshed in the sacks gui and when being set initially +// if it didn't change in an update the lastChange value will stay the same and not be set to 0 +data class SackItem( + @Expose val amount: Int, + @Expose val lastChange: Int, + @Expose val outdatedStatus: Int +) + +private val gemstoneMap = mapOf( + "Jade Gemstones" to "ROUGH_JADE_GEM".asInternalName(), + "Amber Gemstones" to "ROUGH_AMBER_GEM".asInternalName(), + "Topaz Gemstones" to "ROUGH_TOPAZ_GEM".asInternalName(), + "Sapphire Gemstones" to "ROUGH_SAPPHIRE_GEM".asInternalName(), + "Amethyst Gemstones" to "ROUGH_AMETHYST_GEM".asInternalName(), + "Jasper Gemstones" to "ROUGH_JASPER_GEM".asInternalName(), + "Ruby Gemstones" to "ROUGH_RUBY_GEM".asInternalName(), + "Opal Gemstones" to "ROUGH_OPAL_GEM".asInternalName(), +) diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/SackDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/SackDisplay.kt index b9cd5fdeb..260d4bb9e 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/inventory/SackDisplay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/SackDisplay.kt @@ -1,181 +1,53 @@ package at.hannibal2.skyhanni.features.inventory import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.data.SackAPI import at.hannibal2.skyhanni.events.GuiRenderEvent -import at.hannibal2.skyhanni.events.InventoryCloseEvent -import at.hannibal2.skyhanni.events.InventoryFullyOpenedEvent import at.hannibal2.skyhanni.features.bazaar.BazaarApi -import at.hannibal2.skyhanni.features.fishing.trophy.TrophyFishManager -import at.hannibal2.skyhanni.features.fishing.trophy.TrophyRarity -import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName -import at.hannibal2.skyhanni.utils.ItemUtils.getLore -import at.hannibal2.skyhanni.utils.ItemUtils.name import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.LorenzUtils.addAsSingletonList import at.hannibal2.skyhanni.utils.LorenzUtils.addSelector -import at.hannibal2.skyhanni.utils.NEUInternalName -import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.asInternalName import at.hannibal2.skyhanni.utils.NEUItems import at.hannibal2.skyhanni.utils.NEUItems.getItemStack -import at.hannibal2.skyhanni.utils.NEUItems.getNpcPriceOrNull -import at.hannibal2.skyhanni.utils.NEUItems.getPrice import at.hannibal2.skyhanni.utils.NumberUtil import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators import at.hannibal2.skyhanni.utils.NumberUtil.formatNumber import at.hannibal2.skyhanni.utils.RenderUtils.renderStringsAndItems -import at.hannibal2.skyhanni.utils.StringUtils.matchMatcher -import at.hannibal2.skyhanni.utils.StringUtils.removeColor import at.hannibal2.skyhanni.utils.renderables.Renderable -import net.minecraft.item.ItemStack import net.minecraftforge.fml.common.eventhandler.SubscribeEvent -class SackDisplay { - - companion object { - var inInventory = false - var isRuneSack = false - var isGemstoneSack = false - var isTrophySack = false - var sackRarity: TrophyRarity? = null - } - - private val config get() = SkyHanniMod.feature.inventory.sackDisplay +object SackDisplay { private var display = emptyList>() - private val sackItem = mutableMapOf() - private val runeItem = mutableMapOf() - private val gemstoneItem = mutableMapOf() - private val sackPattern = "^(.* Sack|Enchanted .* Sack)$".toPattern() - private val stackList = mutableMapOf() - private val gemstoneMap = mapOf( - "Jade Gemstones" to "ROUGH_JADE_GEM".asInternalName(), - "Amber Gemstones" to "ROUGH_AMBER_GEM".asInternalName(), - "Topaz Gemstones" to "ROUGH_TOPAZ_GEM".asInternalName(), - "Sapphire Gemstones" to "ROUGH_SAPPHIRE_GEM".asInternalName(), - "Amethyst Gemstones" to "ROUGH_AMETHYST_GEM".asInternalName(), - "Jasper Gemstones" to "ROUGH_JASPER_GEM".asInternalName(), - "Ruby Gemstones" to "ROUGH_RUBY_GEM".asInternalName(), - "Opal Gemstones" to "ROUGH_OPAL_GEM".asInternalName(), - ) - private val MAGMA_FISH = "MAGMA_FISH".asInternalName() - - private val numPattern = - "(?:(?:§[0-9a-f](?I{1,3})§7:)?|(?:§7Stored:)?) (?§[0-9a-f])(?[0-9.,kKmMbB]+)§7/(?\\d+(?:[0-9.,]+)?[kKmMbB]?)".toPattern() - private val gemstonePattern = - " §[0-9a-f](?[A-z]*): §[0-9a-f](?\\d+(?:\\.\\d+)?(?:(?:,\\d+)?)+[kKmM]?)(?: §[0-9a-f]\\(\\d+(?:\\.\\d+)?(?:(?:,\\d+)?)+[kKmM]?\\))?".toPattern() + private val config get() = SkyHanniMod.feature.inventory.sackDisplay @SubscribeEvent fun onBackgroundDraw(event: GuiRenderEvent.ChestBackgroundRenderEvent) { - if (inInventory) { + if (SackAPI.inSackInventory) { + if (!isEnabled()) return config.position.renderStringsAndItems( - display, - extraSpace = config.extraSpace, - itemScale = 1.3, - posLabel = "Sacks Items" + display, extraSpace = config.extraSpace, itemScale = 1.3, posLabel = "Sacks Items" ) } } - private fun update() { - display = drawDisplay() + fun update(savingSacks: Boolean) { + display = drawDisplay(savingSacks) } - private fun init() { - for ((_, stack) in stackList) { - val name = stack.name ?: continue - val lore = stack.getLore() - val gem = Gemstone() - val rune = Rune() - val item = Item() - loop@ for (line in lore) { - if (isGemstoneSack) { - gemstonePattern.matchMatcher(line) { - val rarity = group("gemrarity") - val stored = group("stored") - gem.internalName = gemstoneMap[name.removeColor()] ?: NEUInternalName.NONE - if (gemstoneMap.containsKey(name.removeColor())) { - val internalName = "${rarity.uppercase()}_${ - name.uppercase().split(" ")[0].removeColor() - }_GEM".asInternalName() - - when (rarity) { - "Rough" -> { - gem.rough = stored - gem.roughPrice = internalName.sackPrice(stored) - } - - "Flawed" -> { - gem.flawed = stored - gem.flawedPrice = internalName.sackPrice(stored) - } - - "Fine" -> { - gem.fine = stored - gem.finePrice = internalName.sackPrice(stored) - } - - "Flawless" -> { - gem.flawless = stored - gem.flawlessPrice = internalName.sackPrice(stored) - } - } - gemstoneItem[name] = gem - } - } - } else { - numPattern.matchMatcher(line) { - val stored = group("stored") - val internalName = stack.getInternalName() - item.internalName = internalName - item.colorCode = group("color") - item.stored = stored - item.total = group("total") - item.price = if (isTrophySack) { - val trophyName = - internalName.asString().lowercase().substringBeforeLast("_").replace("_", "") - val filletValue = - TrophyFishManager.getInfoByName(trophyName)?.getFilletValue(sackRarity!!) ?: 0 - val storedNumber = stored.formatNumber().toInt() - MAGMA_FISH.sackPrice((filletValue * storedNumber).toString()) - } else internalName.sackPrice(stored).coerceAtLeast(0) - - if (isRuneSack) { - val level = group("level") - rune.stack = stack - if (level == "I") { - rune.lvl1 = stored - continue@loop - } - if (level == "II") { - rune.lvl2 = stored - continue@loop - } - if (level == "III") { - rune.lvl3 = stored - } - runeItem.put(name, rune) - } else { - sackItem.put(name, item) - } - } - } - } - } - } - - private fun drawDisplay(): List> { + private fun drawDisplay(savingSacks: Boolean): List> { val newDisplay = mutableListOf>() var totalPrice = 0 var rendered = 0 - init() - - if (sackItem.isNotEmpty()) { - val sortedPairs: MutableMap = when (config.sortingType) { - 0 -> sackItem.toList().sortedByDescending { it.second.stored.formatNumber() }.toMap().toMutableMap() - 1 -> sackItem.toList().sortedBy { it.second.stored.formatNumber() }.toMap().toMutableMap() - 2 -> sackItem.toList().sortedByDescending { it.second.price }.toMap().toMutableMap() - 3 -> sackItem.toList().sortedBy { it.second.price }.toMap().toMutableMap() - else -> sackItem.toList().sortedByDescending { it.second.stored.formatNumber() }.toMap().toMutableMap() + SackAPI.getSacksData(savingSacks) + + if (SackAPI.sackItem.isNotEmpty()) { + val sortedPairs: MutableMap = when (config.sortingType) { + 0 -> SackAPI.sackItem.toList().sortedByDescending { it.second.stored.formatNumber() }.toMap().toMutableMap() + 1 -> SackAPI.sackItem.toList().sortedBy { it.second.stored.formatNumber() }.toMap().toMutableMap() + 2 -> SackAPI.sackItem.toList().sortedByDescending { it.second.price }.toMap().toMutableMap() + 3 -> SackAPI.sackItem.toList().sortedBy { it.second.price }.toMap().toMutableMap() + else -> SackAPI.sackItem.toList().sortedByDescending { it.second.stored.formatNumber() }.toMap().toMutableMap() } sortedPairs.toList().forEach { @@ -195,12 +67,10 @@ class SackDisplay { newDisplay.add(buildList { add(" §7- ") add(itemStack) - if (!isTrophySack) - add(Renderable.optionalLink("${itemName.replace("§k", "")}: ", { - BazaarApi.searchForBazaarItem(itemName) - }) { !NEUItems.neuHasFocus() }) - else - add("${itemName.replace("§k", "")}: ") + if (!SackAPI.isTrophySack) add(Renderable.optionalLink("${itemName.replace("§k", "")}: ", { + BazaarApi.searchForBazaarItem(itemName) + }) { !NEUItems.neuHasFocus() }) + else add("${itemName.replace("§k", "")}: ") add( when (config.numberFormat) { @@ -211,10 +81,8 @@ class SackDisplay { } ) - if (colorCode == "§a") - add(" §c§l(Full!)") - if (config.showPrice && price != 0) - add(" §7(§6${format(price)}§7)") + if (colorCode == "§a") add(" §c§l(Full!)") + if (config.showPrice && price != 0) add(" §7(§6${format(price)}§7)") }) rendered++ } @@ -222,31 +90,29 @@ class SackDisplay { val name = SortType.entries[config.sortingType].longName newDisplay.addAsSingletonList("§7Sorted By: §c$name") - newDisplay.addSelector( - " ", + newDisplay.addSelector(" ", getName = { type -> type.shortName }, isCurrent = { it.ordinal == config.sortingType }, onChange = { config.sortingType = it.ordinal - update() + update(false) }) if (config.showPrice) { newDisplay.addAsSingletonList("§cTotal price: §6${format(totalPrice)}") - newDisplay.addSelector( - " ", + newDisplay.addSelector(" ", getName = { type -> type.displayName }, isCurrent = { it.ordinal == config.priceFrom }, onChange = { config.priceFrom = it.ordinal - update() + update(false) }) } } - if (runeItem.isNotEmpty()) { + if (SackAPI.runeItem.isNotEmpty()) { newDisplay.addAsSingletonList("§7Runes:") - for ((name, rune) in runeItem) { + for ((name, rune) in SackAPI.runeItem) { val list = mutableListOf() val (stack, lv1, lv2, lv3) = rune list.add(" §7- ") @@ -257,9 +123,9 @@ class SackDisplay { } } - if (gemstoneItem.isNotEmpty()) { + if (SackAPI.gemstoneItem.isNotEmpty()) { newDisplay.addAsSingletonList("§7Gemstones:") - for ((name, gem) in gemstoneItem) { + for ((name, gem) in SackAPI.gemstoneItem) { val (internalName, rough, flawed, fine, flawless, roughprice, flawedprice, fineprice, flawlessprice) = gem newDisplay.add(buildList { add(" §7- ") @@ -270,109 +136,27 @@ class SackDisplay { add(" ($rough-§a$flawed-§9$fine-§5$flawless)") val price = (roughprice + flawedprice + fineprice + flawlessprice) totalPrice += price - if (config.showPrice && price != 0) - add(" §7(§6${format(price)}§7)") + if (config.showPrice && price != 0) add(" §7(§6${format(price)}§7)") }) } - if (config.showPrice) - newDisplay.addAsSingletonList("§eTotal price: §6${format(totalPrice)}") + if (config.showPrice) newDisplay.addAsSingletonList("§eTotal price: §6${format(totalPrice)}") } return newDisplay } private fun format(price: Int) = if (config.priceFormat == 0) NumberUtil.format(price) else price.addSeparators() - @SubscribeEvent - fun onInventoryClose(event: InventoryCloseEvent) { - inInventory = false - isRuneSack = false - isGemstoneSack = false - isTrophySack = false - runeItem.clear() - gemstoneItem.clear() - sackItem.clear() - stackList.clear() - } - - @SubscribeEvent - fun onInventoryOpen(event: InventoryFullyOpenedEvent) { - if (!isEnabled()) return - val inventoryName = event.inventoryName - val match = sackPattern.matcher(inventoryName).matches() - if (!match) return - val stacks = event.inventoryItems - isRuneSack = inventoryName == "Runes Sack" - isGemstoneSack = inventoryName == "Gemstones Sack" - isTrophySack = inventoryName.contains("Trophy Fishing Sack") - sackRarity = inventoryName.getTrophyRarity() - inInventory = true - stackList.putAll(stacks) - update() - } - - - data class Gemstone( - var internalName: NEUInternalName = NEUInternalName.NONE, - var rough: String = "0", - var flawed: String = "0", - var fine: String = "0", - var flawless: String = "0", - var roughPrice: Int = 0, - var flawedPrice: Int = 0, - var finePrice: Int = 0, - var flawlessPrice: Int = 0, - ) - - data class Rune( - var stack: ItemStack? = null, - var lvl1: String = "0", - var lvl2: String = "0", - var lvl3: String = "0", - ) - - data class Item( - var internalName: NEUInternalName = NEUInternalName.NONE, - var colorCode: String = "", - var stored: String = "0", - var total: String = "0", - var price: Int = 0, - ) - private fun isEnabled() = LorenzUtils.inSkyBlock && config.enabled - private fun NEUInternalName.sackPrice(stored: String) = when (config.priceFrom) { - 0 -> (getPrice(true) * stored.formatNumber()).toInt().let { if (it < 0) 0 else it } - - 1 -> try { - val npcPrice = getNpcPriceOrNull() ?: 0.0 - (npcPrice * stored.formatNumber()).toInt() - } catch (e: Exception) { - 0 - } - - else -> 0 - } - enum class SortType(val shortName: String, val longName: String) { STORED_DESC("Stored D", "Stored Descending"), STORED_ASC("Stored A", "Stored Ascending"), PRICE_DESC("Price D", "Price Descending"), - PRICE_ASC("Price A", "Price Ascending"), - ; + PRICE_ASC("Price A", "Price Ascending"),; } enum class PriceFrom(val displayName: String) { BAZAAR("Bazaar Price"), - NPC("Npc Price"), - ; - } - - private fun String.getTrophyRarity(): TrophyRarity? { - return if (this.startsWith("Bronze")) - TrophyRarity.BRONZE - else - if (this.startsWith("Silver")) - TrophyRarity.SILVER - else null + NPC("Npc Price"),; } -} +} \ No newline at end of file -- cgit