aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/at
diff options
context:
space:
mode:
authorCalMWolfs <94038482+CalMWolfs@users.noreply.github.com>2023-09-10 18:40:56 +1000
committerGitHub <noreply@github.com>2023-09-10 10:40:56 +0200
commit593c01992afe4e8d5d4cd8aa61abbfb1d82e2a30 (patch)
tree5e9941862992f014b68dea6420d169be352c6295 /src/main/java/at
parent7e6a2296142e811f77049c0b4080bbd00cd29692 (diff)
downloadskyhanni-593c01992afe4e8d5d4cd8aa61abbfb1d82e2a30.tar.gz
skyhanni-593c01992afe4e8d5d4cd8aa61abbfb1d82e2a30.tar.bz2
skyhanni-593c01992afe4e8d5d4cd8aa61abbfb1d82e2a30.zip
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
Diffstat (limited to 'src/main/java/at')
-rw-r--r--src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt11
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/ConfigManager.kt48
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/SackData.java26
-rw-r--r--src/main/java/at/hannibal2/skyhanni/data/ProfileStorageData.kt26
-rw-r--r--src/main/java/at/hannibal2/skyhanni/data/SackAPI.kt291
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/inventory/SackDisplay.kt290
6 files changed, 430 insertions, 262 deletions
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<Features>
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<UUID, PlayerSpecific> players = new HashMap<>();
+
+ public static class PlayerSpecific {
+ @Expose
+ public Map<String, ProfileSpecific> profiles = new HashMap<>();
+ }
+
+ public static class ProfileSpecific {
+
+ @Expose
+ public Map<NEUInternalName, SackItem> 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 (?<name>.*)\\.\\.\\.".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(?<name>.*)".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](?<level>I{1,3})§7:)?|(?:§7Stored:)?) (?<color>§[0-9a-f])(?<stored>[0-9.,kKmMbB]+)§7/(?<total>\\d+(?:[0-9.,]+)?[kKmMbB]?)".toPattern()
+ private val gemstonePattern =
+ " §[0-9a-f](?<gemrarity>[A-z]*): §[0-9a-f](?<stored>\\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<String, SackOtherItem>()
+ val runeItem = mutableMapOf<String, SackRune>()
+ val gemstoneItem = mutableMapOf<String, SackGemstone>()
+ private val stackList = mutableMapOf<Int, ItemStack>()
+
+ @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<NEUInternalName, SackItem>()
data class SackChange(val delta: Int, val internalName: NEUInternalName, val sacks: List<String>)
@@ -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<NEUInternalName, Int>()
+
+ 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<List<Any>>()
- private val sackItem = mutableMapOf<String, Item>()
- private val runeItem = mutableMapOf<String, Rune>()
- private val gemstoneItem = mutableMapOf<String, Gemstone>()
- private val sackPattern = "^(.* Sack|Enchanted .* Sack)$".toPattern()
- private val stackList = mutableMapOf<Int, ItemStack>()
- 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](?<level>I{1,3})§7:)?|(?:§7Stored:)?) (?<color>§[0-9a-f])(?<stored>[0-9.,kKmMbB]+)§7/(?<total>\\d+(?:[0-9.,]+)?[kKmMbB]?)".toPattern()
- private val gemstonePattern =
- " §[0-9a-f](?<gemrarity>[A-z]*): §[0-9a-f](?<stored>\\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<List<Any>> {
+ private fun drawDisplay(savingSacks: Boolean): List<List<Any>> {
val newDisplay = mutableListOf<List<Any>>()
var totalPrice = 0
var rendered = 0
- init()
-
- if (sackItem.isNotEmpty()) {
- val sortedPairs: MutableMap<String, Item> = 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<String, SackAPI.SackOtherItem> = 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<SortType>(
- " ",
+ newDisplay.addSelector<SortType>(" ",
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<PriceFrom>(
- " ",
+ newDisplay.addSelector<PriceFrom>(" ",
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<Any>()
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