From 96ecad21a9605c4469a070bde41fa00feb9eb144 Mon Sep 17 00:00:00 2001 From: martimavocado Date: Fri, 27 Sep 2024 00:36:19 +0100 Subject: [PATCH 01/91] do most of tab detection --- .../java/at/hannibal2/skyhanni/data/PetAPI.kt | 101 ++++++++++++++++++ .../events/skyblock/PetChangeEvent.kt | 6 ++ .../hannibal2/skyhanni/utils/LorenzRarity.kt | 2 + 3 files changed, 109 insertions(+) create mode 100644 src/main/java/at/hannibal2/skyhanni/events/skyblock/PetChangeEvent.kt diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index d79320603e76..719a22cfe563 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -1,9 +1,15 @@ package at.hannibal2.skyhanni.data +import at.hannibal2.skyhanni.data.model.TabWidget +import at.hannibal2.skyhanni.events.DebugDataCollectEvent +import at.hannibal2.skyhanni.events.WidgetUpdateEvent import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule +import at.hannibal2.skyhanni.utils.LorenzRarity +import at.hannibal2.skyhanni.utils.NEUInternalName import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.RegexUtils.matches import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent @SkyHanniModule object PetAPI { @@ -13,6 +19,17 @@ object PetAPI { "Pets(?: \\(\\d+/\\d+\\) )?", ) + private var rawPetName: String? = null + private var petEquipped = false + + private var petName: String? = null + private var petRarity: LorenzRarity? = null + private var petHasSkin: Boolean? = null + private var petItem: NEUInternalName? = null + + private var petLevel: Int? = null + private var petXP: Double? = null + /** * REGEX-TEST: §e⭐ §7[Lvl 200] §6Golden Dragon§d ✦ * REGEX-TEST: ⭐ [Lvl 100] Black Cat ✦ @@ -26,6 +43,36 @@ object PetAPI { "(?:§f§f)?§7\\[Lvl (?:1➡(?:100|200)|\\{LVL})] (?.*)", ) + /** + * REGEX-TEST: §r§7[Lvl 100] §r§dEndermite + * REGEX-TEST: §r§7[Lvl 200] §r§8[§r§6108§r§8§r§4✦§r§8] §r§6Golden Dragon + * REGEX-TEST: §r§7[Lvl 100] §r§dBlack Cat§r§d ✦ + */ + private val petWidget by patternGroup.pattern( + "widget.pet", + "^ §r§7\\[Lvl (?\\d+)](?: (?:§.)+\\[(?:§.)+(?\\d+)(?:§.)+✦(?:§.)+])? §r§(?.)(?[\\w ]+)(?:§r(?§. ✦))?\$", + ) + + /** + * REGEX-TEST: §r§7No pet selected + * REGEX-TEST: §r§6Washed-up Souvenir + * REGEX-TEST: §r§9Dwarf Turtle Shelmet + */ + private val widgetString by patternGroup.pattern( + "widget.string", + "^ §r§.(?[\\w -]+)\$", + ) + + /** + * REGEX-TEST: §r§b§lMAX LEVEL + * REGEX-TEST: §r§6+§r§e21,248,020.7 XP + * REGEX-TEST: §r§e15,986.6§r§6/§r§e29k XP §r§6(53.6%) + */ + private val xpWidget by patternGroup.pattern( + "widget.xp", + "^ §r§.(?:§l(?MAX LEVEL)|\\+§r§e(?[\\d,.]+) XP|(?[\\d,.]+)§r§6/§r§e(?[\\d.km]+) XP §r§6\\((?[\\d.%]+)\\))$", + ) + private val ignoredPetStrings = listOf( "Archer", "Berserk", @@ -62,4 +109,58 @@ object PetAPI { } fun hasPetName(name: String): Boolean = petItemName.matches(name) && !ignoredPetStrings.any { name.contains(it) } + + @SubscribeEvent + fun onTabUpdate(event: WidgetUpdateEvent) { + if (!event.isWidget(TabWidget.PET)) return + + val newPetLine = event.lines.getOrNull(1) ?: return + if (newPetLine == rawPetName) return + + rawPetName = newPetLine + + widgetString.matchMatcher(newPetLine) { + val string = group("string") + if (string == "No pet selected") { + removePet() + return + } + petItem = NEUInternalName.fromItemNameOrNull(string) + } + + petWidget.matchMatcher(newPetLine) { + petEquipped = true + petName = group("name") + petRarity = LorenzRarity.getByColorCode(group("rarity")[0]) + petLevel = group("level").toInt() + petHasSkin = group("skin") != null + return + } + + xpWidget.matchMatcher(newPetLine) { + //i don't feel like doing this right now + } + } + + private fun removePet() { + petName = null + petLevel = null + petRarity = null + petHasSkin = null + petEquipped = false + petItem = null + } + + @SubscribeEvent + fun onDebug(event: DebugDataCollectEvent) { + event.title("PetAPI") + event.addIrrelevant { + add("petName: '$petName'") + add("petRarity: '$petRarity'") + add("petLevel: '$petLevel'") + add("petHasSkin: '$petHasSkin'") + add("petEquipped: '$petEquipped'") + add("petItem: '$petItem'") + } + } } diff --git a/src/main/java/at/hannibal2/skyhanni/events/skyblock/PetChangeEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/skyblock/PetChangeEvent.kt new file mode 100644 index 000000000000..1f10bedaf56b --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/events/skyblock/PetChangeEvent.kt @@ -0,0 +1,6 @@ +package at.hannibal2.skyhanni.events.skyblock + +import at.hannibal2.skyhanni.api.event.SkyHanniEvent +import at.hannibal2.skyhanni.utils.LorenzRarity + +class PetChangeEvent(val petName: String, val petLevel: Int, val petRarity: LorenzRarity) : SkyHanniEvent() diff --git a/src/main/java/at/hannibal2/skyhanni/utils/LorenzRarity.kt b/src/main/java/at/hannibal2/skyhanni/utils/LorenzRarity.kt index cc0e20efef98..93415947f8c8 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/LorenzRarity.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/LorenzRarity.kt @@ -52,5 +52,7 @@ enum class LorenzRarity(val color: LorenzColor, val id: Int) { fun getById(id: Int) = if (entries.size > id) entries[id] else null fun getByName(name: String): LorenzRarity? = entries.find { it.name.equals(name, ignoreCase = true) } + + fun getByColorCode(colorCode: Char): LorenzRarity? = entries.find { it.color.chatColorCode == colorCode } } } From d0d41bfbe33ff20ba6e7c4fa50b78ef9803e994e Mon Sep 17 00:00:00 2001 From: martimavocado Date: Fri, 27 Sep 2024 15:55:15 +0100 Subject: [PATCH 02/91] hi empa --- .../java/at/hannibal2/skyhanni/data/PetAPI.kt | 77 +++++++++---------- .../at/hannibal2/skyhanni/data/PetData.kt | 14 ++++ .../events/skyblock/PetChangeEvent.kt | 4 +- 3 files changed, 53 insertions(+), 42 deletions(-) create mode 100644 src/main/java/at/hannibal2/skyhanni/data/PetData.kt diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index 719a22cfe563..40410a4140ed 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -19,16 +19,7 @@ object PetAPI { "Pets(?: \\(\\d+/\\d+\\) )?", ) - private var rawPetName: String? = null - private var petEquipped = false - - private var petName: String? = null - private var petRarity: LorenzRarity? = null - private var petHasSkin: Boolean? = null - private var petItem: NEUInternalName? = null - - private var petLevel: Int? = null - private var petXP: Double? = null + private var pet: PetData? = null /** * REGEX-TEST: §e⭐ §7[Lvl 200] §6Golden Dragon§d ✦ @@ -70,7 +61,7 @@ object PetAPI { */ private val xpWidget by patternGroup.pattern( "widget.xp", - "^ §r§.(?:§l(?MAX LEVEL)|\\+§r§e(?[\\d,.]+) XP|(?[\\d,.]+)§r§6/§r§e(?[\\d.km]+) XP §r§6\\((?[\\d.%]+)\\))$", + "^ §r§.(?:§l(?MAX LEVEL)|\\+§r§e(?[\\d,.]+) XP|(?[\\d,.]+)§r§6/§r§e(?[\\d.km]+) XP §r§6\\((?[\\d.%]+)\\))$", ) private val ignoredPetStrings = listOf( @@ -111,56 +102,62 @@ object PetAPI { fun hasPetName(name: String): Boolean = petItemName.matches(name) && !ignoredPetStrings.any { name.contains(it) } @SubscribeEvent - fun onTabUpdate(event: WidgetUpdateEvent) { + fun onWidgetUpdate(event: WidgetUpdateEvent) { if (!event.isWidget(TabWidget.PET)) return val newPetLine = event.lines.getOrNull(1) ?: return - if (newPetLine == rawPetName) return + if (newPetLine == pet?.rawPetName) return - rawPetName = newPetLine + petWidget.matchMatcher(newPetLine) { + pet = PetData( + group("name"), + LorenzRarity.getByColorCode(group("rarity")[0]) ?: LorenzRarity.ULTIMATE, + NEUInternalName.NONE, + group("skin") != null, + group("level").toInt(), + 0.0, + newPetLine, + ) + } widgetString.matchMatcher(newPetLine) { val string = group("string") if (string == "No pet selected") { - removePet() + pet = null return } - petItem = NEUInternalName.fromItemNameOrNull(string) + pet = pet?.let { + PetData( + it.name, + it.rarity, + NEUInternalName.fromItemNameOrNull(string) ?: NEUInternalName.NONE, + it.hasSkin, + it.level, + it.xp, + it.rawPetName, + ) + } } - petWidget.matchMatcher(newPetLine) { - petEquipped = true - petName = group("name") - petRarity = LorenzRarity.getByColorCode(group("rarity")[0]) - petLevel = group("level").toInt() - petHasSkin = group("skin") != null - return - } xpWidget.matchMatcher(newPetLine) { //i don't feel like doing this right now } } - private fun removePet() { - petName = null - petLevel = null - petRarity = null - petHasSkin = null - petEquipped = false - petItem = null - } - @SubscribeEvent fun onDebug(event: DebugDataCollectEvent) { event.title("PetAPI") - event.addIrrelevant { - add("petName: '$petName'") - add("petRarity: '$petRarity'") - add("petLevel: '$petLevel'") - add("petHasSkin: '$petHasSkin'") - add("petEquipped: '$petEquipped'") - add("petItem: '$petItem'") + if (pet != null) { + event.addIrrelevant { + add("petName: '${pet?.name}'") + add("petRarity: '${pet?.rarity}'") + add("petLevel: '${pet?.level}'") + add("petHasSkin: '${pet?.hasSkin}'") + add("petItem: '${pet?.petItem}'") + } + } else { + event.addData("no pet equipped") } } } diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetData.kt b/src/main/java/at/hannibal2/skyhanni/data/PetData.kt new file mode 100644 index 000000000000..52852479d185 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/PetData.kt @@ -0,0 +1,14 @@ +package at.hannibal2.skyhanni.data + +import at.hannibal2.skyhanni.utils.LorenzRarity +import at.hannibal2.skyhanni.utils.NEUInternalName + +data class PetData( + val name: String, + val rarity: LorenzRarity, + val petItem: NEUInternalName, + val hasSkin: Boolean, + val level: Int, + val xp: Double, + val rawPetName: String, +) diff --git a/src/main/java/at/hannibal2/skyhanni/events/skyblock/PetChangeEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/skyblock/PetChangeEvent.kt index 1f10bedaf56b..074dea9f765f 100644 --- a/src/main/java/at/hannibal2/skyhanni/events/skyblock/PetChangeEvent.kt +++ b/src/main/java/at/hannibal2/skyhanni/events/skyblock/PetChangeEvent.kt @@ -1,6 +1,6 @@ package at.hannibal2.skyhanni.events.skyblock import at.hannibal2.skyhanni.api.event.SkyHanniEvent -import at.hannibal2.skyhanni.utils.LorenzRarity +import at.hannibal2.skyhanni.data.PetData -class PetChangeEvent(val petName: String, val petLevel: Int, val petRarity: LorenzRarity) : SkyHanniEvent() +class PetChangeEvent(val oldPet: PetData, val newPet: PetData) : SkyHanniEvent() From e1745f24f0e8e1789e964846b71ea84eaa07ca66 Mon Sep 17 00:00:00 2001 From: martimavocado Date: Fri, 27 Sep 2024 18:00:23 +0100 Subject: [PATCH 03/91] add petxp calculation --- .../skyhanni/config/commands/Commands.kt | 12 +- .../java/at/hannibal2/skyhanni/data/PetAPI.kt | 185 +++++++++++++++++- 2 files changed, 193 insertions(+), 4 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt b/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt index 9f2e3cc3fd71..1c0c07d30530 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt +++ b/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt @@ -9,6 +9,7 @@ import at.hannibal2.skyhanni.data.ChatManager import at.hannibal2.skyhanni.data.GardenCropMilestonesCommunityFix import at.hannibal2.skyhanni.data.GuiEditManager import at.hannibal2.skyhanni.data.PartyAPI +import at.hannibal2.skyhanni.data.PetAPI import at.hannibal2.skyhanni.data.SackAPI import at.hannibal2.skyhanni.data.ScoreboardData import at.hannibal2.skyhanni.data.TitleManager @@ -251,7 +252,8 @@ object Commands { ) { FarmingWeightDisplay.lookUpCommand(it) } registerCommand( "shcopytranslation", - "Copy the English translation of a message in another language to the clipboard.\n" + "Uses a 2 letter language code that can be found at the end of a translation message.", + "Copy the English translation of a message in another language to the clipboard.\n" + + "Uses a 2 letter language code that can be found at the end of a translation message.", ) { Translator.fromEnglish(it) } registerCommand( "shtranslate", @@ -500,6 +502,10 @@ object Commands { "shdebugscoreboard", "Monitors the scoreboard changes: Prints the raw scoreboard lines in the console after each update, with time since last update.", ) { ScoreboardData.toggleMonitor() } + registerCommand( + "shcalcpetxp", + "Gets the pet xp from a given level and rarity.", + ) { PetAPI.testLeveltoXP(it) } } private fun developersCodingHelp() { @@ -589,7 +595,9 @@ object Commands { ) { TitleManager.command(it) } registerCommand( "shresetconfig", - "Reloads the config manager and rendering processors of MoulConfig. " + "This §cWILL RESET §7your config, but also updating the java config files " + "(names, description, orderings and stuff).", + "Reloads the config manager and rendering processors of MoulConfig. " + + "This §cWILL RESET §7your config, but also updating the java config files " + + "(names, description, orderings and stuff).", ) { SkyHanniDebugsAndTests.resetConfigCommand() } registerCommand( "shreadcropmilestonefromclipboard", diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index 40410a4140ed..ba040ddc682a 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -4,8 +4,10 @@ import at.hannibal2.skyhanni.data.model.TabWidget import at.hannibal2.skyhanni.events.DebugDataCollectEvent import at.hannibal2.skyhanni.events.WidgetUpdateEvent import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule +import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.LorenzRarity import at.hannibal2.skyhanni.utils.NEUInternalName +import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.RegexUtils.matches import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern @@ -152,12 +154,191 @@ object PetAPI { event.addIrrelevant { add("petName: '${pet?.name}'") add("petRarity: '${pet?.rarity}'") - add("petLevel: '${pet?.level}'") - add("petHasSkin: '${pet?.hasSkin}'") add("petItem: '${pet?.petItem}'") + add("petHasSkin: '${pet?.hasSkin}'") + add("petLevel: '${pet?.level}'") + add("petXP: '${pet?.xp}'") } } else { event.addData("no pet equipped") } } + + //taken from NEU + //move to repo + private val pet_levels = arrayOf( + 100, + 110, + 120, + 130, + 145, + 160, + 175, + 190, + 210, + 230, + 250, + 275, + 300, + 330, + 360, + 400, + 440, + 490, + 540, + 600, + 660, + 730, + 800, + 880, + 960, + 1050, + 1150, + 1260, + 1380, + 1510, + 1650, + 1800, + 1960, + 2130, + 2310, + 2500, + 2700, + 2920, + 3160, + 3420, + 3700, + 4000, + 4350, + 4750, + 5200, + 5700, + 6300, + 7000, + 7800, + 8700, + 9700, + 10800, + 12000, + 13300, + 14700, + 16200, + 17800, + 19500, + 21300, + 23200, + 25200, + 27400, + 29800, + 32400, + 35200, + 38200, + 41400, + 44800, + 48400, + 52200, + 56200, + 60400, + 64800, + 69400, + 74200, + 79200, + 84700, + 90700, + 97200, + 104200, + 111700, + 119700, + 128200, + 137200, + 146700, + 156700, + 167700, + 179700, + 192700, + 206700, + 221700, + 237700, + 254700, + 272700, + 291700, + 311700, + 333700, + 357700, + 383700, + 411700, + 441700, + 476700, + 516700, + 561700, + 611700, + 666700, + 726700, + 791700, + 861700, + 936700, + 1016700, + 1101700, + 1191700, + 1286700, + 1386700, + 1496700, + 1616700, + 1746700, + 1886700 + ) + + fun testLeveltoXP(input: Array) { + if (input.size == 3) { + val level = input[0].toIntOrNull() + val rarity = LorenzRarity.getByName(input[1]) + val isGoldenDragon = input[2].toBooleanStrictOrNull() + if (level != null && rarity != null && isGoldenDragon != null) { + val xp: Int = levelToXP(level, rarity, isGoldenDragon) ?: run { + ChatUtils.chat("bad input. invalid rarity or level") + return + } + ChatUtils.chat(xp.addSeparators()) + return + } + } + ChatUtils.chat("bad usage. /shcalcpetxp ") + } + + private fun levelToXP(level: Int, rarity: LorenzRarity, isGoldenDragon: Boolean = false): Int? { + val rarityOffset = getRarityOffset(rarity) ?: return null + if (!isValidLevel(level, isGoldenDragon)) return null + + return if (isGoldenDragon && level > 100) { + pet_levels.slice(0 + rarityOffset..<100 + rarityOffset - 1).sum() + getGdragXP(level - 100) + } else { + pet_levels.slice(0 + rarityOffset.. 0 + 2 -> 5555 + else -> 5555 + (levelAbove100 - 2) * 1886700 + } + } + + private fun getRarityOffset(rarity: LorenzRarity): Int? = when (rarity) { + LorenzRarity.COMMON -> 0 + LorenzRarity.UNCOMMON -> 6 + LorenzRarity.RARE -> 11 + LorenzRarity.EPIC -> 16 + LorenzRarity.LEGENDARY -> 20 + LorenzRarity.MYTHIC -> 20 + else -> { + ChatUtils.chat("bad rarity. ${rarity.name}") + null + } + } } From 14294c51aa523800616e4fc516404534d9525b00 Mon Sep 17 00:00:00 2001 From: martimavocado Date: Fri, 27 Sep 2024 18:24:15 +0100 Subject: [PATCH 04/91] finish widget detection --- .../java/at/hannibal2/skyhanni/data/PetAPI.kt | 67 +++++++++++++++---- 1 file changed, 53 insertions(+), 14 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index ba040ddc682a..3dd6cf46ad56 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -110,23 +110,19 @@ object PetAPI { val newPetLine = event.lines.getOrNull(1) ?: return if (newPetLine == pet?.rawPetName) return - petWidget.matchMatcher(newPetLine) { - pet = PetData( - group("name"), - LorenzRarity.getByColorCode(group("rarity")[0]) ?: LorenzRarity.ULTIMATE, - NEUInternalName.NONE, - group("skin") != null, - group("level").toInt(), - 0.0, - newPetLine, - ) + event.lines.forEach { line -> + if (analyseWidgetPetLine(line)) return@forEach + if (analyseWidgetStringLine(line, newPetLine)) return@forEach + if (analyseWidgetXPLine(line)) return@forEach } + } - widgetString.matchMatcher(newPetLine) { + private fun analyseWidgetPetLine(line: String): Boolean { + widgetString.matchMatcher(line) { val string = group("string") if (string == "No pet selected") { pet = null - return + return true } pet = pet?.let { PetData( @@ -139,12 +135,55 @@ object PetAPI { it.rawPetName, ) } + return true + } + return false + } + + private fun analyseWidgetStringLine(line: String, newPetLine: String): Boolean { + petWidget.matchMatcher(line) { + val xp = levelToXP( + group("level").toInt(), + LorenzRarity.getByColorCode(group("rarity")[0]) ?: LorenzRarity.ULTIMATE, + group("name").contains("Golden Dragon") + ) + pet = PetData( + group("name"), + LorenzRarity.getByColorCode(group("rarity")[0]) ?: LorenzRarity.ULTIMATE, + NEUInternalName.NONE, + group("skin") != null, + group("level").toInt(), + xp?.toDouble() ?: 0.0, + newPetLine, + ) + return true } + return false + } + + private fun analyseWidgetXPLine(line: String): Boolean { + xpWidget.matchMatcher(line) { + if (group("max") != null) return true + + val overflow = group("overflow")?.replace(",", "")?.toDoubleOrNull() ?: 0.0 + val currentXP = group("currentXP")?.replace(",", "")?.toDoubleOrNull() ?: 0.0 + val xp = overflow + currentXP - xpWidget.matchMatcher(newPetLine) { - //i don't feel like doing this right now + pet = pet?.let { + PetData( + it.name, + it.rarity, + it.petItem, + it.hasSkin, + it.level, + levelToXP(it.level, it.rarity, it.name.contains("Golden Dragon"))?.plus(xp) ?: 0.0, + it.rawPetName, + ) + } + return true } + return false } @SubscribeEvent From de154f60a26c05b54d2a27d7be80f7f818b15e10 Mon Sep 17 00:00:00 2001 From: martimavocado Date: Fri, 27 Sep 2024 18:29:39 +0100 Subject: [PATCH 05/91] fix function names --- src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index 3dd6cf46ad56..6caa9c041c2d 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -111,13 +111,13 @@ object PetAPI { if (newPetLine == pet?.rawPetName) return event.lines.forEach { line -> - if (analyseWidgetPetLine(line)) return@forEach - if (analyseWidgetStringLine(line, newPetLine)) return@forEach + if (analyseWidgetPetLine(line, newPetLine)) return@forEach + if (analyseWidgetStringLine(line)) return@forEach if (analyseWidgetXPLine(line)) return@forEach } } - private fun analyseWidgetPetLine(line: String): Boolean { + private fun analyseWidgetStringLine(line: String): Boolean { widgetString.matchMatcher(line) { val string = group("string") if (string == "No pet selected") { @@ -140,7 +140,7 @@ object PetAPI { return false } - private fun analyseWidgetStringLine(line: String, newPetLine: String): Boolean { + private fun analyseWidgetPetLine(line: String, newPetLine: String): Boolean { petWidget.matchMatcher(line) { val xp = levelToXP( group("level").toInt(), @@ -334,14 +334,14 @@ object PetAPI { val isGoldenDragon = input[2].toBooleanStrictOrNull() if (level != null && rarity != null && isGoldenDragon != null) { val xp: Int = levelToXP(level, rarity, isGoldenDragon) ?: run { - ChatUtils.chat("bad input. invalid rarity or level") + ChatUtils.userError("bad input. invalid rarity or level") return } ChatUtils.chat(xp.addSeparators()) return } } - ChatUtils.chat("bad usage. /shcalcpetxp ") + ChatUtils.userError("bad usage. /shcalcpetxp ") } private fun levelToXP(level: Int, rarity: LorenzRarity, isGoldenDragon: Boolean = false): Int? { @@ -376,7 +376,7 @@ object PetAPI { LorenzRarity.LEGENDARY -> 20 LorenzRarity.MYTHIC -> 20 else -> { - ChatUtils.chat("bad rarity. ${rarity.name}") + ChatUtils.userError("bad rarity. ${rarity.name}") null } } From 847a96d42e1f78c90fc0432fc35a26c45638760c Mon Sep 17 00:00:00 2001 From: martimavocado Date: Fri, 27 Sep 2024 18:56:14 +0100 Subject: [PATCH 06/91] fix pet item detection --- .../java/at/hannibal2/skyhanni/data/PetAPI.kt | 97 ++++++++++--------- .../events/skyblock/PetChangeEvent.kt | 2 +- 2 files changed, 52 insertions(+), 47 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index 6caa9c041c2d..857325d7eff3 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -1,8 +1,10 @@ package at.hannibal2.skyhanni.data +import at.hannibal2.skyhanni.api.event.HandleEvent import at.hannibal2.skyhanni.data.model.TabWidget import at.hannibal2.skyhanni.events.DebugDataCollectEvent import at.hannibal2.skyhanni.events.WidgetUpdateEvent +import at.hannibal2.skyhanni.events.skyblock.PetChangeEvent import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.LorenzRarity @@ -53,7 +55,7 @@ object PetAPI { */ private val widgetString by patternGroup.pattern( "widget.string", - "^ §r§.(?[\\w -]+)\$", + "^ §r(?§.[\\w -]+)\$", ) /** @@ -107,60 +109,57 @@ object PetAPI { fun onWidgetUpdate(event: WidgetUpdateEvent) { if (!event.isWidget(TabWidget.PET)) return - val newPetLine = event.lines.getOrNull(1) ?: return + val newPetLine = event.lines.getOrNull(1)?.removePrefix(" ") ?: return if (newPetLine == pet?.rawPetName) return + var petItem = NEUInternalName.NONE event.lines.forEach { line -> - if (analyseWidgetPetLine(line, newPetLine)) return@forEach - if (analyseWidgetStringLine(line)) return@forEach - if (analyseWidgetXPLine(line)) return@forEach + petItem = analyseWidgetStringLine(line) + if (petItem != NEUInternalName.NONE) return@forEach } - } - private fun analyseWidgetStringLine(line: String): Boolean { - widgetString.matchMatcher(line) { - val string = group("string") - if (string == "No pet selected") { - pet = null - return true - } - pet = pet?.let { - PetData( - it.name, - it.rarity, - NEUInternalName.fromItemNameOrNull(string) ?: NEUInternalName.NONE, - it.hasSkin, - it.level, - it.xp, - it.rawPetName, - ) - } - return true + event.lines.forEach { line -> + if (analyseWidgetPetLine(line, petItem, newPetLine)) return@forEach + if (analyseWidgetXPLine(line)) return@forEach } - return false } - private fun analyseWidgetPetLine(line: String, newPetLine: String): Boolean { + private fun analyseWidgetPetLine(line: String, petItem: NEUInternalName, newPetLine: String): Boolean { petWidget.matchMatcher(line) { val xp = levelToXP( group("level").toInt(), LorenzRarity.getByColorCode(group("rarity")[0]) ?: LorenzRarity.ULTIMATE, group("name").contains("Golden Dragon") ) - pet = PetData( + val newPet = PetData( group("name"), LorenzRarity.getByColorCode(group("rarity")[0]) ?: LorenzRarity.ULTIMATE, - NEUInternalName.NONE, + petItem, group("skin") != null, group("level").toInt(), xp?.toDouble() ?: 0.0, newPetLine, ) + PetChangeEvent(pet, newPet).post() + pet = newPet return true } return false } + private fun analyseWidgetStringLine(line: String): NEUInternalName { + widgetString.matchMatcher(line) { + val string = group("string") + if (string == "No pet selected") { + PetChangeEvent(pet, null).post() + pet = null + return NEUInternalName.NONE + } + return NEUInternalName.fromItemNameOrNull(string) ?: NEUInternalName.NONE + } + return NEUInternalName.NONE + } + private fun analyseWidgetXPLine(line: String): Boolean { xpWidget.matchMatcher(line) { if (group("max") != null) return true @@ -186,23 +185,6 @@ object PetAPI { return false } - @SubscribeEvent - fun onDebug(event: DebugDataCollectEvent) { - event.title("PetAPI") - if (pet != null) { - event.addIrrelevant { - add("petName: '${pet?.name}'") - add("petRarity: '${pet?.rarity}'") - add("petItem: '${pet?.petItem}'") - add("petHasSkin: '${pet?.hasSkin}'") - add("petLevel: '${pet?.level}'") - add("petXP: '${pet?.xp}'") - } - } else { - event.addData("no pet equipped") - } - } - //taken from NEU //move to repo private val pet_levels = arrayOf( @@ -380,4 +362,27 @@ object PetAPI { null } } + + @SubscribeEvent + fun onDebug(event: DebugDataCollectEvent) { + event.title("PetAPI") + if (pet != null) { + event.addIrrelevant { + add("petName: '${pet?.name}'") + add("petRarity: '${pet?.rarity}'") + add("petItem: '${pet?.petItem}'") + add("petHasSkin: '${pet?.hasSkin}'") + add("petLevel: '${pet?.level}'") + add("petXP: '${pet?.xp}'") + add("rawPetLine: '${pet?.rawPetName}'") + } + } else { + event.addData("no pet equipped") + } + } + + @HandleEvent + fun onPetChange(event: PetChangeEvent) { + ChatUtils.debug("oldPet: ${event.oldPet}, newPet: ${event.newPet}") + } } diff --git a/src/main/java/at/hannibal2/skyhanni/events/skyblock/PetChangeEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/skyblock/PetChangeEvent.kt index 074dea9f765f..60ca08dbf963 100644 --- a/src/main/java/at/hannibal2/skyhanni/events/skyblock/PetChangeEvent.kt +++ b/src/main/java/at/hannibal2/skyhanni/events/skyblock/PetChangeEvent.kt @@ -3,4 +3,4 @@ package at.hannibal2.skyhanni.events.skyblock import at.hannibal2.skyhanni.api.event.SkyHanniEvent import at.hannibal2.skyhanni.data.PetData -class PetChangeEvent(val oldPet: PetData, val newPet: PetData) : SkyHanniEvent() +class PetChangeEvent(val oldPet: PetData?, val newPet: PetData?) : SkyHanniEvent() From c408256f016dbfdfcae967207346441f2b36a119 Mon Sep 17 00:00:00 2001 From: martimavocado Date: Fri, 27 Sep 2024 19:09:06 +0100 Subject: [PATCH 07/91] fix petxp on event --- .../java/at/hannibal2/skyhanni/data/PetAPI.kt | 36 +++++++------------ 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index 857325d7eff3..4058f56c3665 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -113,31 +113,34 @@ object PetAPI { if (newPetLine == pet?.rawPetName) return var petItem = NEUInternalName.NONE + var petXP: Double? = null event.lines.forEach { line -> petItem = analyseWidgetStringLine(line) if (petItem != NEUInternalName.NONE) return@forEach + petXP = analyseWidgetXPLine(line) + if (petXP == null) return@forEach } event.lines.forEach { line -> - if (analyseWidgetPetLine(line, petItem, newPetLine)) return@forEach - if (analyseWidgetXPLine(line)) return@forEach + if (analyseWidgetPetLine(line, petItem, petXP, newPetLine)) return@forEach } } - private fun analyseWidgetPetLine(line: String, petItem: NEUInternalName, newPetLine: String): Boolean { + private fun analyseWidgetPetLine(line: String, petItem: NEUInternalName, petXP: Double?, newPetLine: String): Boolean { + val xpOverLevel = petXP ?: 0.0 petWidget.matchMatcher(line) { - val xp = levelToXP( + val xp = (levelToXP( group("level").toInt(), LorenzRarity.getByColorCode(group("rarity")[0]) ?: LorenzRarity.ULTIMATE, group("name").contains("Golden Dragon") - ) + )) val newPet = PetData( group("name"), LorenzRarity.getByColorCode(group("rarity")[0]) ?: LorenzRarity.ULTIMATE, petItem, group("skin") != null, group("level").toInt(), - xp?.toDouble() ?: 0.0, + (xp?.plus(xpOverLevel)) ?: 0.0, newPetLine, ) PetChangeEvent(pet, newPet).post() @@ -160,29 +163,16 @@ object PetAPI { return NEUInternalName.NONE } - private fun analyseWidgetXPLine(line: String): Boolean { + private fun analyseWidgetXPLine(line: String): Double? { xpWidget.matchMatcher(line) { - if (group("max") != null) return true + if (group("max") != null) return null val overflow = group("overflow")?.replace(",", "")?.toDoubleOrNull() ?: 0.0 val currentXP = group("currentXP")?.replace(",", "")?.toDoubleOrNull() ?: 0.0 - val xp = overflow + currentXP - - pet = pet?.let { - PetData( - it.name, - it.rarity, - it.petItem, - it.hasSkin, - it.level, - levelToXP(it.level, it.rarity, it.name.contains("Golden Dragon"))?.plus(xp) ?: 0.0, - it.rawPetName, - ) - } - return true + return overflow + currentXP } - return false + return null } //taken from NEU From c610e8886bb9aec1cdc63b1f1f67696b7aaeebc1 Mon Sep 17 00:00:00 2001 From: martimavocado Date: Fri, 27 Sep 2024 21:36:10 +0100 Subject: [PATCH 08/91] this is my best commit yet --- .../java/at/hannibal2/skyhanni/data/PetAPI.kt | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index 4058f56c3665..d8138c6ded42 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -375,4 +375,96 @@ object PetAPI { fun onPetChange(event: PetChangeEvent) { ChatUtils.debug("oldPet: ${event.oldPet}, newPet: ${event.newPet}") } + + + // { + // "strikethrough": false, + // "hoverEvent": { + // "action": "show_text", + // "value": { + // "bold": false, + // "italic": false, + // "underlined": false, + // "strikethrough": false, + // "obfuscated": false, + // "color": "red", + // "extra": [ + // { + // "bold": false, + // "italic": false, + // "underlined": false, + // "strikethrough": false, + // "obfuscated": false, + // "color": "green", + // "text": "When:\n" + // }, + // { + // "bold": false, + // "italic": false, + // "underlined": false, + // "strikethrough": false, + // "obfuscated": false, + // "color": "gray", + // "text": "You throw a fishing hook.\n\n" + // }, + // { + // "bold": false, + // "italic": false, + // "underlined": false, + // "strikethrough": false, + // "obfuscated": false, + // "color": "green", + // "text": "Equip: " + // }, + // { + // "bold": false, + // "italic": false, + // "underlined": false, + // "strikethrough": false, + // "obfuscated": false, + // "color": "yellow", + // "text": "⭐ " + // }, + // { + // "bold": false, + // "italic": false, + // "underlined": false, + // "strikethrough": false, + // "obfuscated": false, + // "color": "gray", + // "text": "[Lvl 100] " + // }, + // { + // "bold": false, + // "italic": false, + // "underlined": false, + // "strikethrough": false, + // "obfuscated": false, + // "color": "gold", + // "text": "Scatha\n" + // }, + // { + // "bold": false, + // "italic": false, + // "underlined": false, + // "strikethrough": false, + // "obfuscated": false, + // "color": "green", + // "text": "Held Item: " + // }, + // { + // "bold": false, + // "italic": false, + // "underlined": false, + // "strikethrough": false, + // "obfuscated": false, + // "color": "blue", + // "text": "Mining Exp Boost" + // } + // ], + // "text": "Autopet Rule\n\n" + // } + // }, + // "text": "§cAutopet §eequipped your §7[Lvl 100] §6Scatha§e! §a§lVIEW RULE" + // } } From dbac55e0cefdc05d150eff9046ce2762ccf31304 Mon Sep 17 00:00:00 2001 From: martimavocado Date: Sat, 28 Sep 2024 02:32:15 +0100 Subject: [PATCH 09/91] start handling autopet --- .../skyhanni/config/commands/Commands.kt | 2 +- .../java/at/hannibal2/skyhanni/data/PetAPI.kt | 246 ++++++++++-------- 2 files changed, 132 insertions(+), 116 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt b/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt index 1c0c07d30530..dd4d1473da1f 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt +++ b/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt @@ -505,7 +505,7 @@ object Commands { registerCommand( "shcalcpetxp", "Gets the pet xp from a given level and rarity.", - ) { PetAPI.testLeveltoXP(it) } + ) { PetAPI.testLevelToXP(it) } } private fun developersCodingHelp() { diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index d8138c6ded42..9b191390b299 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -3,6 +3,7 @@ package at.hannibal2.skyhanni.data import at.hannibal2.skyhanni.api.event.HandleEvent import at.hannibal2.skyhanni.data.model.TabWidget import at.hannibal2.skyhanni.events.DebugDataCollectEvent +import at.hannibal2.skyhanni.events.LorenzChatEvent import at.hannibal2.skyhanni.events.WidgetUpdateEvent import at.hannibal2.skyhanni.events.skyblock.PetChangeEvent import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule @@ -12,6 +13,7 @@ import at.hannibal2.skyhanni.utils.NEUInternalName import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.RegexUtils.matches +import at.hannibal2.skyhanni.utils.chat.Text.hover import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern import net.minecraftforge.fml.common.eventhandler.SubscribeEvent @@ -68,6 +70,36 @@ object PetAPI { "^ §r§.(?:§l(?MAX LEVEL)|\\+§r§e(?[\\d,.]+) XP|(?[\\d,.]+)§r§6/§r§e(?[\\d.km]+) XP §r§6\\((?[\\d.%]+)\\))$", ) + /** + * REGEX-TEST: §cAutopet §eequipped your §7[Lvl 100] §6Scatha§e! §a§lVIEW RULE + * REGEX-TEST: §cAutopet §eequipped your §7[Lvl 99] §6Flying Fish§e! §a§lVIEW RULE + * REGEX-TEST: §cAutopet §eequipped your §7[Lvl 100] §dBlack Cat§d ✦§e! §a§lVIEW RULE + */ + private val autopetMessage by patternGroup.pattern( + "chat.autopet", + "^§cAutopet §eequipped your §7(?\\[Lvl \\d{1,3}] §.[\\w ]+)(?:§. ✦)?§e! §a§lVIEW RULE\$" + ) + + /** + * REGEX-TEST: §r, §aEquip: §r, §7[Lvl 99] §r, §6Flying Fish + * REGEX-TEST: §r, §aEquip: §r, §e⭐ §r, §7[Lvl 100] §r, §dBlack Cat§r, §d ✦ + * REGEX-TEST: §r, §aEquip: §r, §7[Lvl 47] §r, §5Lion + */ + private val autopetHoverPet by patternGroup.pattern( + "chat.autopet.hover.pet", + "^§r, §aEquip: §r,(?: §e⭐ §r,)? §7\\[Lvl (?\\d+)] §r, §(?.)(?[\\w ]+)(?:§r, (?§. ✦))?\$" + ) + + /** + * REGEX-TEST: §r, §aHeld Item: §r, §9Mining Exp Boost§r] + * REGEX-TEST: §r, §aHeld Item: §r, §5Lucky Clover§r] + * REGEX-TEST: §r, §aHeld Item: §r, §5Fishing Exp Boost§r] + */ + private val autopetHoverPetItem by patternGroup.pattern( + "chat.autopet.hover.item", + "^§r, §aHeld Item: §r, (?§.[\\w -]+)§r]\$" + ) + private val ignoredPetStrings = listOf( "Archer", "Berserk", @@ -105,6 +137,7 @@ object PetAPI { fun hasPetName(name: String): Boolean = petItemName.matches(name) && !ignoredPetStrings.any { name.contains(it) } +// --- @SubscribeEvent fun onWidgetUpdate(event: WidgetUpdateEvent) { if (!event.isWidget(TabWidget.PET)) return @@ -115,18 +148,24 @@ object PetAPI { var petItem = NEUInternalName.NONE var petXP: Double? = null event.lines.forEach { line -> - petItem = analyseWidgetStringLine(line) - if (petItem != NEUInternalName.NONE) return@forEach - petXP = analyseWidgetXPLine(line) - if (petXP == null) return@forEach + val tempPetItem = handleWidgetStringLine(line) + if (tempPetItem != NEUInternalName.NONE) { + petItem = tempPetItem + return@forEach + } + val tempPetXP = handleWidgetXPLine(line) + if (tempPetXP != null) { + petXP = tempPetXP + return@forEach + } } event.lines.forEach { line -> - if (analyseWidgetPetLine(line, petItem, petXP, newPetLine)) return@forEach + if (handleWidgetPetLine(line, petItem, petXP, newPetLine)) return@forEach } } - private fun analyseWidgetPetLine(line: String, petItem: NEUInternalName, petXP: Double?, newPetLine: String): Boolean { + private fun handleWidgetPetLine(line: String, petItem: NEUInternalName, petXP: Double?, newPetLine: String): Boolean { val xpOverLevel = petXP ?: 0.0 petWidget.matchMatcher(line) { val xp = (levelToXP( @@ -134,23 +173,24 @@ object PetAPI { LorenzRarity.getByColorCode(group("rarity")[0]) ?: LorenzRarity.ULTIMATE, group("name").contains("Golden Dragon") )) - val newPet = PetData( - group("name"), - LorenzRarity.getByColorCode(group("rarity")[0]) ?: LorenzRarity.ULTIMATE, - petItem, - group("skin") != null, - group("level").toInt(), - (xp?.plus(xpOverLevel)) ?: 0.0, - newPetLine, + + fireEvent( + PetData( + group("name"), + LorenzRarity.getByColorCode(group("rarity")[0]) ?: LorenzRarity.ULTIMATE, + petItem, + group("skin") != null, + group("level").toInt(), + (xp?.plus(xpOverLevel)) ?: 0.0, + newPetLine, + ) ) - PetChangeEvent(pet, newPet).post() - pet = newPet return true } return false } - private fun analyseWidgetStringLine(line: String): NEUInternalName { + private fun handleWidgetStringLine(line: String): NEUInternalName { widgetString.matchMatcher(line) { val string = group("string") if (string == "No pet selected") { @@ -163,7 +203,7 @@ object PetAPI { return NEUInternalName.NONE } - private fun analyseWidgetXPLine(line: String): Double? { + private fun handleWidgetXPLine(line: String): Double? { xpWidget.matchMatcher(line) { if (group("max") != null) return null @@ -175,6 +215,60 @@ object PetAPI { return null } + @SubscribeEvent + fun onAutopet(event: LorenzChatEvent) { + if (!autopetMessage.matches(event.message)) return + + val hoverMessage = buildList { + event.chatComponent.hover?.siblings?.forEach { + add(it.formattedText) + } + }.toString().split("\n") + + var petItem = NEUInternalName.NONE + for (it in hoverMessage) { + val item = handleAutopetItemMessage(it) + if (item != null) { + petItem = item + break + } + } + hoverMessage.forEach { + if (handleAutopetMessage(it, petItem)) return + } + } + + private fun handleAutopetMessage(string: String, petItem: NEUInternalName): Boolean { + autopetHoverPet.matchMatcher(string) { + val level = group("level").toInt() + val rarity = LorenzRarity.getByColorCode(group("rarity")[0]) ?: LorenzRarity.ULTIMATE + val petName = group("pet") + val hasSkin = group("skin") != null + + val fakePetLine = "§r§7[Lvl $level] §r${rarity.chatColorCode}$petName${if (hasSkin) "§r${group("skin")}" else ""}" + + val newPet = PetData( + petName, + rarity, + petItem, + hasSkin, + level, + levelToXP(level, rarity) ?: 0.0, + fakePetLine, + ) + fireEvent(newPet) + return true + } + return false + } + + private fun handleAutopetItemMessage(string: String): NEUInternalName? { + autopetHoverPetItem.matchMatcher(string) { + return NEUInternalName.fromItemNameOrNull(group("item")) + } + return null + } + //taken from NEU //move to repo private val pet_levels = arrayOf( @@ -299,13 +393,13 @@ object PetAPI { 1886700 ) - fun testLeveltoXP(input: Array) { + fun testLevelToXP(input: Array) { if (input.size == 3) { val level = input[0].toIntOrNull() val rarity = LorenzRarity.getByName(input[1]) val isGoldenDragon = input[2].toBooleanStrictOrNull() if (level != null && rarity != null && isGoldenDragon != null) { - val xp: Int = levelToXP(level, rarity, isGoldenDragon) ?: run { + val xp: Double = levelToXP(level, rarity, isGoldenDragon) ?: run { ChatUtils.userError("bad input. invalid rarity or level") return } @@ -316,14 +410,14 @@ object PetAPI { ChatUtils.userError("bad usage. /shcalcpetxp ") } - private fun levelToXP(level: Int, rarity: LorenzRarity, isGoldenDragon: Boolean = false): Int? { + private fun levelToXP(level: Int, rarity: LorenzRarity, isGoldenDragon: Boolean = false): Double? { val rarityOffset = getRarityOffset(rarity) ?: return null if (!isValidLevel(level, isGoldenDragon)) return null return if (isGoldenDragon && level > 100) { - pet_levels.slice(0 + rarityOffset..<100 + rarityOffset - 1).sum() + getGdragXP(level - 100) + pet_levels.slice(0 + rarityOffset..<100 + rarityOffset - 1).sum() + getGoldenDragonXP(level - 100).toDouble() } else { - pet_levels.slice(0 + rarityOffset.. 0 2 -> 5555 @@ -353,6 +447,11 @@ object PetAPI { } } + private fun fireEvent(newPet: PetData?) { + PetChangeEvent(pet, newPet).post() + pet = newPet + } + @SubscribeEvent fun onDebug(event: DebugDataCollectEvent) { event.title("PetAPI") @@ -376,95 +475,12 @@ object PetAPI { ChatUtils.debug("oldPet: ${event.oldPet}, newPet: ${event.newPet}") } - - // { - // "strikethrough": false, - // "hoverEvent": { - // "action": "show_text", - // "value": { - // "bold": false, - // "italic": false, - // "underlined": false, - // "strikethrough": false, - // "obfuscated": false, - // "color": "red", - // "extra": [ - // { - // "bold": false, - // "italic": false, - // "underlined": false, - // "strikethrough": false, - // "obfuscated": false, - // "color": "green", - // "text": "When:\n" - // }, - // { - // "bold": false, - // "italic": false, - // "underlined": false, - // "strikethrough": false, - // "obfuscated": false, - // "color": "gray", - // "text": "You throw a fishing hook.\n\n" - // }, - // { - // "bold": false, - // "italic": false, - // "underlined": false, - // "strikethrough": false, - // "obfuscated": false, - // "color": "green", - // "text": "Equip: " - // }, - // { - // "bold": false, - // "italic": false, - // "underlined": false, - // "strikethrough": false, - // "obfuscated": false, - // "color": "yellow", - // "text": "⭐ " - // }, - // { - // "bold": false, - // "italic": false, - // "underlined": false, - // "strikethrough": false, - // "obfuscated": false, - // "color": "gray", - // "text": "[Lvl 100] " - // }, - // { - // "bold": false, - // "italic": false, - // "underlined": false, - // "strikethrough": false, - // "obfuscated": false, - // "color": "gold", - // "text": "Scatha\n" - // }, - // { - // "bold": false, - // "italic": false, - // "underlined": false, - // "strikethrough": false, - // "obfuscated": false, - // "color": "green", - // "text": "Held Item: " - // }, - // { - // "bold": false, - // "italic": false, - // "underlined": false, - // "strikethrough": false, - // "obfuscated": false, - // "color": "blue", - // "text": "Mining Exp Boost" - // } - // ], - // "text": "Autopet Rule\n\n" - // } - // }, - // "text": "§cAutopet §eequipped your §7[Lvl 100] §6Scatha§e! §a§lVIEW RULE" - // } + private fun comparePet(input: PetData, other: PetData): Boolean { + return input.name == other.name && + input.rarity == other.rarity && + input.petItem == other.petItem && + input.hasSkin == other.hasSkin && + input.level == other.level && + input.rawPetName == other.rawPetName + } //leaves xp out on purpose, because the data might not be up to date } From 954372193b4177a604112f3a615f8c639f25d00d Mon Sep 17 00:00:00 2001 From: martimavocado Date: Sat, 28 Sep 2024 02:41:02 +0100 Subject: [PATCH 10/91] prepare for pet menu (oh no) --- .../java/at/hannibal2/skyhanni/data/PetAPI.kt | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index 9b191390b299..a9c8cb2bb39e 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -3,6 +3,8 @@ package at.hannibal2.skyhanni.data import at.hannibal2.skyhanni.api.event.HandleEvent import at.hannibal2.skyhanni.data.model.TabWidget import at.hannibal2.skyhanni.events.DebugDataCollectEvent +import at.hannibal2.skyhanni.events.InventoryCloseEvent +import at.hannibal2.skyhanni.events.InventoryFullyOpenedEvent import at.hannibal2.skyhanni.events.LorenzChatEvent import at.hannibal2.skyhanni.events.WidgetUpdateEvent import at.hannibal2.skyhanni.events.skyblock.PetChangeEvent @@ -27,6 +29,8 @@ object PetAPI { private var pet: PetData? = null + private var inPetMenu = false + /** * REGEX-TEST: §e⭐ §7[Lvl 200] §6Golden Dragon§d ✦ * REGEX-TEST: ⭐ [Lvl 100] Black Cat ✦ @@ -112,14 +116,19 @@ object PetAPI { fun isPetMenu(inventoryTitle: String): Boolean = petMenuPattern.matches(inventoryTitle) // Contains color code + name and for older SkyHanni users maybe also the pet level + @Deprecated(message = "use PetAPI.pet.name") var currentPet: String? get() = ProfileStorageData.profileSpecific?.currentPet?.takeIf { it.isNotEmpty() } set(value) { ProfileStorageData.profileSpecific?.currentPet = value } + @Deprecated(message = "use PetAPI.pet.rawPetName", + replaceWith = ReplaceWith("pet.name.contains(petName) ?: false", "at.hannibal2.skyhanni.data.PetAPI.pet") + ) fun isCurrentPet(petName: String): Boolean = currentPet?.contains(petName) ?: false + @Deprecated(message = "use PetAPI.pet.rawPetName") fun getCleanName(nameWithLevel: String): String? { petItemName.matchMatcher(nameWithLevel) { return group("name") @@ -131,10 +140,12 @@ object PetAPI { return null } + @Deprecated(message = "use PetAPI.pet.level") fun getPetLevel(nameWithLevel: String): Int? = petItemName.matchMatcher(nameWithLevel) { group("level").toInt() } + @Deprecated(message = "use PetAPI.pet.name") fun hasPetName(name: String): Boolean = petItemName.matches(name) && !ignoredPetStrings.any { name.contains(it) } // --- @@ -269,6 +280,16 @@ object PetAPI { return null } + @SubscribeEvent + fun onOpenInventory(event: InventoryFullyOpenedEvent) { + inPetMenu = isPetMenu(event.inventoryName) + } + + @SubscribeEvent + fun onCloseInventory(event: InventoryCloseEvent) { + inPetMenu = false + } + //taken from NEU //move to repo private val pet_levels = arrayOf( @@ -474,13 +495,4 @@ object PetAPI { fun onPetChange(event: PetChangeEvent) { ChatUtils.debug("oldPet: ${event.oldPet}, newPet: ${event.newPet}") } - - private fun comparePet(input: PetData, other: PetData): Boolean { - return input.name == other.name && - input.rarity == other.rarity && - input.petItem == other.petItem && - input.hasSkin == other.hasSkin && - input.level == other.level && - input.rawPetName == other.rawPetName - } //leaves xp out on purpose, because the data might not be up to date } From 535dd39aaa80c67a8a3e54aa32ec25f19ab3a25b Mon Sep 17 00:00:00 2001 From: martimavocado Date: Sat, 28 Sep 2024 03:26:07 +0100 Subject: [PATCH 11/91] add pet menu support --- .../java/at/hannibal2/skyhanni/data/PetAPI.kt | 94 ++++++++++++++++++- 1 file changed, 91 insertions(+), 3 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index a9c8cb2bb39e..3ea7ae32698c 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -3,13 +3,18 @@ package at.hannibal2.skyhanni.data import at.hannibal2.skyhanni.api.event.HandleEvent import at.hannibal2.skyhanni.data.model.TabWidget import at.hannibal2.skyhanni.events.DebugDataCollectEvent +import at.hannibal2.skyhanni.events.GuiContainerEvent import at.hannibal2.skyhanni.events.InventoryCloseEvent import at.hannibal2.skyhanni.events.InventoryFullyOpenedEvent import at.hannibal2.skyhanni.events.LorenzChatEvent import at.hannibal2.skyhanni.events.WidgetUpdateEvent import at.hannibal2.skyhanni.events.skyblock.PetChangeEvent import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule +import at.hannibal2.skyhanni.test.command.ErrorManager import at.hannibal2.skyhanni.utils.ChatUtils +import at.hannibal2.skyhanni.utils.ItemCategory +import at.hannibal2.skyhanni.utils.ItemUtils.getItemCategoryOrNull +import at.hannibal2.skyhanni.utils.ItemUtils.getLore import at.hannibal2.skyhanni.utils.LorenzRarity import at.hannibal2.skyhanni.utils.NEUInternalName import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators @@ -17,6 +22,7 @@ import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.RegexUtils.matches import at.hannibal2.skyhanni.utils.chat.Text.hover import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern +import net.minecraft.item.ItemStack import net.minecraftforge.fml.common.eventhandler.SubscribeEvent @SkyHanniModule @@ -28,7 +34,6 @@ object PetAPI { ) private var pet: PetData? = null - private var inPetMenu = false /** @@ -44,6 +49,36 @@ object PetAPI { "(?:§f§f)?§7\\[Lvl (?:1➡(?:100|200)|\\{LVL})] (?.*)", ) + /** + * REGEX-TEST: §e⭐ §7[Lvl 100] §6Ender Dragon + * REGEX-TEST: §e⭐ §7[Lvl 100] §dBlack Cat§d ✦ + * REGEX-TEST: §7[Lvl 100] §6Mole + */ + private val petNameMenu by patternGroup.pattern( + "menu.pet.name", + "^(?:§e(?⭐) )?(?:§.)*\\[Lvl (?\\d+)] §(?.)(?[\\w ]+)(?§. ✦)?\$" + ) + + /** + * REGEX-TEST: §6Held Item: §9Mining Exp Boost + * REGEX-TEST: §6Held Item: §fAll Skills Exp Boost + * REGEX-TEST: §6Held Item: §9Dwarf Turtle Shelmet + */ + private val petItemMenu by patternGroup.pattern( + "menu.pet.item", + "^§6Held Item: (?§.[\\w -]+)\$" + ) + + /** + * REGEX-TEST: §7Progress to Level 45: §e94.4% + * REGEX-TEST: §8▸ 25,396,280 XP + * REGEX-TEST: §7Progress to Level 58: §e3.3% + */ + private val petXPMenu by patternGroup.pattern( + "menu.pet.xp", + "§.(?:Progress to Level (?\\d+): §e(?[\\d.]+)%|▸ (?[\\d,.]+) XP)\$" + ) + /** * REGEX-TEST: §r§7[Lvl 100] §r§dEndermite * REGEX-TEST: §r§7[Lvl 200] §r§8[§r§6108§r§8§r§4✦§r§8] §r§6Golden Dragon @@ -128,7 +163,6 @@ object PetAPI { ) fun isCurrentPet(petName: String): Boolean = currentPet?.contains(petName) ?: false - @Deprecated(message = "use PetAPI.pet.rawPetName") fun getCleanName(nameWithLevel: String): String? { petItemName.matchMatcher(nameWithLevel) { return group("name") @@ -153,7 +187,8 @@ object PetAPI { fun onWidgetUpdate(event: WidgetUpdateEvent) { if (!event.isWidget(TabWidget.PET)) return - val newPetLine = event.lines.getOrNull(1)?.removePrefix(" ") ?: return + val newPetLine = event.lines.getOrNull(1)?.removePrefix(" ") ?: return //TODO don't hardcode this + println("'${pet?.rawPetName}' '$newPetLine'") if (newPetLine == pet?.rawPetName) return var petItem = NEUInternalName.NONE @@ -290,6 +325,59 @@ object PetAPI { inPetMenu = false } + @SubscribeEvent + fun onItemClick(event: GuiContainerEvent.SlotClickEvent) { + if (!inPetMenu) return + if (event.clickTypeEnum != GuiContainerEvent.ClickType.NORMAL) return + val category = event.item?.getItemCategoryOrNull() ?: return + if (category != ItemCategory.PET) return + + parsePetAsItem(event.item) + } + + private fun parsePetAsItem(item: ItemStack) { + val lore = item.getLore() + + var level = 0 + var rarity: LorenzRarity = LorenzRarity.ULTIMATE + var petName = "" + var petItem = NEUInternalName.NONE + var petXP = 0.0 + var skin = "" + + petNameMenu.matchMatcher(item.displayName) { + level = group("level").toInt() + rarity = LorenzRarity.getByColorCode(group("rarity")[0]) ?: LorenzRarity.ULTIMATE + petName = group("name") + skin = group("skin") ?: "" + } + + for (it in lore) { + petItemMenu.matchMatcher(it) { + petItem = NEUInternalName.fromItemNameOrNull(group("item")) ?: ErrorManager.skyHanniError( + "Couldn't parse pet item name.", + Pair("lore", it), + Pair("item", group("item")) + ) + } + petXPMenu.matchMatcher(it) { + petXP = group("totalXP")?.replace(",", "")?.toDoubleOrNull() ?: 0.0 + } + } + + val fakePetLine = "§r§7[Lvl $level] §r${rarity.chatColorCode}$petName${if (skin != "") "§r${skin}" else ""}" + + fireEvent(PetData( + petName, + rarity, + petItem, + skin != "", + level, + petXP, + fakePetLine, + )) + } + //taken from NEU //move to repo private val pet_levels = arrayOf( From 28ba77e64a20854b7714e3869ed3474a4b055637 Mon Sep 17 00:00:00 2001 From: martimavocado Date: Sat, 28 Sep 2024 14:49:52 +0100 Subject: [PATCH 12/91] add pet menu despawn logic --- .../java/at/hannibal2/skyhanni/data/PetAPI.kt | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index 3ea7ae32698c..feff184abb8d 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -79,6 +79,14 @@ object PetAPI { "§.(?:Progress to Level (?\\d+): §e(?[\\d.]+)%|▸ (?[\\d,.]+) XP)\$" ) + /** + * REGEX-TEST: §7§cClick to despawn! + */ + private val petDespawnMenu by patternGroup.pattern( + "menu.pet.despawn", + "§7§cClick to despawn!" + ) + /** * REGEX-TEST: §r§7[Lvl 100] §r§dEndermite * REGEX-TEST: §r§7[Lvl 200] §r§8[§r§6108§r§8§r§4✦§r§8] §r§6Golden Dragon @@ -338,6 +346,15 @@ object PetAPI { private fun parsePetAsItem(item: ItemStack) { val lore = item.getLore() + if (lore.any { petDespawnMenu.matches(it) }) { + fireEvent(null) + return + } + + getPetDataFromLore(item.displayName, lore) + } + + private fun getPetDataFromLore(displayName: String, lore: List) { var level = 0 var rarity: LorenzRarity = LorenzRarity.ULTIMATE var petName = "" @@ -345,28 +362,28 @@ object PetAPI { var petXP = 0.0 var skin = "" - petNameMenu.matchMatcher(item.displayName) { + petNameMenu.matchMatcher(displayName) { level = group("level").toInt() rarity = LorenzRarity.getByColorCode(group("rarity")[0]) ?: LorenzRarity.ULTIMATE petName = group("name") skin = group("skin") ?: "" } - for (it in lore) { + lore.forEach { petItemMenu.matchMatcher(it) { petItem = NEUInternalName.fromItemNameOrNull(group("item")) ?: ErrorManager.skyHanniError( "Couldn't parse pet item name.", Pair("lore", it), Pair("item", group("item")) ) + return@forEach } petXPMenu.matchMatcher(it) { petXP = group("totalXP")?.replace(",", "")?.toDoubleOrNull() ?: 0.0 + return@forEach } } - val fakePetLine = "§r§7[Lvl $level] §r${rarity.chatColorCode}$petName${if (skin != "") "§r${skin}" else ""}" - fireEvent(PetData( petName, rarity, @@ -374,7 +391,7 @@ object PetAPI { skin != "", level, petXP, - fakePetLine, + "§r§7[Lvl $level] §r${rarity.chatColorCode}$petName${if (skin != "") "§r${skin}" else ""}", )) } From 9b285e001dfca4fc6a22e1c6c1ed9b0f2024e6f6 Mon Sep 17 00:00:00 2001 From: martimavocado Date: Sat, 28 Sep 2024 15:16:10 +0100 Subject: [PATCH 13/91] move pet levels to repo --- .../java/at/hannibal2/skyhanni/data/PetAPI.kt | 146 ++---------------- .../skyhanni/data/jsonobjects/repo/Pets.kt | 8 + 2 files changed, 23 insertions(+), 131 deletions(-) create mode 100644 src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/Pets.kt diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index feff184abb8d..7d761e3dea8d 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -1,12 +1,14 @@ package at.hannibal2.skyhanni.data import at.hannibal2.skyhanni.api.event.HandleEvent +import at.hannibal2.skyhanni.data.jsonobjects.repo.PetsJson import at.hannibal2.skyhanni.data.model.TabWidget import at.hannibal2.skyhanni.events.DebugDataCollectEvent import at.hannibal2.skyhanni.events.GuiContainerEvent import at.hannibal2.skyhanni.events.InventoryCloseEvent import at.hannibal2.skyhanni.events.InventoryFullyOpenedEvent import at.hannibal2.skyhanni.events.LorenzChatEvent +import at.hannibal2.skyhanni.events.RepositoryReloadEvent import at.hannibal2.skyhanni.events.WidgetUpdateEvent import at.hannibal2.skyhanni.events.skyblock.PetChangeEvent import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule @@ -36,6 +38,9 @@ object PetAPI { private var pet: PetData? = null private var inPetMenu = false + private var xpLeveling: List = listOf() + private var xpLevelingGoldenDragon: List = listOf() + /** * REGEX-TEST: §e⭐ §7[Lvl 200] §6Golden Dragon§d ✦ * REGEX-TEST: ⭐ [Lvl 100] Black Cat ✦ @@ -395,130 +400,6 @@ object PetAPI { )) } - //taken from NEU - //move to repo - private val pet_levels = arrayOf( - 100, - 110, - 120, - 130, - 145, - 160, - 175, - 190, - 210, - 230, - 250, - 275, - 300, - 330, - 360, - 400, - 440, - 490, - 540, - 600, - 660, - 730, - 800, - 880, - 960, - 1050, - 1150, - 1260, - 1380, - 1510, - 1650, - 1800, - 1960, - 2130, - 2310, - 2500, - 2700, - 2920, - 3160, - 3420, - 3700, - 4000, - 4350, - 4750, - 5200, - 5700, - 6300, - 7000, - 7800, - 8700, - 9700, - 10800, - 12000, - 13300, - 14700, - 16200, - 17800, - 19500, - 21300, - 23200, - 25200, - 27400, - 29800, - 32400, - 35200, - 38200, - 41400, - 44800, - 48400, - 52200, - 56200, - 60400, - 64800, - 69400, - 74200, - 79200, - 84700, - 90700, - 97200, - 104200, - 111700, - 119700, - 128200, - 137200, - 146700, - 156700, - 167700, - 179700, - 192700, - 206700, - 221700, - 237700, - 254700, - 272700, - 291700, - 311700, - 333700, - 357700, - 383700, - 411700, - 441700, - 476700, - 516700, - 561700, - 611700, - 666700, - 726700, - 791700, - 861700, - 936700, - 1016700, - 1101700, - 1191700, - 1286700, - 1386700, - 1496700, - 1616700, - 1746700, - 1886700 - ) - fun testLevelToXP(input: Array) { if (input.size == 3) { val level = input[0].toIntOrNull() @@ -541,9 +422,9 @@ object PetAPI { if (!isValidLevel(level, isGoldenDragon)) return null return if (isGoldenDragon && level > 100) { - pet_levels.slice(0 + rarityOffset..<100 + rarityOffset - 1).sum() + getGoldenDragonXP(level - 100).toDouble() + xpLeveling.slice(0 + rarityOffset..<100 + rarityOffset - 1).sum() + getGoldenDragonXP(level - 100).toDouble() } else { - pet_levels.slice(0 + rarityOffset.. 0 - 2 -> 5555 - else -> 5555 + (levelAbove100 - 2) * 1886700 - } + return xpLevelingGoldenDragon.slice(0..("Pets") + xpLeveling = data.xpLeveling + xpLevelingGoldenDragon = data.xpLevelingGoldenDragon + } + @HandleEvent fun onPetChange(event: PetChangeEvent) { ChatUtils.debug("oldPet: ${event.oldPet}, newPet: ${event.newPet}") diff --git a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/Pets.kt b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/Pets.kt new file mode 100644 index 000000000000..1fa8c1923dd6 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/Pets.kt @@ -0,0 +1,8 @@ +package at.hannibal2.skyhanni.data.jsonobjects.repo + +import com.google.gson.annotations.Expose + +data class PetsJson( + @Expose val xpLeveling: List, + @Expose val xpLevelingGoldenDragon: List, +) From 04d1fe3d6593ef4fa918107a2c74d9b2f21dcdb1 Mon Sep 17 00:00:00 2001 From: martimavocado Date: Sat, 28 Sep 2024 16:57:01 +0100 Subject: [PATCH 14/91] add event description and move to neu repo --- .../java/at/hannibal2/skyhanni/data/PetAPI.kt | 61 ++++++++++--------- .../data/jsonobjects/repo/NEUPetsJson.kt | 9 +++ .../skyhanni/data/jsonobjects/repo/Pets.kt | 8 --- .../events/skyblock/PetChangeEvent.kt | 7 +++ 4 files changed, 49 insertions(+), 36 deletions(-) create mode 100644 src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt delete mode 100644 src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/Pets.kt diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index 7d761e3dea8d..0582d2958bd5 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -1,14 +1,14 @@ package at.hannibal2.skyhanni.data import at.hannibal2.skyhanni.api.event.HandleEvent -import at.hannibal2.skyhanni.data.jsonobjects.repo.PetsJson +import at.hannibal2.skyhanni.data.jsonobjects.repo.NEUPetsJson import at.hannibal2.skyhanni.data.model.TabWidget import at.hannibal2.skyhanni.events.DebugDataCollectEvent import at.hannibal2.skyhanni.events.GuiContainerEvent import at.hannibal2.skyhanni.events.InventoryCloseEvent import at.hannibal2.skyhanni.events.InventoryFullyOpenedEvent import at.hannibal2.skyhanni.events.LorenzChatEvent -import at.hannibal2.skyhanni.events.RepositoryReloadEvent +import at.hannibal2.skyhanni.events.NeuRepositoryReloadEvent import at.hannibal2.skyhanni.events.WidgetUpdateEvent import at.hannibal2.skyhanni.events.skyblock.PetChangeEvent import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule @@ -39,7 +39,7 @@ object PetAPI { private var inPetMenu = false private var xpLeveling: List = listOf() - private var xpLevelingGoldenDragon: List = listOf() + private var xpLevelingCustom: List = listOf() /** * REGEX-TEST: §e⭐ §7[Lvl 200] §6Golden Dragon§d ✦ @@ -230,7 +230,7 @@ object PetAPI { val xp = (levelToXP( group("level").toInt(), LorenzRarity.getByColorCode(group("rarity")[0]) ?: LorenzRarity.ULTIMATE, - group("name").contains("Golden Dragon") + group("name") )) fireEvent( @@ -312,7 +312,7 @@ object PetAPI { petItem, hasSkin, level, - levelToXP(level, rarity) ?: 0.0, + levelToXP(level, rarity, petName) ?: 0.0, fakePetLine, ) fireEvent(newPet) @@ -401,12 +401,12 @@ object PetAPI { } fun testLevelToXP(input: Array) { - if (input.size == 3) { + if (input.size >= 3) { val level = input[0].toIntOrNull() val rarity = LorenzRarity.getByName(input[1]) - val isGoldenDragon = input[2].toBooleanStrictOrNull() - if (level != null && rarity != null && isGoldenDragon != null) { - val xp: Double = levelToXP(level, rarity, isGoldenDragon) ?: run { + val petName = input.slice(2.. ") } - private fun levelToXP(level: Int, rarity: LorenzRarity, isGoldenDragon: Boolean = false): Double? { - val rarityOffset = getRarityOffset(rarity) ?: return null - if (!isValidLevel(level, isGoldenDragon)) return null + private fun levelToXP(level: Int, rarity: LorenzRarity, petName: String = ""): Double? { + val rarityOffset = getRarityOffset(rarity, petName) ?: return null + if (!isValidLevel(level, petName == "Golden Dragon")) return null - return if (isGoldenDragon && level > 100) { + return if (petName == "Golden Dragon" && level > 100) { xpLeveling.slice(0 + rarityOffset..<100 + rarityOffset - 1).sum() + getGoldenDragonXP(level - 100).toDouble() } else { xpLeveling.slice(0 + rarityOffset.. 0 - LorenzRarity.UNCOMMON -> 6 - LorenzRarity.RARE -> 11 - LorenzRarity.EPIC -> 16 - LorenzRarity.LEGENDARY -> 20 - LorenzRarity.MYTHIC -> 20 - else -> { - ChatUtils.userError("bad rarity. ${rarity.name}") - null + private fun getRarityOffset(rarity: LorenzRarity, pet: String = ""): Int? { + if (pet == "Bingo") return 0 + return when (rarity) { + LorenzRarity.COMMON -> 0 + LorenzRarity.UNCOMMON -> 6 + LorenzRarity.RARE -> 11 + LorenzRarity.EPIC -> 16 + LorenzRarity.LEGENDARY -> 20 + LorenzRarity.MYTHIC -> 20 + else -> { + ChatUtils.userError("bad rarity. ${rarity.name}") + null + } } } @@ -474,10 +477,12 @@ object PetAPI { } @SubscribeEvent - fun onRepoReload(event: RepositoryReloadEvent) { - val data = event.getConstant("Pets") - xpLeveling = data.xpLeveling - xpLevelingGoldenDragon = data.xpLevelingGoldenDragon + fun onNEURepoReload(event: NeuRepositoryReloadEvent) { + val data = event.getConstant("pets") + xpLeveling = data.pet_levels + val xpLevelingCustomJson = data.custom_pet_leveling.getAsJsonObject("GOLDEN_DRAGON").getAsJsonArray("pet_levels") + + xpLevelingCustom = xpLevelingCustomJson.map { it.asInt } } @HandleEvent diff --git a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt new file mode 100644 index 000000000000..4061c4a7d8d1 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt @@ -0,0 +1,9 @@ +package at.hannibal2.skyhanni.data.jsonobjects.repo + +import com.google.gson.JsonObject +import com.google.gson.annotations.Expose + +data class NEUPetsJson( + @Expose val pet_levels: List, + @Expose val custom_pet_leveling: JsonObject, +) diff --git a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/Pets.kt b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/Pets.kt deleted file mode 100644 index 1fa8c1923dd6..000000000000 --- a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/Pets.kt +++ /dev/null @@ -1,8 +0,0 @@ -package at.hannibal2.skyhanni.data.jsonobjects.repo - -import com.google.gson.annotations.Expose - -data class PetsJson( - @Expose val xpLeveling: List, - @Expose val xpLevelingGoldenDragon: List, -) diff --git a/src/main/java/at/hannibal2/skyhanni/events/skyblock/PetChangeEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/skyblock/PetChangeEvent.kt index 60ca08dbf963..0237159c5522 100644 --- a/src/main/java/at/hannibal2/skyhanni/events/skyblock/PetChangeEvent.kt +++ b/src/main/java/at/hannibal2/skyhanni/events/skyblock/PetChangeEvent.kt @@ -3,4 +3,11 @@ package at.hannibal2.skyhanni.events.skyblock import at.hannibal2.skyhanni.api.event.SkyHanniEvent import at.hannibal2.skyhanni.data.PetData +/** + * This event fires when a pet change occurs and on joining SkyBlock for the first time in a session. + * The XP value in the PetData might not be accurate. + * + * @property oldPet The previous pet before the change. + * @property newPet The new pet after the change. + */ class PetChangeEvent(val oldPet: PetData?, val newPet: PetData?) : SkyHanniEvent() From 90fd5f5a23201892e83084ecfe33d21c6700a480 Mon Sep 17 00:00:00 2001 From: martimavocado Date: Sat, 28 Sep 2024 17:19:24 +0100 Subject: [PATCH 15/91] fix pet item xp parsing, cleanup --- .../java/at/hannibal2/skyhanni/data/PetAPI.kt | 56 ++++++++++++++----- 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index 0582d2958bd5..653d00b49345 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -360,11 +360,25 @@ object PetAPI { } private fun getPetDataFromLore(displayName: String, lore: List) { + val (name, rarity, _, _, level, _, skin) = parsePetName(displayName) + val (petItem, petXP) = parsePetLore(lore, Pair(rarity, name)) + + val newPet = PetData( + name, + rarity, + petItem, + skin != "", + level, + petXP, + "§r§7[Lvl $level] §r${rarity.chatColorCode}$name${if (skin != "") "§r${skin}" else ""}", + ) + fireEvent(newPet) + } + + private fun parsePetName(displayName: String): PetData { var level = 0 var rarity: LorenzRarity = LorenzRarity.ULTIMATE var petName = "" - var petItem = NEUInternalName.NONE - var petXP = 0.0 var skin = "" petNameMenu.matchMatcher(displayName) { @@ -374,8 +388,23 @@ object PetAPI { skin = group("skin") ?: "" } + return PetData( + petName, + rarity, + NEUInternalName.NONE, + false, + level, + 0.0, + skin + ) + } + + private fun parsePetLore(lore: List, petInfo: Pair): Pair { + var petItem = NEUInternalName.NONE + var petXP = 0.0 + lore.forEach { - petItemMenu.matchMatcher(it) { + if (petItem == NEUInternalName.NONE) petItemMenu.matchMatcher(it) { petItem = NEUInternalName.fromItemNameOrNull(group("item")) ?: ErrorManager.skyHanniError( "Couldn't parse pet item name.", Pair("lore", it), @@ -383,21 +412,20 @@ object PetAPI { ) return@forEach } - petXPMenu.matchMatcher(it) { - petXP = group("totalXP")?.replace(",", "")?.toDoubleOrNull() ?: 0.0 + if (petXP == 0.0) petXPMenu.matchMatcher(it) { + val totalXP = group("totalXP")?.replace(",", "")?.toDoubleOrNull() ?: 0.0 + val percentage = (group("percentage")?.toDoubleOrNull()?.div(100.0)) ?: 0.0 + + val fromXP = levelToXP(group("level")?.toIntOrNull()?.minus(1) ?: 1, petInfo.first, petInfo.second) ?: 0.0 + val toXP = levelToXP(group("level")?.toIntOrNull() ?: 2, petInfo.first, petInfo.second) ?: 0.0 + + petXP = if (totalXP == 0.0) fromXP + ((toXP - fromXP) * percentage) + else totalXP return@forEach } } - fireEvent(PetData( - petName, - rarity, - petItem, - skin != "", - level, - petXP, - "§r§7[Lvl $level] §r${rarity.chatColorCode}$petName${if (skin != "") "§r${skin}" else ""}", - )) + return Pair(petItem, petXP) } fun testLevelToXP(input: Array) { From 0533bc53a57eacf11635deffaca51edd5f73e5a6 Mon Sep 17 00:00:00 2001 From: martimavocado Date: Sat, 28 Sep 2024 17:21:56 +0100 Subject: [PATCH 16/91] more cleanup --- .../java/at/hannibal2/skyhanni/data/PetAPI.kt | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index 653d00b49345..95d1ac6a2e29 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -233,17 +233,16 @@ object PetAPI { group("name") )) - fireEvent( - PetData( - group("name"), - LorenzRarity.getByColorCode(group("rarity")[0]) ?: LorenzRarity.ULTIMATE, - petItem, - group("skin") != null, - group("level").toInt(), - (xp?.plus(xpOverLevel)) ?: 0.0, - newPetLine, - ) + val newPet = PetData( + group("name"), + LorenzRarity.getByColorCode(group("rarity")[0]) ?: LorenzRarity.ULTIMATE, + petItem, + group("skin") != null, + group("level").toInt(), + (xp?.plus(xpOverLevel)) ?: 0.0, + newPetLine, ) + fireEvent(newPet) return true } return false From 2ea237b31fdd65bdee68db4b55f05f53a80158da Mon Sep 17 00:00:00 2001 From: martimavocado Date: Sat, 28 Sep 2024 17:25:57 +0100 Subject: [PATCH 17/91] remove debugdata --- src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index 95d1ac6a2e29..5fdefb08fb4d 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -1,6 +1,5 @@ package at.hannibal2.skyhanni.data -import at.hannibal2.skyhanni.api.event.HandleEvent import at.hannibal2.skyhanni.data.jsonobjects.repo.NEUPetsJson import at.hannibal2.skyhanni.data.model.TabWidget import at.hannibal2.skyhanni.events.DebugDataCollectEvent @@ -511,9 +510,4 @@ object PetAPI { xpLevelingCustom = xpLevelingCustomJson.map { it.asInt } } - - @HandleEvent - fun onPetChange(event: PetChangeEvent) { - ChatUtils.debug("oldPet: ${event.oldPet}, newPet: ${event.newPet}") - } } From 6419bdb74fe08c07197e7b4cba8aed7c3bfb1597 Mon Sep 17 00:00:00 2001 From: martimavocado Date: Thu, 3 Oct 2024 13:33:15 +0100 Subject: [PATCH 18/91] add support for changing pet item --- .../java/at/hannibal2/skyhanni/data/PetAPI.kt | 50 +++++++++++++------ 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index 5fdefb08fb4d..30ab0d70652e 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -151,6 +151,14 @@ object PetAPI { "^§r, §aHeld Item: §r, (?§.[\\w -]+)§r]\$" ) + /** + * REGEX-TEST: §aYour pet is now holding §r§9Bejeweled Collar§r§a. + */ + private val petItemMessage by patternGroup.pattern( + "chat.pet.item.equip", + "^§aYour pet is now holding §r(?§.[\\w -]+)§r§a\\.\$" + ) + private val ignoredPetStrings = listOf( "Archer", "Berserk", @@ -273,25 +281,35 @@ object PetAPI { } @SubscribeEvent - fun onAutopet(event: LorenzChatEvent) { - if (!autopetMessage.matches(event.message)) return - - val hoverMessage = buildList { - event.chatComponent.hover?.siblings?.forEach { - add(it.formattedText) + fun onChat(event: LorenzChatEvent) { + if (autopetMessage.matches(event.message)) { + val hoverMessage = buildList { + event.chatComponent.hover?.siblings?.forEach { + add(it.formattedText) + } + }.toString().split("\n") + + var petItem = NEUInternalName.NONE + for (it in hoverMessage) { + val item = handleAutopetItemMessage(it) + if (item != null) { + petItem = item + break + } } - }.toString().split("\n") - - var petItem = NEUInternalName.NONE - for (it in hoverMessage) { - val item = handleAutopetItemMessage(it) - if (item != null) { - petItem = item - break + hoverMessage.forEach { + if (handleAutopetMessage(it, petItem)) return } + return } - hoverMessage.forEach { - if (handleAutopetMessage(it, petItem)) return + petItemMessage.matchMatcher(event.message) { + val item = NEUInternalName.fromItemNameOrNull(group("petItem")) ?: ErrorManager.skyHanniError( + "Couldn't parse pet item name.", + Pair("message", event.message), + Pair("item", group("petItem")) + ) + val newPet = pet?.copy(petItem = item) ?: return + fireEvent(newPet) } } From f0814a45ab6b078dbcc29239442960ef258036e3 Mon Sep 17 00:00:00 2001 From: martimavocado Date: Thu, 3 Oct 2024 13:37:42 +0100 Subject: [PATCH 19/91] stop hardcoding pet line --- src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index 30ab0d70652e..15bf3ea76278 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -207,9 +207,14 @@ object PetAPI { fun onWidgetUpdate(event: WidgetUpdateEvent) { if (!event.isWidget(TabWidget.PET)) return - val newPetLine = event.lines.getOrNull(1)?.removePrefix(" ") ?: return //TODO don't hardcode this - println("'${pet?.rawPetName}' '$newPetLine'") - if (newPetLine == pet?.rawPetName) return + var newPetLine = "" + for (line in event.lines) { + if (petWidget.matches(line)) { + newPetLine = line + break + } + } + if (newPetLine == pet?.rawPetName || newPetLine == "") return var petItem = NEUInternalName.NONE var petXP: Double? = null From d3db01f65da97e08b1b1c6ac678a8fc531b34a5c Mon Sep 17 00:00:00 2001 From: martimavocado Date: Thu, 3 Oct 2024 16:17:11 +0100 Subject: [PATCH 20/91] hypixel successfully trolled everyone --- .../java/at/hannibal2/skyhanni/data/PetAPI.kt | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index 15bf3ea76278..30deee6f0352 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -91,6 +91,16 @@ object PetAPI { "§7§cClick to despawn!" ) + /** + * REGEX-TEST: §7To Select Process (Slot #2) + * REGEX-TEST: §7To Select Process (Slot #4) + * REGEX-TEST: §7To Select Process (Slot #7) + */ + private val forgeBackMenu by patternGroup.pattern( + "menu.forge.goback", + "§7To Select Process \\(Slot #\\d\\)" + ) + /** * REGEX-TEST: §r§7[Lvl 100] §r§dEndermite * REGEX-TEST: §r§7[Lvl 200] §r§8[§r§6108§r§8§r§4✦§r§8] §r§6Golden Dragon @@ -168,6 +178,7 @@ object PetAPI { "➡", ) + @Deprecated(message = "use PetAPI.inPetMenu") fun isPetMenu(inventoryTitle: String): Boolean = petMenuPattern.matches(inventoryTitle) // Contains color code + name and for older SkyHanni users maybe also the pet level @@ -351,7 +362,17 @@ object PetAPI { @SubscribeEvent fun onOpenInventory(event: InventoryFullyOpenedEvent) { - inPetMenu = isPetMenu(event.inventoryName) + if (!isPetMenu(event.inventoryName)) { + inPetMenu = false + return + } + val goBackLore = event.inventoryItems[48]?.getLore() ?: emptyList() + if (goBackLore.any { forgeBackMenu.matches(it) }) { + inPetMenu = false + return + } + + inPetMenu = true } @SubscribeEvent From 007f2753197cc92489805602da6c29d49956b9ca Mon Sep 17 00:00:00 2001 From: martimavocado Date: Sat, 12 Oct 2024 15:36:32 +0100 Subject: [PATCH 21/91] update pattern names --- .../java/at/hannibal2/skyhanni/data/PetAPI.kt | 62 +++++++++---------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index 30deee6f0352..7bf998d36701 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -44,11 +44,11 @@ object PetAPI { * REGEX-TEST: §e⭐ §7[Lvl 200] §6Golden Dragon§d ✦ * REGEX-TEST: ⭐ [Lvl 100] Black Cat ✦ */ - private val petItemName by patternGroup.pattern( + private val petItemNamePattern by patternGroup.pattern( "item.name", "(?(?:§.)*⭐ )?(?:§.)*\\[Lvl (?\\d+)] (?.*)", ) - private val neuRepoPetItemName by patternGroup.pattern( + private val neuRepoPetItemNamePattern by patternGroup.pattern( "item.name.neu.format", "(?:§f§f)?§7\\[Lvl (?:1➡(?:100|200)|\\{LVL})] (?.*)", ) @@ -58,7 +58,7 @@ object PetAPI { * REGEX-TEST: §e⭐ §7[Lvl 100] §dBlack Cat§d ✦ * REGEX-TEST: §7[Lvl 100] §6Mole */ - private val petNameMenu by patternGroup.pattern( + private val petNameMenuPattern by patternGroup.pattern( "menu.pet.name", "^(?:§e(?⭐) )?(?:§.)*\\[Lvl (?\\d+)] §(?.)(?[\\w ]+)(?§. ✦)?\$" ) @@ -68,7 +68,7 @@ object PetAPI { * REGEX-TEST: §6Held Item: §fAll Skills Exp Boost * REGEX-TEST: §6Held Item: §9Dwarf Turtle Shelmet */ - private val petItemMenu by patternGroup.pattern( + private val petItemMenuPattern by patternGroup.pattern( "menu.pet.item", "^§6Held Item: (?§.[\\w -]+)\$" ) @@ -78,7 +78,7 @@ object PetAPI { * REGEX-TEST: §8▸ 25,396,280 XP * REGEX-TEST: §7Progress to Level 58: §e3.3% */ - private val petXPMenu by patternGroup.pattern( + private val petXPMenuPattern by patternGroup.pattern( "menu.pet.xp", "§.(?:Progress to Level (?\\d+): §e(?[\\d.]+)%|▸ (?[\\d,.]+) XP)\$" ) @@ -86,7 +86,7 @@ object PetAPI { /** * REGEX-TEST: §7§cClick to despawn! */ - private val petDespawnMenu by patternGroup.pattern( + private val petDespawnMenuPattern by patternGroup.pattern( "menu.pet.despawn", "§7§cClick to despawn!" ) @@ -96,7 +96,7 @@ object PetAPI { * REGEX-TEST: §7To Select Process (Slot #4) * REGEX-TEST: §7To Select Process (Slot #7) */ - private val forgeBackMenu by patternGroup.pattern( + private val forgeBackMenuPattern by patternGroup.pattern( "menu.forge.goback", "§7To Select Process \\(Slot #\\d\\)" ) @@ -106,7 +106,7 @@ object PetAPI { * REGEX-TEST: §r§7[Lvl 200] §r§8[§r§6108§r§8§r§4✦§r§8] §r§6Golden Dragon * REGEX-TEST: §r§7[Lvl 100] §r§dBlack Cat§r§d ✦ */ - private val petWidget by patternGroup.pattern( + private val petWidgetPattern by patternGroup.pattern( "widget.pet", "^ §r§7\\[Lvl (?\\d+)](?: (?:§.)+\\[(?:§.)+(?\\d+)(?:§.)+✦(?:§.)+])? §r§(?.)(?[\\w ]+)(?:§r(?§. ✦))?\$", ) @@ -116,7 +116,7 @@ object PetAPI { * REGEX-TEST: §r§6Washed-up Souvenir * REGEX-TEST: §r§9Dwarf Turtle Shelmet */ - private val widgetString by patternGroup.pattern( + private val widgetStringPattern by patternGroup.pattern( "widget.string", "^ §r(?§.[\\w -]+)\$", ) @@ -126,7 +126,7 @@ object PetAPI { * REGEX-TEST: §r§6+§r§e21,248,020.7 XP * REGEX-TEST: §r§e15,986.6§r§6/§r§e29k XP §r§6(53.6%) */ - private val xpWidget by patternGroup.pattern( + private val xpWidgetPattern by patternGroup.pattern( "widget.xp", "^ §r§.(?:§l(?MAX LEVEL)|\\+§r§e(?[\\d,.]+) XP|(?[\\d,.]+)§r§6/§r§e(?[\\d.km]+) XP §r§6\\((?[\\d.%]+)\\))$", ) @@ -136,7 +136,7 @@ object PetAPI { * REGEX-TEST: §cAutopet §eequipped your §7[Lvl 99] §6Flying Fish§e! §a§lVIEW RULE * REGEX-TEST: §cAutopet §eequipped your §7[Lvl 100] §dBlack Cat§d ✦§e! §a§lVIEW RULE */ - private val autopetMessage by patternGroup.pattern( + private val autopetMessagePattern by patternGroup.pattern( "chat.autopet", "^§cAutopet §eequipped your §7(?\\[Lvl \\d{1,3}] §.[\\w ]+)(?:§. ✦)?§e! §a§lVIEW RULE\$" ) @@ -146,7 +146,7 @@ object PetAPI { * REGEX-TEST: §r, §aEquip: §r, §e⭐ §r, §7[Lvl 100] §r, §dBlack Cat§r, §d ✦ * REGEX-TEST: §r, §aEquip: §r, §7[Lvl 47] §r, §5Lion */ - private val autopetHoverPet by patternGroup.pattern( + private val autopetHoverPetPattern by patternGroup.pattern( "chat.autopet.hover.pet", "^§r, §aEquip: §r,(?: §e⭐ §r,)? §7\\[Lvl (?\\d+)] §r, §(?.)(?[\\w ]+)(?:§r, (?§. ✦))?\$" ) @@ -156,7 +156,7 @@ object PetAPI { * REGEX-TEST: §r, §aHeld Item: §r, §5Lucky Clover§r] * REGEX-TEST: §r, §aHeld Item: §r, §5Fishing Exp Boost§r] */ - private val autopetHoverPetItem by patternGroup.pattern( + private val autopetHoverPetItemPattern by patternGroup.pattern( "chat.autopet.hover.item", "^§r, §aHeld Item: §r, (?§.[\\w -]+)§r]\$" ) @@ -164,7 +164,7 @@ object PetAPI { /** * REGEX-TEST: §aYour pet is now holding §r§9Bejeweled Collar§r§a. */ - private val petItemMessage by patternGroup.pattern( + private val petItemMessagePattern by patternGroup.pattern( "chat.pet.item.equip", "^§aYour pet is now holding §r(?§.[\\w -]+)§r§a\\.\$" ) @@ -195,10 +195,10 @@ object PetAPI { fun isCurrentPet(petName: String): Boolean = currentPet?.contains(petName) ?: false fun getCleanName(nameWithLevel: String): String? { - petItemName.matchMatcher(nameWithLevel) { + petItemNamePattern.matchMatcher(nameWithLevel) { return group("name") } - neuRepoPetItemName.matchMatcher(nameWithLevel) { + neuRepoPetItemNamePattern.matchMatcher(nameWithLevel) { return group("name") } @@ -206,12 +206,12 @@ object PetAPI { } @Deprecated(message = "use PetAPI.pet.level") - fun getPetLevel(nameWithLevel: String): Int? = petItemName.matchMatcher(nameWithLevel) { + fun getPetLevel(nameWithLevel: String): Int? = petItemNamePattern.matchMatcher(nameWithLevel) { group("level").toInt() } @Deprecated(message = "use PetAPI.pet.name") - fun hasPetName(name: String): Boolean = petItemName.matches(name) && !ignoredPetStrings.any { name.contains(it) } + fun hasPetName(name: String): Boolean = petItemNamePattern.matches(name) && !ignoredPetStrings.any { name.contains(it) } // --- @SubscribeEvent @@ -220,7 +220,7 @@ object PetAPI { var newPetLine = "" for (line in event.lines) { - if (petWidget.matches(line)) { + if (petWidgetPattern.matches(line)) { newPetLine = line break } @@ -249,7 +249,7 @@ object PetAPI { private fun handleWidgetPetLine(line: String, petItem: NEUInternalName, petXP: Double?, newPetLine: String): Boolean { val xpOverLevel = petXP ?: 0.0 - petWidget.matchMatcher(line) { + petWidgetPattern.matchMatcher(line) { val xp = (levelToXP( group("level").toInt(), LorenzRarity.getByColorCode(group("rarity")[0]) ?: LorenzRarity.ULTIMATE, @@ -272,7 +272,7 @@ object PetAPI { } private fun handleWidgetStringLine(line: String): NEUInternalName { - widgetString.matchMatcher(line) { + widgetStringPattern.matchMatcher(line) { val string = group("string") if (string == "No pet selected") { PetChangeEvent(pet, null).post() @@ -285,7 +285,7 @@ object PetAPI { } private fun handleWidgetXPLine(line: String): Double? { - xpWidget.matchMatcher(line) { + xpWidgetPattern.matchMatcher(line) { if (group("max") != null) return null val overflow = group("overflow")?.replace(",", "")?.toDoubleOrNull() ?: 0.0 @@ -298,7 +298,7 @@ object PetAPI { @SubscribeEvent fun onChat(event: LorenzChatEvent) { - if (autopetMessage.matches(event.message)) { + if (autopetMessagePattern.matches(event.message)) { val hoverMessage = buildList { event.chatComponent.hover?.siblings?.forEach { add(it.formattedText) @@ -318,7 +318,7 @@ object PetAPI { } return } - petItemMessage.matchMatcher(event.message) { + petItemMessagePattern.matchMatcher(event.message) { val item = NEUInternalName.fromItemNameOrNull(group("petItem")) ?: ErrorManager.skyHanniError( "Couldn't parse pet item name.", Pair("message", event.message), @@ -330,7 +330,7 @@ object PetAPI { } private fun handleAutopetMessage(string: String, petItem: NEUInternalName): Boolean { - autopetHoverPet.matchMatcher(string) { + autopetHoverPetPattern.matchMatcher(string) { val level = group("level").toInt() val rarity = LorenzRarity.getByColorCode(group("rarity")[0]) ?: LorenzRarity.ULTIMATE val petName = group("pet") @@ -354,7 +354,7 @@ object PetAPI { } private fun handleAutopetItemMessage(string: String): NEUInternalName? { - autopetHoverPetItem.matchMatcher(string) { + autopetHoverPetItemPattern.matchMatcher(string) { return NEUInternalName.fromItemNameOrNull(group("item")) } return null @@ -367,7 +367,7 @@ object PetAPI { return } val goBackLore = event.inventoryItems[48]?.getLore() ?: emptyList() - if (goBackLore.any { forgeBackMenu.matches(it) }) { + if (goBackLore.any { forgeBackMenuPattern.matches(it) }) { inPetMenu = false return } @@ -393,7 +393,7 @@ object PetAPI { private fun parsePetAsItem(item: ItemStack) { val lore = item.getLore() - if (lore.any { petDespawnMenu.matches(it) }) { + if (lore.any { petDespawnMenuPattern.matches(it) }) { fireEvent(null) return } @@ -423,7 +423,7 @@ object PetAPI { var petName = "" var skin = "" - petNameMenu.matchMatcher(displayName) { + petNameMenuPattern.matchMatcher(displayName) { level = group("level").toInt() rarity = LorenzRarity.getByColorCode(group("rarity")[0]) ?: LorenzRarity.ULTIMATE petName = group("name") @@ -446,7 +446,7 @@ object PetAPI { var petXP = 0.0 lore.forEach { - if (petItem == NEUInternalName.NONE) petItemMenu.matchMatcher(it) { + if (petItem == NEUInternalName.NONE) petItemMenuPattern.matchMatcher(it) { petItem = NEUInternalName.fromItemNameOrNull(group("item")) ?: ErrorManager.skyHanniError( "Couldn't parse pet item name.", Pair("lore", it), @@ -454,7 +454,7 @@ object PetAPI { ) return@forEach } - if (petXP == 0.0) petXPMenu.matchMatcher(it) { + if (petXP == 0.0) petXPMenuPattern.matchMatcher(it) { val totalXP = group("totalXP")?.replace(",", "")?.toDoubleOrNull() ?: 0.0 val percentage = (group("percentage")?.toDoubleOrNull()?.div(100.0)) ?: 0.0 From b974cc08167de310b4028b8f113274b62a280583 Mon Sep 17 00:00:00 2001 From: martimavocado Date: Sat, 12 Oct 2024 18:53:11 +0100 Subject: [PATCH 22/91] parse pet nbt --- .../config/features/dev/DebugConfig.java | 5 + .../java/at/hannibal2/skyhanni/data/PetAPI.kt | 146 +++++++++++------- .../data/jsonobjects/repo/NEUPetsJson.kt | 1 + 3 files changed, 92 insertions(+), 60 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/dev/DebugConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/dev/DebugConfig.java index 56a17dfb921b..05f2dcc56b73 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/dev/DebugConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/dev/DebugConfig.java @@ -142,6 +142,11 @@ public class DebugConfig { @ConfigEditorBoolean public boolean oreEventMessages = false; + @Expose + @ConfigOption(name = "Pet Event Messages", desc = "Shows debug messages every time the Pet Event happens.") + @ConfigEditorBoolean + public boolean petEventMessages = false; + @Expose @ConfigOption(name = "Assume Mayor", desc = "Select a mayor to assume.") @ConfigEditorDropdown diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index 7bf998d36701..330bdc695434 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -1,5 +1,6 @@ package at.hannibal2.skyhanni.data +import at.hannibal2.skyhanni.SkyHanniMod import at.hannibal2.skyhanni.data.jsonobjects.repo.NEUPetsJson import at.hannibal2.skyhanni.data.model.TabWidget import at.hannibal2.skyhanni.events.DebugDataCollectEvent @@ -14,16 +15,22 @@ import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.test.command.ErrorManager import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.ItemCategory +import at.hannibal2.skyhanni.utils.ItemUtils.extraAttributes import at.hannibal2.skyhanni.utils.ItemUtils.getItemCategoryOrNull import at.hannibal2.skyhanni.utils.ItemUtils.getLore import at.hannibal2.skyhanni.utils.LorenzRarity import at.hannibal2.skyhanni.utils.NEUInternalName +import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.asInternalName import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.RegexUtils.matches import at.hannibal2.skyhanni.utils.chat.Text.hover import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern +import com.google.gson.Gson +import com.google.gson.JsonObject +import com.google.gson.annotations.SerializedName import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound import net.minecraftforge.fml.common.eventhandler.SubscribeEvent @SkyHanniModule @@ -38,7 +45,8 @@ object PetAPI { private var inPetMenu = false private var xpLeveling: List = listOf() - private var xpLevelingCustom: List = listOf() + private var xpLevelingCustom: JsonObject? = null + private var petRarityOffset = mapOf() /** * REGEX-TEST: §e⭐ §7[Lvl 200] §6Golden Dragon§d ✦ @@ -218,14 +226,14 @@ object PetAPI { fun onWidgetUpdate(event: WidgetUpdateEvent) { if (!event.isWidget(TabWidget.PET)) return - var newPetLine = "" + var newPetLine: String? = null for (line in event.lines) { if (petWidgetPattern.matches(line)) { - newPetLine = line + newPetLine = line.removePrefix(" ") break } } - if (newPetLine == pet?.rawPetName || newPetLine == "") return + if (newPetLine == pet?.rawPetName || newPetLine == null) return var petItem = NEUInternalName.NONE var petXP: Double? = null @@ -398,18 +406,18 @@ object PetAPI { return } - getPetDataFromLore(item.displayName, lore) + getPetDataFromItem(item) } - private fun getPetDataFromLore(displayName: String, lore: List) { - val (name, rarity, _, _, level, _, skin) = parsePetName(displayName) - val (petItem, petXP) = parsePetLore(lore, Pair(rarity, name)) + private fun getPetDataFromItem(item: ItemStack) { + val (_, rarity, petItem, _, _, petXP, _) = parsePetNBT(item.extraAttributes) + val (name, _, _, hasSkin, level, _, skin) = parsePetName(item.displayName) val newPet = PetData( name, rarity, petItem, - skin != "", + hasSkin, level, petXP, "§r§7[Lvl $level] §r${rarity.chatColorCode}$name${if (skin != "") "§r${skin}" else ""}", @@ -417,59 +425,46 @@ object PetAPI { fireEvent(newPet) } + private fun parsePetNBT(nbt: NBTTagCompound): PetData { + val jsonString = nbt.getTag("petInfo").toString() + .replace("\\", "") + .removePrefix("\"") + .removeSuffix("\"") + val petInfo = Gson().fromJson(jsonString, PetNBT::class.java) + + return PetData( + "", + LorenzRarity.getByName(petInfo.tier) ?: LorenzRarity.ULTIMATE, + petInfo.heldItem?.asInternalName() ?: NEUInternalName.NONE, + petInfo.skin != null, + 0, + petInfo.exp, + "" + ) + } + private fun parsePetName(displayName: String): PetData { + var name = "" var level = 0 - var rarity: LorenzRarity = LorenzRarity.ULTIMATE - var petName = "" var skin = "" petNameMenuPattern.matchMatcher(displayName) { + name = group("name") ?: "" level = group("level").toInt() - rarity = LorenzRarity.getByColorCode(group("rarity")[0]) ?: LorenzRarity.ULTIMATE - petName = group("name") skin = group("skin") ?: "" } return PetData( - petName, - rarity, + name, + LorenzRarity.SUPREME, NEUInternalName.NONE, - false, + skin != "", level, 0.0, skin ) } - private fun parsePetLore(lore: List, petInfo: Pair): Pair { - var petItem = NEUInternalName.NONE - var petXP = 0.0 - - lore.forEach { - if (petItem == NEUInternalName.NONE) petItemMenuPattern.matchMatcher(it) { - petItem = NEUInternalName.fromItemNameOrNull(group("item")) ?: ErrorManager.skyHanniError( - "Couldn't parse pet item name.", - Pair("lore", it), - Pair("item", group("item")) - ) - return@forEach - } - if (petXP == 0.0) petXPMenuPattern.matchMatcher(it) { - val totalXP = group("totalXP")?.replace(",", "")?.toDoubleOrNull() ?: 0.0 - val percentage = (group("percentage")?.toDoubleOrNull()?.div(100.0)) ?: 0.0 - - val fromXP = levelToXP(group("level")?.toIntOrNull()?.minus(1) ?: 1, petInfo.first, petInfo.second) ?: 0.0 - val toXP = levelToXP(group("level")?.toIntOrNull() ?: 2, petInfo.first, petInfo.second) ?: 0.0 - - petXP = if (totalXP == 0.0) fromXP + ((toXP - fromXP) * percentage) - else totalXP - return@forEach - } - } - - return Pair(petItem, petXP) - } - fun testLevelToXP(input: Array) { if (input.size >= 3) { val level = input[0].toIntOrNull() @@ -504,28 +499,40 @@ object PetAPI { } private fun getGoldenDragonXP(levelAbove100: Int): Int { - return xpLevelingCustom.slice(0.. 0 - LorenzRarity.UNCOMMON -> 6 - LorenzRarity.RARE -> 11 - LorenzRarity.EPIC -> 16 - LorenzRarity.LEGENDARY -> 20 - LorenzRarity.MYTHIC -> 20 - else -> { - ChatUtils.userError("bad rarity. ${rarity.name}") - null + val customLeveling = xpLevelingCustom?.getAsJsonObject(pet.replace(" ", "_").uppercase())?.getAsJsonObject("rarity_offset") + return if (customLeveling == null) { + when (rarity) { + LorenzRarity.COMMON -> 0 + LorenzRarity.UNCOMMON -> 6 + LorenzRarity.RARE -> 11 + LorenzRarity.EPIC -> 16 + LorenzRarity.LEGENDARY -> 20 + LorenzRarity.MYTHIC -> 20 + else -> { + ChatUtils.userError("bad rarity. ${rarity.name}") + null + } } + } else { + customLeveling.entrySet().associate { (rarity, offset) -> + (LorenzRarity.getByName(rarity) ?: LorenzRarity.ULTIMATE) to offset.asInt + }[rarity] } } private fun fireEvent(newPet: PetData?) { - PetChangeEvent(pet, newPet).post() + val oldPet = pet pet = newPet + if (SkyHanniMod.feature.dev.debug.petEventMessages) { + ChatUtils.debug(oldPet.toString()) + ChatUtils.debug(newPet.toString()) + } + PetChangeEvent(oldPet, newPet).post() } @SubscribeEvent @@ -550,8 +557,27 @@ object PetAPI { fun onNEURepoReload(event: NeuRepositoryReloadEvent) { val data = event.getConstant("pets") xpLeveling = data.pet_levels - val xpLevelingCustomJson = data.custom_pet_leveling.getAsJsonObject("GOLDEN_DRAGON").getAsJsonArray("pet_levels") + val xpLevelingCustomJson = data.custom_pet_leveling.getAsJsonObject() - xpLevelingCustom = xpLevelingCustomJson.map { it.asInt } + xpLevelingCustom = xpLevelingCustomJson + + petRarityOffset = data.pet_rarity_offset.getAsJsonObject().entrySet().associate { (rarity, offset) -> + (LorenzRarity.getByName(rarity) ?: LorenzRarity.ULTIMATE) to offset.asInt + } } } + +data class PetNBT( + @SerializedName("type") val type: String, + @SerializedName("active") val active: Boolean, + @SerializedName("exp") val exp: Double, + @SerializedName("tier") val tier: String, + @SerializedName("hideInfo") val hideInfo: Boolean, + @SerializedName("heldItem") val heldItem: String?, + @SerializedName("candyUsed") val candyUsed: Int, + @SerializedName("skin") val skin: String?, + @SerializedName("uuid") val uuid: String, + @SerializedName("uniqueId") val uniqueId: String, + @SerializedName("hideRightClick") val hideRightClick: Boolean, + @SerializedName("noMove") val noMove: Boolean +) diff --git a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt index 4061c4a7d8d1..f62db77d0508 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt @@ -6,4 +6,5 @@ import com.google.gson.annotations.Expose data class NEUPetsJson( @Expose val pet_levels: List, @Expose val custom_pet_leveling: JsonObject, + @Expose val pet_rarity_offset: JsonObject, ) From 4658db8ed2deed7521ebd5a148cdfdccc5778f96 Mon Sep 17 00:00:00 2001 From: martimavocado Date: Sun, 13 Oct 2024 17:06:01 +0100 Subject: [PATCH 23/91] use more repo data --- .../java/at/hannibal2/skyhanni/data/PetAPI.kt | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index 330bdc695434..ff4920f7df71 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -479,33 +479,33 @@ object PetAPI { return } } - ChatUtils.userError("bad usage. /shcalcpetxp ") + ChatUtils.userError("bad usage. /shcalcpetxp ") } private fun levelToXP(level: Int, rarity: LorenzRarity, petName: String = ""): Double? { - val rarityOffset = getRarityOffset(rarity, petName) ?: return null - if (!isValidLevel(level, petName == "Golden Dragon")) return null + val newPetName = petName.replace(" ", "_").uppercase() + val petObject = xpLevelingCustom?.getAsJsonObject(newPetName) - return if (petName == "Golden Dragon" && level > 100) { - xpLeveling.slice(0 + rarityOffset..<100 + rarityOffset - 1).sum() + getGoldenDragonXP(level - 100).toDouble() - } else { - xpLeveling.slice(0 + rarityOffset..= level } - private fun getGoldenDragonXP(levelAbove100: Int): Int { - val overflowLevels = xpLevelingCustom?.getAsJsonObject("GOLDEN_DRAGON")?.getAsJsonArray()?.map { it.asInt } ?: listOf() - return overflowLevels.slice(0.. { + return petObject?.getAsJsonArray("pet_levels")?.map { it.asInt } ?: listOf() } - private fun getRarityOffset(rarity: LorenzRarity, pet: String = ""): Int? { - val customLeveling = xpLevelingCustom?.getAsJsonObject(pet.replace(" ", "_").uppercase())?.getAsJsonObject("rarity_offset") - return if (customLeveling == null) { + private fun getRarityOffset(rarity: LorenzRarity, petObject: JsonObject?): Int? { + return if (petObject == null) { when (rarity) { LorenzRarity.COMMON -> 0 LorenzRarity.UNCOMMON -> 6 @@ -519,7 +519,7 @@ object PetAPI { } } } else { - customLeveling.entrySet().associate { (rarity, offset) -> + petObject.entrySet().associate { (rarity, offset) -> (LorenzRarity.getByName(rarity) ?: LorenzRarity.ULTIMATE) to offset.asInt }[rarity] } From 0cabf6dff7b0645db4d01a81d7e211ffb544c104 Mon Sep 17 00:00:00 2001 From: martimavocado Date: Sun, 13 Oct 2024 17:33:00 +0100 Subject: [PATCH 24/91] cleanup, use internalname instead of string for pet name --- .../java/at/hannibal2/skyhanni/data/PetAPI.kt | 45 ++++++++++++++----- .../at/hannibal2/skyhanni/data/PetData.kt | 2 +- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index ff4920f7df71..2a4547358b82 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -263,10 +263,12 @@ object PetAPI { LorenzRarity.getByColorCode(group("rarity")[0]) ?: LorenzRarity.ULTIMATE, group("name") )) + val petName = group("name") + val rarity = LorenzRarity.getByColorCode(group("rarity")[0]) ?: LorenzRarity.ULTIMATE val newPet = PetData( - group("name"), - LorenzRarity.getByColorCode(group("rarity")[0]) ?: LorenzRarity.ULTIMATE, + petNametoInternalName(petName, rarity), + rarity, petItem, group("skin") != null, group("level").toInt(), @@ -347,7 +349,7 @@ object PetAPI { val fakePetLine = "§r§7[Lvl $level] §r${rarity.chatColorCode}$petName${if (hasSkin) "§r${group("skin")}" else ""}" val newPet = PetData( - petName, + petNametoInternalName(petName, rarity), rarity, petItem, hasSkin, @@ -433,7 +435,7 @@ object PetAPI { val petInfo = Gson().fromJson(jsonString, PetNBT::class.java) return PetData( - "", + NEUInternalName.NONE, LorenzRarity.getByName(petInfo.tier) ?: LorenzRarity.ULTIMATE, petInfo.heldItem?.asInternalName() ?: NEUInternalName.NONE, petInfo.skin != null, @@ -445,23 +447,25 @@ object PetAPI { private fun parsePetName(displayName: String): PetData { var name = "" + var rarity = LorenzRarity.ULTIMATE var level = 0 var skin = "" petNameMenuPattern.matchMatcher(displayName) { name = group("name") ?: "" + rarity = LorenzRarity.getByColorCode(group("rarity")[0]) ?: LorenzRarity.ULTIMATE level = group("level").toInt() skin = group("skin") ?: "" } return PetData( - name, - LorenzRarity.SUPREME, + petNametoInternalName(name, rarity), + rarity, NEUInternalName.NONE, skin != "", level, 0.0, - skin + skin, ) } @@ -483,7 +487,7 @@ object PetAPI { } private fun levelToXP(level: Int, rarity: LorenzRarity, petName: String = ""): Double? { - val newPetName = petName.replace(" ", "_").uppercase() + val newPetName = petNametoFakeInternalName(petName) val petObject = xpLevelingCustom?.getAsJsonObject(newPetName) val rarityOffset = getRarityOffset(rarity, petObject?.getAsJsonObject("rarity_offset")) ?: return null @@ -528,9 +532,10 @@ object PetAPI { private fun fireEvent(newPet: PetData?) { val oldPet = pet pet = newPet + if (oldPet.arePetsEqual(newPet)) return if (SkyHanniMod.feature.dev.debug.petEventMessages) { - ChatUtils.debug(oldPet.toString()) - ChatUtils.debug(newPet.toString()) + ChatUtils.debug(oldPet.toString().replace("§", "&")) + ChatUtils.debug(newPet.toString().replace("§", "&")) } PetChangeEvent(oldPet, newPet).post() } @@ -565,6 +570,26 @@ object PetAPI { (LorenzRarity.getByName(rarity) ?: LorenzRarity.ULTIMATE) to offset.asInt } } + + private fun petNametoFakeInternalName(petName: String): String { + return when (petName.uppercase()) { + "T-REX" -> "TYRANNOSAURUS" + else -> petName.uppercase().replace(" ", "_") + } + } + + private fun petNametoInternalName(petName: String, rarity: LorenzRarity): NEUInternalName { + return "${petNametoFakeInternalName(petName)};${rarity.id}".asInternalName() + } + + fun PetData?.arePetsEqual(pet2: PetData?): Boolean { + return this?.name == pet2?.name && + this?.rarity == this?.rarity && + this?.petItem == this?.petItem && + this?.hasSkin == this?.hasSkin && + this?.level == this?.level && + this?.rawPetName == this?.rawPetName + } } data class PetNBT( diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetData.kt b/src/main/java/at/hannibal2/skyhanni/data/PetData.kt index 52852479d185..f863bd28c6e8 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetData.kt @@ -4,7 +4,7 @@ import at.hannibal2.skyhanni.utils.LorenzRarity import at.hannibal2.skyhanni.utils.NEUInternalName data class PetData( - val name: String, + val name: NEUInternalName, val rarity: LorenzRarity, val petItem: NEUInternalName, val hasSkin: Boolean, From 975f7d72fe95559be991976ee552aa2df4c2d869 Mon Sep 17 00:00:00 2001 From: martimavocado Date: Mon, 14 Oct 2024 15:52:45 +0100 Subject: [PATCH 25/91] move DiscordStatus.kt to petapi --- .../java/at/hannibal2/skyhanni/data/PetAPI.kt | 17 +++++++++++------ .../java/at/hannibal2/skyhanni/data/PetData.kt | 3 ++- .../features/misc/discordrpc/DiscordStatus.kt | 12 +++++------- .../at/hannibal2/skyhanni/utils/LorenzRarity.kt | 6 ++++++ 4 files changed, 24 insertions(+), 14 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index 2a4547358b82..2a14abe25b9d 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -41,7 +41,7 @@ object PetAPI { "Pets(?: \\(\\d+/\\d+\\) )?", ) - private var pet: PetData? = null + var pet: PetData? = null private var inPetMenu = false private var xpLeveling: List = listOf() @@ -268,6 +268,7 @@ object PetAPI { val newPet = PetData( petNametoInternalName(petName, rarity), + petName, rarity, petItem, group("skin") != null, @@ -350,6 +351,7 @@ object PetAPI { val newPet = PetData( petNametoInternalName(petName, rarity), + petName, rarity, petItem, hasSkin, @@ -412,17 +414,18 @@ object PetAPI { } private fun getPetDataFromItem(item: ItemStack) { - val (_, rarity, petItem, _, _, petXP, _) = parsePetNBT(item.extraAttributes) - val (name, _, _, hasSkin, level, _, skin) = parsePetName(item.displayName) + val (_, _, rarity, petItem, _, _, petXP, _) = parsePetNBT(item.extraAttributes) + val (internalName, name, _, _, hasSkin, level, _, skin) = parsePetName(item.displayName) val newPet = PetData( + internalName, name, rarity, petItem, hasSkin, level, petXP, - "§r§7[Lvl $level] §r${rarity.chatColorCode}$name${if (skin != "") "§r${skin}" else ""}", + "§r§7[Lvl $level] §r${rarity.chatColorCode}$internalName${if (skin != "") "§r${skin}" else ""}", ) fireEvent(newPet) } @@ -436,6 +439,7 @@ object PetAPI { return PetData( NEUInternalName.NONE, + "", LorenzRarity.getByName(petInfo.tier) ?: LorenzRarity.ULTIMATE, petInfo.heldItem?.asInternalName() ?: NEUInternalName.NONE, petInfo.skin != null, @@ -460,6 +464,7 @@ object PetAPI { return PetData( petNametoInternalName(name, rarity), + name, rarity, NEUInternalName.NONE, skin != "", @@ -545,7 +550,7 @@ object PetAPI { event.title("PetAPI") if (pet != null) { event.addIrrelevant { - add("petName: '${pet?.name}'") + add("petName: '${pet?.internalName}'") add("petRarity: '${pet?.rarity}'") add("petItem: '${pet?.petItem}'") add("petHasSkin: '${pet?.hasSkin}'") @@ -583,7 +588,7 @@ object PetAPI { } fun PetData?.arePetsEqual(pet2: PetData?): Boolean { - return this?.name == pet2?.name && + return this?.internalName == pet2?.internalName && this?.rarity == this?.rarity && this?.petItem == this?.petItem && this?.hasSkin == this?.hasSkin && diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetData.kt b/src/main/java/at/hannibal2/skyhanni/data/PetData.kt index f863bd28c6e8..4216901b72f2 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetData.kt @@ -4,7 +4,8 @@ import at.hannibal2.skyhanni.utils.LorenzRarity import at.hannibal2.skyhanni.utils.NEUInternalName data class PetData( - val name: NEUInternalName, + val internalName: NEUInternalName, + val cleanName: String, val rarity: LorenzRarity, val petItem: NEUInternalName, val hasSkin: Boolean, diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt index 708704d68c26..6c0fff62f586 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt @@ -18,7 +18,6 @@ import at.hannibal2.skyhanni.features.misc.compacttablist.AdvancedPlayerList import at.hannibal2.skyhanni.features.rift.RiftAPI import at.hannibal2.skyhanni.utils.InventoryUtils import at.hannibal2.skyhanni.utils.LorenzUtils -import at.hannibal2.skyhanni.utils.LorenzUtils.colorCodeToRarity import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators import at.hannibal2.skyhanni.utils.SimpleTimeMark import at.hannibal2.skyhanni.utils.SkyBlockTime @@ -27,7 +26,6 @@ import at.hannibal2.skyhanni.utils.StringUtils.removeColor import at.hannibal2.skyhanni.utils.TabListData import at.hannibal2.skyhanni.utils.TimeUtils.format import at.hannibal2.skyhanni.utils.TimeUtils.formatted -import io.github.moulberry.notenoughupdates.miscfeatures.PetInfoOverlay.getCurrentPet import net.minecraft.item.ItemStack import net.minecraft.nbt.NBTTagCompound import java.util.regex.Pattern @@ -54,12 +52,12 @@ private fun getVisitingName(): String { var beenAfkFor = SimpleTimeMark.now() -fun getPetDisplay(): String = PetAPI.currentPet?.let { - val colorCode = it.substring(1..2).first() - val petName = it.substring(2).removeColor() - val petLevel = getCurrentPet()?.petLevel?.currentLevel ?: "?" +fun getPetDisplay(): String = PetAPI.pet?.let { + val rarity = PetAPI.pet?.rarity + val petName = PetAPI.pet?.cleanName + val petLevel = PetAPI.pet?.level ?: "?" - "[Lvl $petLevel] ${colorCodeToRarity(colorCode)} $petName" + "[Lvl $petLevel] ${rarity?.getCleanName()} $petName" } ?: "No pet equipped" private fun getCropMilestoneDisplay(): String { diff --git a/src/main/java/at/hannibal2/skyhanni/utils/LorenzRarity.kt b/src/main/java/at/hannibal2/skyhanni/utils/LorenzRarity.kt index 93415947f8c8..9b36cd125e57 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/LorenzRarity.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/LorenzRarity.kt @@ -1,6 +1,7 @@ package at.hannibal2.skyhanni.utils import at.hannibal2.skyhanni.test.command.ErrorManager +import java.util.Locale // TODO: replace id with ordinal enum class LorenzRarity(val color: LorenzColor, val id: Int) { @@ -45,6 +46,11 @@ enum class LorenzRarity(val color: LorenzColor, val id: Int) { return rarityBelow } + fun getCleanName(): String { + return rawName.lowercase(Locale.getDefault()) + .replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() } + } + fun isAtLeast(other: LorenzRarity): Boolean = this.ordinal >= other.ordinal companion object { From 8c36dcade2fe896afaddbc312935dac3a50c4dd2 Mon Sep 17 00:00:00 2001 From: martimavocado Date: Mon, 14 Oct 2024 15:53:42 +0100 Subject: [PATCH 26/91] a --- src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index 2a14abe25b9d..721731c6672d 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -589,6 +589,7 @@ object PetAPI { fun PetData?.arePetsEqual(pet2: PetData?): Boolean { return this?.internalName == pet2?.internalName && + this?.cleanName == this?.cleanName && this?.rarity == this?.rarity && this?.petItem == this?.petItem && this?.hasSkin == this?.hasSkin && From a79f5be5295bac1af64964c9f0df3b7bb092c1c7 Mon Sep 17 00:00:00 2001 From: Cal Date: Tue, 15 Oct 2024 13:42:47 +1100 Subject: [PATCH 27/91] moved command, fixed typos --- .../skyhanni/config/commands/Commands.kt | 6 --- .../java/at/hannibal2/skyhanni/data/PetAPI.kt | 39 ++++++++++++------- .../events/skyblock/PetChangeEvent.kt | 2 +- 3 files changed, 27 insertions(+), 20 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt b/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt index 7c5f8cba34a1..d6454b2b47f6 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt +++ b/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt @@ -8,7 +8,6 @@ import at.hannibal2.skyhanni.config.ConfigGuiManager import at.hannibal2.skyhanni.data.ChatManager import at.hannibal2.skyhanni.data.GardenCropMilestonesCommunityFix import at.hannibal2.skyhanni.data.PartyAPI -import at.hannibal2.skyhanni.data.PetAPI import at.hannibal2.skyhanni.data.SackAPI import at.hannibal2.skyhanni.data.ScoreboardData import at.hannibal2.skyhanni.data.TitleManager @@ -785,11 +784,6 @@ object Commands { category = CommandCategory.DEVELOPER_TEST callback { SkyBlockIslandTest.onCommand(it) } } - event.register("shcalcpetxp") { - description = "Gets the pet xp from a given level and rarity." - category = CommandCategory.DEVELOPER_TEST - callback { PetAPI.testLevelToXP(it) } - } } private fun internalCommands(event: CommandRegistrationEvent) { diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index 721731c6672d..87b5b6eec2d4 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -1,6 +1,9 @@ package at.hannibal2.skyhanni.data import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.api.event.HandleEvent +import at.hannibal2.skyhanni.config.commands.CommandCategory +import at.hannibal2.skyhanni.config.commands.CommandRegistrationEvent import at.hannibal2.skyhanni.data.jsonobjects.repo.NEUPetsJson import at.hannibal2.skyhanni.data.model.TabWidget import at.hannibal2.skyhanni.events.DebugDataCollectEvent @@ -22,6 +25,7 @@ import at.hannibal2.skyhanni.utils.LorenzRarity import at.hannibal2.skyhanni.utils.NEUInternalName import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.asInternalName import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators +import at.hannibal2.skyhanni.utils.NumberUtil.formatDoubleOrNull import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.RegexUtils.matches import at.hannibal2.skyhanni.utils.chat.Text.hover @@ -267,7 +271,7 @@ object PetAPI { val rarity = LorenzRarity.getByColorCode(group("rarity")[0]) ?: LorenzRarity.ULTIMATE val newPet = PetData( - petNametoInternalName(petName, rarity), + petNameToInternalName(petName, rarity), petName, rarity, petItem, @@ -299,8 +303,8 @@ object PetAPI { xpWidgetPattern.matchMatcher(line) { if (group("max") != null) return null - val overflow = group("overflow")?.replace(",", "")?.toDoubleOrNull() ?: 0.0 - val currentXP = group("currentXP")?.replace(",", "")?.toDoubleOrNull() ?: 0.0 + val overflow = group("overflow")?.formatDoubleOrNull() ?: 0.0 + val currentXP = group("currentXP")?.formatDoubleOrNull() ?: 0.0 return overflow + currentXP } @@ -350,7 +354,7 @@ object PetAPI { val fakePetLine = "§r§7[Lvl $level] §r${rarity.chatColorCode}$petName${if (hasSkin) "§r${group("skin")}" else ""}" val newPet = PetData( - petNametoInternalName(petName, rarity), + petNameToInternalName(petName, rarity), petName, rarity, petItem, @@ -373,7 +377,7 @@ object PetAPI { } @SubscribeEvent - fun onOpenInventory(event: InventoryFullyOpenedEvent) { + fun onInventoryOpen(event: InventoryFullyOpenedEvent) { if (!isPetMenu(event.inventoryName)) { inPetMenu = false return @@ -388,12 +392,12 @@ object PetAPI { } @SubscribeEvent - fun onCloseInventory(event: InventoryCloseEvent) { + fun onInventoryClose(event: InventoryCloseEvent) { inPetMenu = false } @SubscribeEvent - fun onItemClick(event: GuiContainerEvent.SlotClickEvent) { + fun onSlotClick(event: GuiContainerEvent.SlotClickEvent) { if (!inPetMenu) return if (event.clickTypeEnum != GuiContainerEvent.ClickType.NORMAL) return val category = event.item?.getItemCategoryOrNull() ?: return @@ -463,7 +467,7 @@ object PetAPI { } return PetData( - petNametoInternalName(name, rarity), + petNameToInternalName(name, rarity), name, rarity, NEUInternalName.NONE, @@ -474,7 +478,16 @@ object PetAPI { ) } - fun testLevelToXP(input: Array) { + @HandleEvent + fun onCommandRegistration(event: CommandRegistrationEvent) { + event.register("shcalcpetxp") { + description = "Gets the pet xp from a given level and rarity." + category = CommandCategory.DEVELOPER_TEST + callback { testLevelToXP(it) } + } + } + + private fun testLevelToXP(input: Array) { if (input.size >= 3) { val level = input[0].toIntOrNull() val rarity = LorenzRarity.getByName(input[1]) @@ -492,7 +505,7 @@ object PetAPI { } private fun levelToXP(level: Int, rarity: LorenzRarity, petName: String = ""): Double? { - val newPetName = petNametoFakeInternalName(petName) + val newPetName = petNameToFakeInternalName(petName) val petObject = xpLevelingCustom?.getAsJsonObject(newPetName) val rarityOffset = getRarityOffset(rarity, petObject?.getAsJsonObject("rarity_offset")) ?: return null @@ -576,15 +589,15 @@ object PetAPI { } } - private fun petNametoFakeInternalName(petName: String): String { + private fun petNameToFakeInternalName(petName: String): String { return when (petName.uppercase()) { "T-REX" -> "TYRANNOSAURUS" else -> petName.uppercase().replace(" ", "_") } } - private fun petNametoInternalName(petName: String, rarity: LorenzRarity): NEUInternalName { - return "${petNametoFakeInternalName(petName)};${rarity.id}".asInternalName() + private fun petNameToInternalName(petName: String, rarity: LorenzRarity): NEUInternalName { + return "${petNameToFakeInternalName(petName)};${rarity.id}".asInternalName() } fun PetData?.arePetsEqual(pet2: PetData?): Boolean { diff --git a/src/main/java/at/hannibal2/skyhanni/events/skyblock/PetChangeEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/skyblock/PetChangeEvent.kt index 0237159c5522..c59a3e7a9b3f 100644 --- a/src/main/java/at/hannibal2/skyhanni/events/skyblock/PetChangeEvent.kt +++ b/src/main/java/at/hannibal2/skyhanni/events/skyblock/PetChangeEvent.kt @@ -4,7 +4,7 @@ import at.hannibal2.skyhanni.api.event.SkyHanniEvent import at.hannibal2.skyhanni.data.PetData /** - * This event fires when a pet change occurs and on joining SkyBlock for the first time in a session. + * This event fires when a pet change occurs and when joining SkyBlock for the first time in a session. * The XP value in the PetData might not be accurate. * * @property oldPet The previous pet before the change. From a3635dea88959b05d6ab410d315c80f9fd684b07 Mon Sep 17 00:00:00 2001 From: martimavocado Date: Wed, 16 Oct 2024 18:59:00 +0100 Subject: [PATCH 28/91] misc review changes --- .../java/at/hannibal2/skyhanni/data/PetAPI.kt | 66 +++++++++---------- .../data/jsonobjects/repo/NEUPetsJson.kt | 7 +- .../hannibal2/skyhanni/utils/LorenzRarity.kt | 10 ++- .../hannibal2/skyhanni/utils/StringUtils.kt | 9 ++- 4 files changed, 48 insertions(+), 44 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index 87b5b6eec2d4..3d975d9a760d 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -28,11 +28,11 @@ import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators import at.hannibal2.skyhanni.utils.NumberUtil.formatDoubleOrNull import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.RegexUtils.matches +import at.hannibal2.skyhanni.utils.StringUtils.convertToUnformatted import at.hannibal2.skyhanni.utils.chat.Text.hover import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern import com.google.gson.Gson import com.google.gson.JsonObject -import com.google.gson.annotations.SerializedName import net.minecraft.item.ItemStack import net.minecraft.nbt.NBTTagCompound import net.minecraftforge.fml.common.eventhandler.SubscribeEvent @@ -46,7 +46,9 @@ object PetAPI { ) var pet: PetData? = null - private var inPetMenu = false + private set + var inPetMenu = false + private set private var xpLeveling: List = listOf() private var xpLevelingCustom: JsonObject? = null @@ -201,10 +203,7 @@ object PetAPI { ProfileStorageData.profileSpecific?.currentPet = value } - @Deprecated(message = "use PetAPI.pet.rawPetName", - replaceWith = ReplaceWith("pet.name.contains(petName) ?: false", "at.hannibal2.skyhanni.data.PetAPI.pet") - ) - fun isCurrentPet(petName: String): Boolean = currentPet?.contains(petName) ?: false + fun isCurrentPet(petName: String): Boolean = pet?.cleanName?.contains(petName) ?: false fun getCleanName(nameWithLevel: String): String? { petItemNamePattern.matchMatcher(nameWithLevel) { @@ -378,7 +377,7 @@ object PetAPI { @SubscribeEvent fun onInventoryOpen(event: InventoryFullyOpenedEvent) { - if (!isPetMenu(event.inventoryName)) { + if (!petMenuPattern.matches(event.inventoryName)) { inPetMenu = false return } @@ -550,10 +549,10 @@ object PetAPI { private fun fireEvent(newPet: PetData?) { val oldPet = pet pet = newPet - if (oldPet.arePetsEqual(newPet)) return + if (newPet == oldPet) return if (SkyHanniMod.feature.dev.debug.petEventMessages) { - ChatUtils.debug(oldPet.toString().replace("§", "&")) - ChatUtils.debug(newPet.toString().replace("§", "&")) + ChatUtils.debug(oldPet.toString().convertToUnformatted()) + ChatUtils.debug(newPet.toString().convertToUnformatted()) } PetChangeEvent(oldPet, newPet).post() } @@ -579,12 +578,12 @@ object PetAPI { @SubscribeEvent fun onNEURepoReload(event: NeuRepositoryReloadEvent) { val data = event.getConstant("pets") - xpLeveling = data.pet_levels - val xpLevelingCustomJson = data.custom_pet_leveling.getAsJsonObject() + xpLeveling = data.petLevels + val xpLevelingCustomJson = data.customPetLeveling.getAsJsonObject() xpLevelingCustom = xpLevelingCustomJson - petRarityOffset = data.pet_rarity_offset.getAsJsonObject().entrySet().associate { (rarity, offset) -> + petRarityOffset = data.petRarityOffset.getAsJsonObject().entrySet().associate { (rarity, offset) -> (LorenzRarity.getByName(rarity) ?: LorenzRarity.ULTIMATE) to offset.asInt } } @@ -600,28 +599,29 @@ object PetAPI { return "${petNameToFakeInternalName(petName)};${rarity.id}".asInternalName() } - fun PetData?.arePetsEqual(pet2: PetData?): Boolean { - return this?.internalName == pet2?.internalName && - this?.cleanName == this?.cleanName && - this?.rarity == this?.rarity && - this?.petItem == this?.petItem && - this?.hasSkin == this?.hasSkin && - this?.level == this?.level && - this?.rawPetName == this?.rawPetName + override fun equals(other: Any?): Boolean { + if (other !is PetData) return false + return this.pet?.internalName == other.internalName && + this.pet?.cleanName == other.cleanName && + this.pet?.rarity == other.rarity && + this.pet?.petItem == other.petItem && + this.pet?.hasSkin == other.hasSkin && + this.pet?.level == other.level && + this.pet?.rawPetName == other.rawPetName } } data class PetNBT( - @SerializedName("type") val type: String, - @SerializedName("active") val active: Boolean, - @SerializedName("exp") val exp: Double, - @SerializedName("tier") val tier: String, - @SerializedName("hideInfo") val hideInfo: Boolean, - @SerializedName("heldItem") val heldItem: String?, - @SerializedName("candyUsed") val candyUsed: Int, - @SerializedName("skin") val skin: String?, - @SerializedName("uuid") val uuid: String, - @SerializedName("uniqueId") val uniqueId: String, - @SerializedName("hideRightClick") val hideRightClick: Boolean, - @SerializedName("noMove") val noMove: Boolean + val type: String, + val active: Boolean, + val exp: Double, + val tier: String, + val hideInfo: Boolean, + val heldItem: String?, + val candyUsed: Int, + val skin: String?, + val uuid: String, + val uniqueId: String, + val hideRightClick: Boolean, + val noMove: Boolean ) diff --git a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt index f62db77d0508..db868461a53a 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt @@ -2,9 +2,10 @@ package at.hannibal2.skyhanni.data.jsonobjects.repo import com.google.gson.JsonObject import com.google.gson.annotations.Expose +import com.google.gson.annotations.SerializedName data class NEUPetsJson( - @Expose val pet_levels: List, - @Expose val custom_pet_leveling: JsonObject, - @Expose val pet_rarity_offset: JsonObject, + @Expose @SerializedName("pet_levels") val petLevels: List, + @Expose @SerializedName("custom_pet_leveling") val customPetLeveling: JsonObject, + @Expose @SerializedName("pet_rarity_offset") val petRarityOffset: JsonObject, ) diff --git a/src/main/java/at/hannibal2/skyhanni/utils/LorenzRarity.kt b/src/main/java/at/hannibal2/skyhanni/utils/LorenzRarity.kt index 9b36cd125e57..0d8a38e509ec 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/LorenzRarity.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/LorenzRarity.kt @@ -1,7 +1,7 @@ package at.hannibal2.skyhanni.utils import at.hannibal2.skyhanni.test.command.ErrorManager -import java.util.Locale +import at.hannibal2.skyhanni.utils.StringUtils.firstLetterUppercase // TODO: replace id with ordinal enum class LorenzRarity(val color: LorenzColor, val id: Int) { @@ -47,8 +47,12 @@ enum class LorenzRarity(val color: LorenzColor, val id: Int) { } fun getCleanName(): String { - return rawName.lowercase(Locale.getDefault()) - .replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() } + val wordArray = rawName.split("_").toTypedArray() + val returnList = mutableListOf() + for (word in wordArray) { + returnList.add(word.firstLetterUppercase()) + } + return returnList.joinToString(" ") } fun isAtLeast(other: LorenzRarity): Boolean = this.ordinal >= other.ordinal diff --git a/src/main/java/at/hannibal2/skyhanni/utils/StringUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/StringUtils.kt index c6de8c13fced..69f1c6a9be20 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/StringUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/StringUtils.kt @@ -15,6 +15,7 @@ import net.minecraft.util.ChatStyle import net.minecraft.util.EnumChatFormatting import net.minecraft.util.IChatComponent import java.util.Base64 +import java.util.Locale import java.util.NavigableMap import java.util.UUID import java.util.function.Predicate @@ -37,11 +38,8 @@ object StringUtils { fun String.removeNonAscii(): String = asciiPattern.matcher(this).replaceAll("") fun String.firstLetterUppercase(): String { - if (isEmpty()) return this - - val lowercase = lowercase() - val first = lowercase[0].uppercase() - return first + lowercase.substring(1) + return this.lowercase(Locale.getDefault()) + .replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() } } private val formattingChars = "kmolnrKMOLNR".toSet() @@ -361,6 +359,7 @@ object StringUtils { } fun String.convertToFormatted(): String = this.replace("&&", "§") + fun String.convertToUnformatted(): String = this.replace("§", "&") @Deprecated("Use the new one instead", ReplaceWith("RegexUtils.matches(string)")) fun Pattern.matches(string: String?): Boolean = string?.let { matcher(it).matches() } ?: false From 90e053a9852a2f5e62b4364bdc42adb5678cfb17 Mon Sep 17 00:00:00 2001 From: martimavocado Date: Wed, 16 Oct 2024 19:00:55 +0100 Subject: [PATCH 29/91] remove skin --- src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt | 11 ++--------- src/main/java/at/hannibal2/skyhanni/data/PetData.kt | 1 - 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index 3d975d9a760d..180e8dd05ca3 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -274,7 +274,6 @@ object PetAPI { petName, rarity, petItem, - group("skin") != null, group("level").toInt(), (xp?.plus(xpOverLevel)) ?: 0.0, newPetLine, @@ -357,7 +356,6 @@ object PetAPI { petName, rarity, petItem, - hasSkin, level, levelToXP(level, rarity, petName) ?: 0.0, fakePetLine, @@ -417,15 +415,14 @@ object PetAPI { } private fun getPetDataFromItem(item: ItemStack) { - val (_, _, rarity, petItem, _, _, petXP, _) = parsePetNBT(item.extraAttributes) - val (internalName, name, _, _, hasSkin, level, _, skin) = parsePetName(item.displayName) + val (_, _, rarity, petItem, _, petXP, _) = parsePetNBT(item.extraAttributes) + val (internalName, name, _, _, level, _, skin) = parsePetName(item.displayName) val newPet = PetData( internalName, name, rarity, petItem, - hasSkin, level, petXP, "§r§7[Lvl $level] §r${rarity.chatColorCode}$internalName${if (skin != "") "§r${skin}" else ""}", @@ -445,7 +442,6 @@ object PetAPI { "", LorenzRarity.getByName(petInfo.tier) ?: LorenzRarity.ULTIMATE, petInfo.heldItem?.asInternalName() ?: NEUInternalName.NONE, - petInfo.skin != null, 0, petInfo.exp, "" @@ -470,7 +466,6 @@ object PetAPI { name, rarity, NEUInternalName.NONE, - skin != "", level, 0.0, skin, @@ -565,7 +560,6 @@ object PetAPI { add("petName: '${pet?.internalName}'") add("petRarity: '${pet?.rarity}'") add("petItem: '${pet?.petItem}'") - add("petHasSkin: '${pet?.hasSkin}'") add("petLevel: '${pet?.level}'") add("petXP: '${pet?.xp}'") add("rawPetLine: '${pet?.rawPetName}'") @@ -605,7 +599,6 @@ object PetAPI { this.pet?.cleanName == other.cleanName && this.pet?.rarity == other.rarity && this.pet?.petItem == other.petItem && - this.pet?.hasSkin == other.hasSkin && this.pet?.level == other.level && this.pet?.rawPetName == other.rawPetName } diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetData.kt b/src/main/java/at/hannibal2/skyhanni/data/PetData.kt index 4216901b72f2..c5be9ec590ed 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetData.kt @@ -8,7 +8,6 @@ data class PetData( val cleanName: String, val rarity: LorenzRarity, val petItem: NEUInternalName, - val hasSkin: Boolean, val level: Int, val xp: Double, val rawPetName: String, From ceddf65acdb62abb15ad74663a4a360621ceb020 Mon Sep 17 00:00:00 2001 From: martimavocado Date: Wed, 16 Oct 2024 19:05:19 +0100 Subject: [PATCH 30/91] is this correct --- src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index 180e8dd05ca3..0b9b5b3b76bf 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -602,6 +602,10 @@ object PetAPI { this.pet?.level == other.level && this.pet?.rawPetName == other.rawPetName } + + override fun hashCode(): Int { + return pet?.hashCode() ?: 0 + } } data class PetNBT( From 971e6c69b1d915fa9daa596145cc6c356f2f327b Mon Sep 17 00:00:00 2001 From: martimavocado Date: Wed, 16 Oct 2024 19:10:06 +0100 Subject: [PATCH 31/91] use neurepo for custom display to internalname --- src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt | 8 ++++---- .../skyhanni/data/jsonobjects/repo/NEUPetsJson.kt | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index 0b9b5b3b76bf..bd1425a06119 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -53,6 +53,7 @@ object PetAPI { private var xpLeveling: List = listOf() private var xpLevelingCustom: JsonObject? = null private var petRarityOffset = mapOf() + private var displayToInternalNameCustom = mapOf() /** * REGEX-TEST: §e⭐ §7[Lvl 200] §6Golden Dragon§d ✦ @@ -580,13 +581,12 @@ object PetAPI { petRarityOffset = data.petRarityOffset.getAsJsonObject().entrySet().associate { (rarity, offset) -> (LorenzRarity.getByName(rarity) ?: LorenzRarity.ULTIMATE) to offset.asInt } + displayToInternalNameCustom = data.displayToInternalName } private fun petNameToFakeInternalName(petName: String): String { - return when (petName.uppercase()) { - "T-REX" -> "TYRANNOSAURUS" - else -> petName.uppercase().replace(" ", "_") - } + return if (petName in displayToInternalNameCustom) displayToInternalNameCustom[petName].toString() + else petName.uppercase().replace(" ", "_") } private fun petNameToInternalName(petName: String, rarity: LorenzRarity): NEUInternalName { diff --git a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt index db868461a53a..915000be635d 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt @@ -1,5 +1,6 @@ package at.hannibal2.skyhanni.data.jsonobjects.repo +import at.hannibal2.skyhanni.utils.NEUInternalName import com.google.gson.JsonObject import com.google.gson.annotations.Expose import com.google.gson.annotations.SerializedName @@ -8,4 +9,5 @@ data class NEUPetsJson( @Expose @SerializedName("pet_levels") val petLevels: List, @Expose @SerializedName("custom_pet_leveling") val customPetLeveling: JsonObject, @Expose @SerializedName("pet_rarity_offset") val petRarityOffset: JsonObject, + @Expose @SerializedName("id_to_display_name") val displayToInternalName: Map ) From d31fae6f3d606d459d9b7bddbf2964ca2d0ef8e9 Mon Sep 17 00:00:00 2001 From: martimavocado Date: Wed, 16 Oct 2024 19:32:51 +0100 Subject: [PATCH 32/91] fix equals and hashcode, make petItem nullable --- .../java/at/hannibal2/skyhanni/data/PetAPI.kt | 18 ++------------- .../at/hannibal2/skyhanni/data/PetData.kt | 23 +++++++++++++++++-- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index bd1425a06119..b580fcbbfb3f 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -442,7 +442,7 @@ object PetAPI { NEUInternalName.NONE, "", LorenzRarity.getByName(petInfo.tier) ?: LorenzRarity.ULTIMATE, - petInfo.heldItem?.asInternalName() ?: NEUInternalName.NONE, + petInfo.heldItem?.asInternalName(), 0, petInfo.exp, "" @@ -466,7 +466,7 @@ object PetAPI { petNameToInternalName(name, rarity), name, rarity, - NEUInternalName.NONE, + null, level, 0.0, skin, @@ -592,20 +592,6 @@ object PetAPI { private fun petNameToInternalName(petName: String, rarity: LorenzRarity): NEUInternalName { return "${petNameToFakeInternalName(petName)};${rarity.id}".asInternalName() } - - override fun equals(other: Any?): Boolean { - if (other !is PetData) return false - return this.pet?.internalName == other.internalName && - this.pet?.cleanName == other.cleanName && - this.pet?.rarity == other.rarity && - this.pet?.petItem == other.petItem && - this.pet?.level == other.level && - this.pet?.rawPetName == other.rawPetName - } - - override fun hashCode(): Int { - return pet?.hashCode() ?: 0 - } } data class PetNBT( diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetData.kt b/src/main/java/at/hannibal2/skyhanni/data/PetData.kt index c5be9ec590ed..1849819a065f 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetData.kt @@ -7,8 +7,27 @@ data class PetData( val internalName: NEUInternalName, val cleanName: String, val rarity: LorenzRarity, - val petItem: NEUInternalName, + val petItem: NEUInternalName?, val level: Int, val xp: Double, val rawPetName: String, -) +) { + override fun equals(other: Any?): Boolean { + if (other !is PetData) return false + return this.internalName == other.internalName && + this.cleanName == other.cleanName && + this.rarity == other.rarity && + this.petItem == other.petItem && + this.level == other.level && + this.rawPetName == other.rawPetName + } + + override fun hashCode(): Int { + var result = cleanName.hashCode() + result = 31 * result + rarity.hashCode() + result = 31 * result + (petItem?.hashCode() ?: 0) + result = 31 * result + level + result = 31 * result + rawPetName.hashCode() + return result + } +} From d95140293d6403e4319b556d0339407deee09b83 Mon Sep 17 00:00:00 2001 From: martimavocado Date: Wed, 16 Oct 2024 20:48:38 +0100 Subject: [PATCH 33/91] fix fakeinternalname --- .../java/at/hannibal2/skyhanni/data/PetAPI.kt | 21 ++++++++++++------- .../data/jsonobjects/repo/NEUPetsJson.kt | 2 +- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index b580fcbbfb3f..a2bd309fb625 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -51,9 +51,9 @@ object PetAPI { private set private var xpLeveling: List = listOf() - private var xpLevelingCustom: JsonObject? = null + private var customXpLeveling: JsonObject? = null private var petRarityOffset = mapOf() - private var displayToInternalNameCustom = mapOf() + private var customDisplayToInternalName = mapOf() /** * REGEX-TEST: §e⭐ §7[Lvl 200] §6Golden Dragon§d ✦ @@ -501,7 +501,7 @@ object PetAPI { private fun levelToXP(level: Int, rarity: LorenzRarity, petName: String = ""): Double? { val newPetName = petNameToFakeInternalName(petName) - val petObject = xpLevelingCustom?.getAsJsonObject(newPetName) + val petObject = customXpLeveling?.getAsJsonObject(newPetName) val rarityOffset = getRarityOffset(rarity, petObject?.getAsJsonObject("rarity_offset")) ?: return null if (!isValidLevel(level, petObject)) return null @@ -576,17 +576,24 @@ object PetAPI { xpLeveling = data.petLevels val xpLevelingCustomJson = data.customPetLeveling.getAsJsonObject() - xpLevelingCustom = xpLevelingCustomJson + customXpLeveling = xpLevelingCustomJson petRarityOffset = data.petRarityOffset.getAsJsonObject().entrySet().associate { (rarity, offset) -> (LorenzRarity.getByName(rarity) ?: LorenzRarity.ULTIMATE) to offset.asInt } - displayToInternalNameCustom = data.displayToInternalName + customDisplayToInternalName = data.displayToInternalName } private fun petNameToFakeInternalName(petName: String): String { - return if (petName in displayToInternalNameCustom) displayToInternalNameCustom[petName].toString() - else petName.uppercase().replace(" ", "_") + var fakeInternalName: String? = null + for ((internalName, name) in customDisplayToInternalName) { + if (petName == name) { + fakeInternalName = internalName.asString() + break + } + } + if (fakeInternalName == null) fakeInternalName = petName.uppercase().replace(" ", "_") + return fakeInternalName } private fun petNameToInternalName(petName: String, rarity: LorenzRarity): NEUInternalName { diff --git a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt index 915000be635d..3d3ea4d78c7a 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt @@ -9,5 +9,5 @@ data class NEUPetsJson( @Expose @SerializedName("pet_levels") val petLevels: List, @Expose @SerializedName("custom_pet_leveling") val customPetLeveling: JsonObject, @Expose @SerializedName("pet_rarity_offset") val petRarityOffset: JsonObject, - @Expose @SerializedName("id_to_display_name") val displayToInternalName: Map + @Expose @SerializedName("id_to_display_name") val displayToInternalName: Map ) From 929dc4180f3a805043d3a35b297519b1e413d84a Mon Sep 17 00:00:00 2001 From: martimavocado Date: Fri, 18 Oct 2024 22:42:02 +0100 Subject: [PATCH 34/91] empa review --- .../java/at/hannibal2/skyhanni/data/PetAPI.kt | 102 ++++++++---------- .../at/hannibal2/skyhanni/data/PetData.kt | 14 +-- 2 files changed, 52 insertions(+), 64 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index a2bd309fb625..39ef2431e106 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -26,6 +26,7 @@ import at.hannibal2.skyhanni.utils.NEUInternalName import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.asInternalName import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators import at.hannibal2.skyhanni.utils.NumberUtil.formatDoubleOrNull +import at.hannibal2.skyhanni.utils.RegexUtils.firstMatches import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.RegexUtils.matches import at.hannibal2.skyhanni.utils.StringUtils.convertToUnformatted @@ -230,72 +231,71 @@ object PetAPI { fun onWidgetUpdate(event: WidgetUpdateEvent) { if (!event.isWidget(TabWidget.PET)) return - var newPetLine: String? = null - for (line in event.lines) { - if (petWidgetPattern.matches(line)) { - newPetLine = line.removePrefix(" ") - break - } - } - if (newPetLine == pet?.rawPetName || newPetLine == null) return + val newPetLine = petWidgetPattern.firstMatches(event.lines)?.trim() ?: return + if (newPetLine == pet?.rawPetName) return - var petItem = NEUInternalName.NONE - var petXP: Double? = null + var newPetData = PetData() + var overflowXP = 0.0 event.lines.forEach { line -> val tempPetItem = handleWidgetStringLine(line) - if (tempPetItem != NEUInternalName.NONE) { - petItem = tempPetItem + if (tempPetItem != null) { + newPetData = newPetData.copy(petItem = tempPetItem) return@forEach } + val tempPetXP = handleWidgetXPLine(line) if (tempPetXP != null) { - petXP = tempPetXP + overflowXP = tempPetXP return@forEach } - } - event.lines.forEach { line -> - if (handleWidgetPetLine(line, petItem, petXP, newPetLine)) return@forEach + val tempPetMisc = handleWidgetPetLine(line, newPetLine) + if (tempPetMisc != null) { + newPetData = newPetData.copy( + internalName = tempPetMisc.internalName, + cleanName = tempPetMisc.cleanName, + rarity = tempPetMisc.rarity, + level = tempPetMisc.level, + xp = tempPetMisc.xp, + rawPetName = tempPetMisc.rawPetName, + ) + return@forEach + } } + fireEvent(newPetData.copy(xp = newPetData.xp + overflowXP)) } - private fun handleWidgetPetLine(line: String, petItem: NEUInternalName, petXP: Double?, newPetLine: String): Boolean { - val xpOverLevel = petXP ?: 0.0 + private fun handleWidgetPetLine(line: String, newPetLine: String): PetData? { petWidgetPattern.matchMatcher(line) { - val xp = (levelToXP( - group("level").toInt(), - LorenzRarity.getByColorCode(group("rarity")[0]) ?: LorenzRarity.ULTIMATE, - group("name") - )) - val petName = group("name") val rarity = LorenzRarity.getByColorCode(group("rarity")[0]) ?: LorenzRarity.ULTIMATE + val petName = group("name") + val level = group("level").toInt() + val xp = levelToXP(level, rarity, petName) ?: return null - val newPet = PetData( + return PetData( petNameToInternalName(petName, rarity), petName, rarity, - petItem, - group("level").toInt(), - (xp?.plus(xpOverLevel)) ?: 0.0, + null, + level, + xp, newPetLine, ) - fireEvent(newPet) - return true } - return false + return null } - private fun handleWidgetStringLine(line: String): NEUInternalName { + private fun handleWidgetStringLine(line: String): NEUInternalName? { widgetStringPattern.matchMatcher(line) { val string = group("string") if (string == "No pet selected") { PetChangeEvent(pet, null).post() pet = null - return NEUInternalName.NONE + return null } return NEUInternalName.fromItemNameOrNull(string) ?: NEUInternalName.NONE } - return NEUInternalName.NONE + return null } private fun handleWidgetXPLine(line: String): Double? { @@ -313,11 +313,7 @@ object PetAPI { @SubscribeEvent fun onChat(event: LorenzChatEvent) { if (autopetMessagePattern.matches(event.message)) { - val hoverMessage = buildList { - event.chatComponent.hover?.siblings?.forEach { - add(it.formattedText) - } - }.toString().split("\n") + val hoverMessage = event.chatComponent.hover?.siblings?.joinToString("")?.split("\n") ?: return var petItem = NEUInternalName.NONE for (it in hoverMessage) { @@ -368,10 +364,9 @@ object PetAPI { } private fun handleAutopetItemMessage(string: String): NEUInternalName? { - autopetHoverPetItemPattern.matchMatcher(string) { - return NEUInternalName.fromItemNameOrNull(group("item")) + return autopetHoverPetItemPattern.matchMatcher(string) { + NEUInternalName.fromItemNameOrNull(group("item")) } - return null } @SubscribeEvent @@ -426,7 +421,7 @@ object PetAPI { petItem, level, petXP, - "§r§7[Lvl $level] §r${rarity.chatColorCode}$internalName${if (skin != "") "§r${skin}" else ""}", + "§r§7[Lvl $level] §r${rarity.chatColorCode}$name${if (skin != "") "§r${skin}" else ""}", ) fireEvent(newPet) } @@ -489,14 +484,14 @@ object PetAPI { val petName = input.slice(2.. ") + ChatUtils.userError("Invalid Usage. /shcalcpetxp ") } private fun levelToXP(level: Int, rarity: LorenzRarity, petName: String = ""): Double? { @@ -531,7 +526,7 @@ object PetAPI { LorenzRarity.LEGENDARY -> 20 LorenzRarity.MYTHIC -> 20 else -> { - ChatUtils.userError("bad rarity. ${rarity.name}") + ChatUtils.userError("Invalid Rarity \"${rarity.name}\"") null } } @@ -547,8 +542,8 @@ object PetAPI { pet = newPet if (newPet == oldPet) return if (SkyHanniMod.feature.dev.debug.petEventMessages) { - ChatUtils.debug(oldPet.toString().convertToUnformatted()) - ChatUtils.debug(newPet.toString().convertToUnformatted()) + ChatUtils.debug("oldPet: " + oldPet.toString().convertToUnformatted()) + ChatUtils.debug("newPet: " + newPet.toString().convertToUnformatted()) } PetChangeEvent(oldPet, newPet).post() } @@ -585,15 +580,8 @@ object PetAPI { } private fun petNameToFakeInternalName(petName: String): String { - var fakeInternalName: String? = null - for ((internalName, name) in customDisplayToInternalName) { - if (petName == name) { - fakeInternalName = internalName.asString() - break - } - } - if (fakeInternalName == null) fakeInternalName = petName.uppercase().replace(" ", "_") - return fakeInternalName + return customDisplayToInternalName.entries.find { it.value == petName }?.key?.asString() + ?: petName.uppercase().replace(" ", "_") } private fun petNameToInternalName(petName: String, rarity: LorenzRarity): NEUInternalName { diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetData.kt b/src/main/java/at/hannibal2/skyhanni/data/PetData.kt index 1849819a065f..136383e99ddf 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetData.kt @@ -4,13 +4,13 @@ import at.hannibal2.skyhanni.utils.LorenzRarity import at.hannibal2.skyhanni.utils.NEUInternalName data class PetData( - val internalName: NEUInternalName, - val cleanName: String, - val rarity: LorenzRarity, - val petItem: NEUInternalName?, - val level: Int, - val xp: Double, - val rawPetName: String, + val internalName: NEUInternalName = NEUInternalName.NONE, + val cleanName: String = "", + val rarity: LorenzRarity = LorenzRarity.ULTIMATE, + val petItem: NEUInternalName? = null, + val level: Int = 0, + val xp: Double = 0.0, + val rawPetName: String = "", ) { override fun equals(other: Any?): Boolean { if (other !is PetData) return false From 17d7c7ab7578da2bc137938a911e2478d1826897 Mon Sep 17 00:00:00 2001 From: martimavocado Date: Fri, 18 Oct 2024 22:47:03 +0100 Subject: [PATCH 35/91] a --- src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index 39ef2431e106..52059fc3c1f1 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -293,7 +293,7 @@ object PetAPI { pet = null return null } - return NEUInternalName.fromItemNameOrNull(string) ?: NEUInternalName.NONE + return NEUInternalName.fromItemNameOrNull(string) } return null } From 3420fb5a16402feee9cbb74227b7cc756515820d Mon Sep 17 00:00:00 2001 From: hannibal2 <24389977+hannibal00212@users.noreply.github.com> Date: Sun, 20 Oct 2024 13:26:45 +0200 Subject: [PATCH 36/91] fix regex test --- src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index 52059fc3c1f1..3cfeb7198eac 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -144,7 +144,7 @@ object PetAPI { */ private val xpWidgetPattern by patternGroup.pattern( "widget.xp", - "^ §r§.(?:§l(?MAX LEVEL)|\\+§r§e(?[\\d,.]+) XP|(?[\\d,.]+)§r§6/§r§e(?[\\d.km]+) XP §r§6\\((?[\\d.%]+)\\))$", + "^ §r§.(?:§l(?MAX LEVEL)|\\+§r§e(?[\\d,.]+) XP|(?[\\d,.]+)§r§6\\/§r§e(?[\\d.km]+) XP §r§6\\((?[\\d.%]+)\\))$", ) /** From 10769ad8ceaa98358283d46fc1e2d42e83fb83a8 Mon Sep 17 00:00:00 2001 From: martimavocado Date: Sun, 20 Oct 2024 16:56:48 +0100 Subject: [PATCH 37/91] misc reviews --- .../java/at/hannibal2/skyhanni/data/PetAPI.kt | 247 +++++++++--------- .../data/jsonobjects/repo/NEUPetsJson.kt | 2 +- .../features/misc/discordrpc/DiscordStatus.kt | 8 +- 3 files changed, 124 insertions(+), 133 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index 3cfeb7198eac..0e0c577825f5 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -25,8 +25,10 @@ import at.hannibal2.skyhanni.utils.LorenzRarity import at.hannibal2.skyhanni.utils.NEUInternalName import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.asInternalName import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators -import at.hannibal2.skyhanni.utils.NumberUtil.formatDoubleOrNull +import at.hannibal2.skyhanni.utils.NumberUtil.formatDouble import at.hannibal2.skyhanni.utils.RegexUtils.firstMatches +import at.hannibal2.skyhanni.utils.RegexUtils.groupOrNull +import at.hannibal2.skyhanni.utils.RegexUtils.hasGroup import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.RegexUtils.matches import at.hannibal2.skyhanni.utils.StringUtils.convertToUnformatted @@ -194,11 +196,13 @@ object PetAPI { "➡", ) - @Deprecated(message = "use PetAPI.inPetMenu") - fun isPetMenu(inventoryTitle: String): Boolean = petMenuPattern.matches(inventoryTitle) + fun isPetMenu(inventoryTitle: String, inventoryItems: Map): Boolean { + if (!petMenuPattern.matches(inventoryTitle)) return false + + val goBackLore = inventoryItems[48]?.getLore() ?: emptyList() + return !goBackLore.any { forgeBackMenuPattern.matches(it) } + } - // Contains color code + name and for older SkyHanni users maybe also the pet level - @Deprecated(message = "use PetAPI.pet.name") var currentPet: String? get() = ProfileStorageData.profileSpecific?.currentPet?.takeIf { it.isNotEmpty() } set(value) { @@ -226,7 +230,6 @@ object PetAPI { @Deprecated(message = "use PetAPI.pet.name") fun hasPetName(name: String): Boolean = petItemNamePattern.matches(name) && !ignoredPetStrings.any { name.contains(it) } -// --- @SubscribeEvent fun onWidgetUpdate(event: WidgetUpdateEvent) { if (!event.isWidget(TabWidget.PET)) return @@ -236,17 +239,17 @@ object PetAPI { var newPetData = PetData() var overflowXP = 0.0 - event.lines.forEach { line -> + for (line in event.lines) { val tempPetItem = handleWidgetStringLine(line) if (tempPetItem != null) { newPetData = newPetData.copy(petItem = tempPetItem) - return@forEach + continue } val tempPetXP = handleWidgetXPLine(line) if (tempPetXP != null) { overflowXP = tempPetXP - return@forEach + continue } val tempPetMisc = handleWidgetPetLine(line, newPetLine) @@ -259,17 +262,17 @@ object PetAPI { xp = tempPetMisc.xp, rawPetName = tempPetMisc.rawPetName, ) - return@forEach + continue } } - fireEvent(newPetData.copy(xp = newPetData.xp + overflowXP)) + updatePet(newPetData.copy(xp = newPetData.xp + overflowXP)) } private fun handleWidgetPetLine(line: String, newPetLine: String): PetData? { - petWidgetPattern.matchMatcher(line) { - val rarity = LorenzRarity.getByColorCode(group("rarity")[0]) ?: LorenzRarity.ULTIMATE - val petName = group("name") - val level = group("level").toInt() + return petWidgetPattern.matchMatcher(line) { + val rarity = LorenzRarity.getByColorCode(groupOrNull("rarity")?.get(0) ?: '4') ?: LorenzRarity.ULTIMATE + val petName = groupOrNull("name") ?: "" + val level = groupOrNull("level")?.toInt() ?: 0 val xp = levelToXP(level, rarity, petName) ?: return null return PetData( @@ -282,11 +285,10 @@ object PetAPI { newPetLine, ) } - return null } private fun handleWidgetStringLine(line: String): NEUInternalName? { - widgetStringPattern.matchMatcher(line) { + return widgetStringPattern.matchMatcher(line) { val string = group("string") if (string == "No pet selected") { PetChangeEvent(pet, null).post() @@ -295,17 +297,13 @@ object PetAPI { } return NEUInternalName.fromItemNameOrNull(string) } - return null } private fun handleWidgetXPLine(line: String): Double? { xpWidgetPattern.matchMatcher(line) { - if (group("max") != null) return null + if (hasGroup("max")) return null - val overflow = group("overflow")?.formatDoubleOrNull() ?: 0.0 - val currentXP = group("currentXP")?.formatDoubleOrNull() ?: 0.0 - - return overflow + currentXP + return group("overflow")?.formatDouble() ?: group("currentXP")?.formatDouble() } return null } @@ -315,17 +313,22 @@ object PetAPI { if (autopetMessagePattern.matches(event.message)) { val hoverMessage = event.chatComponent.hover?.siblings?.joinToString("")?.split("\n") ?: return - var petItem = NEUInternalName.NONE - for (it in hoverMessage) { - val item = handleAutopetItemMessage(it) + var petData = PetData() + var petItem: NEUInternalName? = null + for (line in hoverMessage) { + val item = readAutopetItemMessage(line) if (item != null) { petItem = item - break + continue + } + + val data = readAutopetMessage(line) + if (data != null) { + petData = data + continue } } - hoverMessage.forEach { - if (handleAutopetMessage(it, petItem)) return - } + updatePet(petData.copy(petItem = petItem)) return } petItemMessagePattern.matchMatcher(event.message) { @@ -335,11 +338,11 @@ object PetAPI { Pair("item", group("petItem")) ) val newPet = pet?.copy(petItem = item) ?: return - fireEvent(newPet) + updatePet(newPet) } } - private fun handleAutopetMessage(string: String, petItem: NEUInternalName): Boolean { + private fun readAutopetMessage(string: String): PetData? { autopetHoverPetPattern.matchMatcher(string) { val level = group("level").toInt() val rarity = LorenzRarity.getByColorCode(group("rarity")[0]) ?: LorenzRarity.ULTIMATE @@ -348,22 +351,19 @@ object PetAPI { val fakePetLine = "§r§7[Lvl $level] §r${rarity.chatColorCode}$petName${if (hasSkin) "§r${group("skin")}" else ""}" - val newPet = PetData( - petNameToInternalName(petName, rarity), - petName, - rarity, - petItem, - level, - levelToXP(level, rarity, petName) ?: 0.0, - fakePetLine, + return PetData( + internalName = petNameToInternalName(petName, rarity), + cleanName = petName, + rarity = rarity, + level = level, + xp = levelToXP(level, rarity, petName) ?: 0.0, + rawPetName = fakePetLine, ) - fireEvent(newPet) - return true } - return false + return null } - private fun handleAutopetItemMessage(string: String): NEUInternalName? { + private fun readAutopetItemMessage(string: String): NEUInternalName? { return autopetHoverPetItemPattern.matchMatcher(string) { NEUInternalName.fromItemNameOrNull(group("item")) } @@ -371,17 +371,7 @@ object PetAPI { @SubscribeEvent fun onInventoryOpen(event: InventoryFullyOpenedEvent) { - if (!petMenuPattern.matches(event.inventoryName)) { - inPetMenu = false - return - } - val goBackLore = event.inventoryItems[48]?.getLore() ?: emptyList() - if (goBackLore.any { forgeBackMenuPattern.matches(it) }) { - inPetMenu = false - return - } - - inPetMenu = true + inPetMenu = isPetMenu(event.inventoryName, event.inventoryItems) } @SubscribeEvent @@ -403,7 +393,7 @@ object PetAPI { val lore = item.getLore() if (lore.any { petDespawnMenuPattern.matches(it) }) { - fireEvent(null) + updatePet(null) return } @@ -412,7 +402,7 @@ object PetAPI { private fun getPetDataFromItem(item: ItemStack) { val (_, _, rarity, petItem, _, petXP, _) = parsePetNBT(item.extraAttributes) - val (internalName, name, _, _, level, _, skin) = parsePetName(item.displayName) + val (internalName, name, _, _, level, _, skin) = parsePetName(item.displayName) ?: return val newPet = PetData( internalName, @@ -423,78 +413,87 @@ object PetAPI { petXP, "§r§7[Lvl $level] §r${rarity.chatColorCode}$name${if (skin != "") "§r${skin}" else ""}", ) - fireEvent(newPet) + updatePet(newPet) } private fun parsePetNBT(nbt: NBTTagCompound): PetData { - val jsonString = nbt.getTag("petInfo").toString() + val jsonString = nbt.getString("petInfo") .replace("\\", "") .removePrefix("\"") .removeSuffix("\"") val petInfo = Gson().fromJson(jsonString, PetNBT::class.java) + val rarity = LorenzRarity.getByName(petInfo.tier) ?: ErrorManager.skyHanniError( + "Couldn't parse pet rarity.", + Pair("petNBT", petInfo), + Pair("rarity", petInfo.tier) + ) + return PetData( - NEUInternalName.NONE, - "", - LorenzRarity.getByName(petInfo.tier) ?: LorenzRarity.ULTIMATE, - petInfo.heldItem?.asInternalName(), - 0, - petInfo.exp, - "" + rarity = rarity, + petItem = petInfo.heldItem?.asInternalName(), + xp = petInfo.exp, ) } - private fun parsePetName(displayName: String): PetData { - var name = "" - var rarity = LorenzRarity.ULTIMATE - var level = 0 - var skin = "" - + private fun parsePetName(displayName: String): PetData? { petNameMenuPattern.matchMatcher(displayName) { - name = group("name") ?: "" - rarity = LorenzRarity.getByColorCode(group("rarity")[0]) ?: LorenzRarity.ULTIMATE - level = group("level").toInt() - skin = group("skin") ?: "" - } + val name = group("name") ?: "" + val rarity = LorenzRarity.getByColorCode(group("rarity")[0]) ?: ErrorManager.skyHanniError( + "Couldn't parse pet rarity.", + Pair("displayName", displayName), + Pair("rarity", group("rarity")) + ) + val level = group("level").toInt() + val skin = group("skin") ?: "" - return PetData( - petNameToInternalName(name, rarity), - name, - rarity, - null, - level, - 0.0, - skin, - ) + return PetData( + internalName = petNameToInternalName(name, rarity), + cleanName = name, + rarity = rarity, + level = level, + rawPetName = skin, + ) + } + return null } @HandleEvent fun onCommandRegistration(event: CommandRegistrationEvent) { - event.register("shcalcpetxp") { - description = "Gets the pet xp from a given level and rarity." + event.register("shpetxp") { + description = "Calculates the pet xp from a given level and rarity." category = CommandCategory.DEVELOPER_TEST - callback { testLevelToXP(it) } + callback { levelToXPCommand(it) } } } - private fun testLevelToXP(input: Array) { - if (input.size >= 3) { - val level = input[0].toIntOrNull() - val rarity = LorenzRarity.getByName(input[1]) - val petName = input.slice(2..) { + if (input.size < 3) { + ChatUtils.userError("Usage: /shcalcpetxp ") + return } - ChatUtils.userError("Invalid Usage. /shcalcpetxp ") + + val level = input[0].toIntOrNull() + if (level == null) { + ChatUtils.userError("Invalid level '${input[0]}'.") + return + } + val rarity = LorenzRarity.getByName(input[1]) + if (rarity == null) { + ChatUtils.userError("Invalid rarity '${input[1]}'.") + return + } + + val petName = input.slice(2.. + (LorenzRarity.getByName(rarity) ?: LorenzRarity.ULTIMATE) to offset.asInt + }?.let { it[rarity] } + ?: when (rarity) { LorenzRarity.COMMON -> 0 LorenzRarity.UNCOMMON -> 6 LorenzRarity.RARE -> 11 @@ -530,38 +531,34 @@ object PetAPI { null } } - } else { - petObject.entrySet().associate { (rarity, offset) -> - (LorenzRarity.getByName(rarity) ?: LorenzRarity.ULTIMATE) to offset.asInt - }[rarity] - } } - private fun fireEvent(newPet: PetData?) { + private fun updatePet(newPet: PetData?) { + if (newPet == pet) return val oldPet = pet pet = newPet - if (newPet == oldPet) return if (SkyHanniMod.feature.dev.debug.petEventMessages) { ChatUtils.debug("oldPet: " + oldPet.toString().convertToUnformatted()) ChatUtils.debug("newPet: " + newPet.toString().convertToUnformatted()) } + currentPet = if (newPet == null) null else "§${newPet.rarity.chatColorCode}${newPet.cleanName}" PetChangeEvent(oldPet, newPet).post() } @SubscribeEvent fun onDebug(event: DebugDataCollectEvent) { event.title("PetAPI") - if (pet != null) { - event.addIrrelevant { - add("petName: '${pet?.internalName}'") - add("petRarity: '${pet?.rarity}'") - add("petItem: '${pet?.petItem}'") - add("petLevel: '${pet?.level}'") - add("petXP: '${pet?.xp}'") - add("rawPetLine: '${pet?.rawPetName}'") - } - } else { - event.addData("no pet equipped") + if (pet == null) { + event.addIrrelevant("no pet equipped") + return + } + event.addIrrelevant { + add("petName: '${pet?.internalName}'") + add("petRarity: '${pet?.rarity}'") + add("petItem: '${pet?.petItem}'") + add("petLevel: '${pet?.level}'") + add("petXP: '${pet?.xp}'") + add("rawPetLine: '${pet?.rawPetName}'") } } @@ -576,7 +573,7 @@ object PetAPI { petRarityOffset = data.petRarityOffset.getAsJsonObject().entrySet().associate { (rarity, offset) -> (LorenzRarity.getByName(rarity) ?: LorenzRarity.ULTIMATE) to offset.asInt } - customDisplayToInternalName = data.displayToInternalName + customDisplayToInternalName = data.internalToDisplayName } private fun petNameToFakeInternalName(petName: String): String { diff --git a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt index 3d3ea4d78c7a..a063bcc0d019 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt @@ -9,5 +9,5 @@ data class NEUPetsJson( @Expose @SerializedName("pet_levels") val petLevels: List, @Expose @SerializedName("custom_pet_leveling") val customPetLeveling: JsonObject, @Expose @SerializedName("pet_rarity_offset") val petRarityOffset: JsonObject, - @Expose @SerializedName("id_to_display_name") val displayToInternalName: Map + @Expose @SerializedName("id_to_display_name") val internalToDisplayName: Map ) diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt index 3befd6101363..cc206a7e94e8 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt @@ -52,13 +52,7 @@ private fun getVisitingName(): String { var beenAfkFor = SimpleTimeMark.now() -fun getPetDisplay(): String = PetAPI.pet?.let { - val rarity = PetAPI.pet?.rarity - val petName = PetAPI.pet?.cleanName - val petLevel = PetAPI.pet?.level ?: "?" - - "[Lvl $petLevel] ${rarity?.getCleanName()} $petName" -} ?: "No pet equipped" +fun getPetDisplay(): String = PetAPI.pet?.rawPetName ?: "No pet equipped" private fun getCropMilestoneDisplay(): String { val crop = InventoryUtils.getItemInHand()?.getCropType() From d04ad5df2a6189c1ebbcd3422deeb54de0e29c00 Mon Sep 17 00:00:00 2001 From: martimavocado Date: Sun, 20 Oct 2024 17:06:41 +0100 Subject: [PATCH 38/91] more unknown rarity errors --- .../java/at/hannibal2/skyhanni/data/PetAPI.kt | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index 0e0c577825f5..f6edaf03edc4 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -270,7 +270,9 @@ object PetAPI { private fun handleWidgetPetLine(line: String, newPetLine: String): PetData? { return petWidgetPattern.matchMatcher(line) { - val rarity = LorenzRarity.getByColorCode(groupOrNull("rarity")?.get(0) ?: '4') ?: LorenzRarity.ULTIMATE + val rarity = LorenzRarity.getByColorCode(groupOrNull("rarity")?.get(0) ?: run { + throwUnknownRarity(group("rarity")) + }) ?: throwUnknownRarity(group("rarity")) val petName = groupOrNull("name") ?: "" val level = groupOrNull("level")?.toInt() ?: 0 val xp = levelToXP(level, rarity, petName) ?: return null @@ -345,7 +347,7 @@ object PetAPI { private fun readAutopetMessage(string: String): PetData? { autopetHoverPetPattern.matchMatcher(string) { val level = group("level").toInt() - val rarity = LorenzRarity.getByColorCode(group("rarity")[0]) ?: LorenzRarity.ULTIMATE + val rarity = LorenzRarity.getByColorCode(group("rarity")[0]) ?: throwUnknownRarity(group("rarity")) val petName = group("pet") val hasSkin = group("skin") != null @@ -517,7 +519,10 @@ object PetAPI { private fun getRarityOffset(rarity: LorenzRarity, petObject: JsonObject?): Int? { return petObject?.entrySet()?.associate { (rarity, offset) -> - (LorenzRarity.getByName(rarity) ?: LorenzRarity.ULTIMATE) to offset.asInt + (LorenzRarity.getByName(rarity) ?: run { + ChatUtils.userError("Invalid Rarity '${rarity}''") + return null + }) to offset.asInt }?.let { it[rarity] } ?: when (rarity) { LorenzRarity.COMMON -> 0 @@ -571,7 +576,7 @@ object PetAPI { customXpLeveling = xpLevelingCustomJson petRarityOffset = data.petRarityOffset.getAsJsonObject().entrySet().associate { (rarity, offset) -> - (LorenzRarity.getByName(rarity) ?: LorenzRarity.ULTIMATE) to offset.asInt + (LorenzRarity.getByName(rarity) ?: throwUnknownRarity(rarity)) to offset.asInt } customDisplayToInternalName = data.internalToDisplayName } @@ -584,6 +589,12 @@ object PetAPI { private fun petNameToInternalName(petName: String, rarity: LorenzRarity): NEUInternalName { return "${petNameToFakeInternalName(petName)};${rarity.id}".asInternalName() } + + private fun throwUnknownRarity(badRarity: String): Nothing { + ErrorManager.skyHanniError("Unknown rarity", + Pair("rarity", badRarity) + ) + } } data class PetNBT( From d58dd48472bf3628a712da29c074f67678e21efd Mon Sep 17 00:00:00 2001 From: martimavocado Date: Sun, 20 Oct 2024 20:31:55 +0100 Subject: [PATCH 39/91] fix isPetMenu usages --- src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt | 14 +++++--------- .../garden/fortuneguide/CaptureFarmingGear.kt | 2 +- .../features/misc/pets/CurrentPetDisplay.kt | 2 +- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index f6edaf03edc4..1ab94812c3a0 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -18,7 +18,6 @@ import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.test.command.ErrorManager import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.ItemCategory -import at.hannibal2.skyhanni.utils.ItemUtils.extraAttributes import at.hannibal2.skyhanni.utils.ItemUtils.getItemCategoryOrNull import at.hannibal2.skyhanni.utils.ItemUtils.getLore import at.hannibal2.skyhanni.utils.LorenzRarity @@ -31,13 +30,13 @@ import at.hannibal2.skyhanni.utils.RegexUtils.groupOrNull import at.hannibal2.skyhanni.utils.RegexUtils.hasGroup import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.RegexUtils.matches +import at.hannibal2.skyhanni.utils.SkyBlockItemModifierUtils.getExtraAttributes import at.hannibal2.skyhanni.utils.StringUtils.convertToUnformatted import at.hannibal2.skyhanni.utils.chat.Text.hover import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern import com.google.gson.Gson import com.google.gson.JsonObject import net.minecraft.item.ItemStack -import net.minecraft.nbt.NBTTagCompound import net.minecraftforge.fml.common.eventhandler.SubscribeEvent @SkyHanniModule @@ -403,7 +402,7 @@ object PetAPI { } private fun getPetDataFromItem(item: ItemStack) { - val (_, _, rarity, petItem, _, petXP, _) = parsePetNBT(item.extraAttributes) + val (_, _, rarity, petItem, _, petXP, _) = parsePetNBT(item) val (internalName, name, _, _, level, _, skin) = parsePetName(item.displayName) ?: return val newPet = PetData( @@ -418,13 +417,10 @@ object PetAPI { updatePet(newPet) } - private fun parsePetNBT(nbt: NBTTagCompound): PetData { - val jsonString = nbt.getString("petInfo") - .replace("\\", "") - .removePrefix("\"") - .removeSuffix("\"") - val petInfo = Gson().fromJson(jsonString, PetNBT::class.java) + private fun parsePetNBT(item: ItemStack): PetData { + val petInfo = Gson().fromJson(item.getExtraAttributes()?.getString("petInfo"), PetNBT::class.java) + println(petInfo) val rarity = LorenzRarity.getByName(petInfo.tier) ?: ErrorManager.skyHanniError( "Couldn't parse pet rarity.", Pair("petNBT", petInfo), diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/fortuneguide/CaptureFarmingGear.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/fortuneguide/CaptureFarmingGear.kt index b8337ad15a8c..3d447eaea0c6 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/fortuneguide/CaptureFarmingGear.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/fortuneguide/CaptureFarmingGear.kt @@ -153,7 +153,7 @@ object CaptureFarmingGear { val storage = GardenAPI.storage?.fortune ?: return val outdatedItems = outdatedItems ?: return val items = event.inventoryItems - if (PetAPI.isPetMenu(event.inventoryName)) { + if (PetAPI.isPetMenu(event.inventoryName, event.inventoryItems)) { pets(items, outdatedItems) return } diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt index 6f74f353d46a..10310c3687c3 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt @@ -71,7 +71,7 @@ object CurrentPetDisplay { @SubscribeEvent fun onInventoryOpen(event: InventoryFullyOpenedEvent) { - if (!PetAPI.isPetMenu(event.inventoryName)) return + if (!PetAPI.isPetMenu(event.inventoryName, event.inventoryItems)) return val lore = event.inventoryItems[4]?.getLore() ?: return lore.matchFirst(inventorySelectedPetPattern) { From f7b1ad68bac7a006eb478467fa5ef139bb38fac4 Mon Sep 17 00:00:00 2001 From: martimavocado Date: Tue, 22 Oct 2024 02:42:53 +0100 Subject: [PATCH 40/91] remove petdata default values --- .../java/at/hannibal2/skyhanni/data/PetAPI.kt | 62 +++++++++++++++---- .../at/hannibal2/skyhanni/data/PetData.kt | 12 ++-- 2 files changed, 56 insertions(+), 18 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index 1ab94812c3a0..dc0603f59a33 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -236,12 +236,18 @@ object PetAPI { val newPetLine = petWidgetPattern.firstMatches(event.lines)?.trim() ?: return if (newPetLine == pet?.rawPetName) return - var newPetData = PetData() + var internalName: NEUInternalName? = null + var cleanName: String? = null + var rarity: LorenzRarity? = null + var level: Int? = null + var xp: Double? = null + var rawPetName: String? = null + var petItem: NEUInternalName? = null var overflowXP = 0.0 for (line in event.lines) { val tempPetItem = handleWidgetStringLine(line) if (tempPetItem != null) { - newPetData = newPetData.copy(petItem = tempPetItem) + petItem = tempPetItem continue } @@ -253,17 +259,24 @@ object PetAPI { val tempPetMisc = handleWidgetPetLine(line, newPetLine) if (tempPetMisc != null) { - newPetData = newPetData.copy( - internalName = tempPetMisc.internalName, - cleanName = tempPetMisc.cleanName, - rarity = tempPetMisc.rarity, - level = tempPetMisc.level, - xp = tempPetMisc.xp, - rawPetName = tempPetMisc.rawPetName, - ) + internalName = tempPetMisc.internalName + cleanName = tempPetMisc.cleanName + rarity = tempPetMisc.rarity + level = tempPetMisc.level + xp = tempPetMisc.xp + rawPetName = tempPetMisc.rawPetName continue } } + val newPetData = PetData( + internalName ?: return, + cleanName ?: return, + rarity ?: return, + petItem, + level ?: return, + xp ?: return, + rawPetName ?: return, + ) updatePet(newPetData.copy(xp = newPetData.xp + overflowXP)) } @@ -314,7 +327,12 @@ object PetAPI { if (autopetMessagePattern.matches(event.message)) { val hoverMessage = event.chatComponent.hover?.siblings?.joinToString("")?.split("\n") ?: return - var petData = PetData() + var internalName: NEUInternalName? = null + var cleanName: String? = null + var rarity: LorenzRarity? = null + var level: Int? = null + var xp: Double? = null + var rawPetName: String? = null var petItem: NEUInternalName? = null for (line in hoverMessage) { val item = readAutopetItemMessage(line) @@ -325,10 +343,24 @@ object PetAPI { val data = readAutopetMessage(line) if (data != null) { - petData = data + internalName = data.internalName + cleanName = data.cleanName + rarity = data.rarity + level = data.level + xp = data.xp + rawPetName = data.rawPetName continue } } + val petData = PetData( + internalName ?: return, + cleanName ?: return, + rarity ?: return, + petItem, + level ?: return, + xp ?: return, + rawPetName ?: return, + ) updatePet(petData.copy(petItem = petItem)) return } @@ -428,9 +460,13 @@ object PetAPI { ) return PetData( + internalName = NEUInternalName.NONE, + cleanName = "", + level = 0, rarity = rarity, petItem = petInfo.heldItem?.asInternalName(), xp = petInfo.exp, + rawPetName = "", ) } @@ -449,7 +485,9 @@ object PetAPI { internalName = petNameToInternalName(name, rarity), cleanName = name, rarity = rarity, + petItem = null, level = level, + xp = 0.0, rawPetName = skin, ) } diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetData.kt b/src/main/java/at/hannibal2/skyhanni/data/PetData.kt index 136383e99ddf..c5de2814a2fe 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetData.kt @@ -4,13 +4,13 @@ import at.hannibal2.skyhanni.utils.LorenzRarity import at.hannibal2.skyhanni.utils.NEUInternalName data class PetData( - val internalName: NEUInternalName = NEUInternalName.NONE, - val cleanName: String = "", - val rarity: LorenzRarity = LorenzRarity.ULTIMATE, + val internalName: NEUInternalName, + val cleanName: String, + val rarity: LorenzRarity, val petItem: NEUInternalName? = null, - val level: Int = 0, - val xp: Double = 0.0, - val rawPetName: String = "", + val level: Int, + val xp: Double, + val rawPetName: String, ) { override fun equals(other: Any?): Boolean { if (other !is PetData) return false From d2d19c26262b0201822fc4e3d7006c80237929f1 Mon Sep 17 00:00:00 2001 From: martimavocado Date: Tue, 22 Oct 2024 03:29:19 +0100 Subject: [PATCH 41/91] intellij gave up on me, i give up on this (for now) --- .../java/at/hannibal2/skyhanni/data/PetAPI.kt | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index dc0603f59a33..75db7e52284d 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -57,6 +57,8 @@ object PetAPI { private var petRarityOffset = mapOf() private var customDisplayToInternalName = mapOf() + private var NEUPetsData: Map? = null + /** * REGEX-TEST: §e⭐ §7[Lvl 200] §6Golden Dragon§d ✦ * REGEX-TEST: ⭐ [Lvl 100] Black Cat ✦ @@ -607,7 +609,22 @@ object PetAPI { xpLeveling = data.petLevels val xpLevelingCustomJson = data.customPetLeveling.getAsJsonObject() - customXpLeveling = xpLevelingCustomJson +// customXpLeveling = xpLevelingCustomJson + for ((petName, json) in xpLevelingCustomJson.entrySet()) { + val petData = json.asJsonObject + val type = try { + petData.get("type").asInt + } catch (_: Exception) { + null + } + val data = NEUPetData( + type = petData.get("type").asInt, + petLevels = TODO(), + maxLevel = TODO(), + rarityOffset = TODO(), + xpMultiplier = petData?.get("xp_multiplier")?.asDouble + ) + } petRarityOffset = data.petRarityOffset.getAsJsonObject().entrySet().associate { (rarity, offset) -> (LorenzRarity.getByName(rarity) ?: throwUnknownRarity(rarity)) to offset.asInt @@ -615,9 +632,14 @@ object PetAPI { customDisplayToInternalName = data.internalToDisplayName } + private val nameToInternalNameCache = mutableMapOf() + private fun petNameToFakeInternalName(petName: String): String { - return customDisplayToInternalName.entries.find { it.value == petName }?.key?.asString() + if (petName in nameToInternalNameCache) return nameToInternalNameCache[petName].toString() + val internalName = customDisplayToInternalName.entries.find { it.value == petName }?.key?.asString() ?: petName.uppercase().replace(" ", "_") + nameToInternalNameCache.put(petName, internalName) + return internalName } private fun petNameToInternalName(petName: String, rarity: LorenzRarity): NEUInternalName { @@ -645,3 +667,11 @@ data class PetNBT( val hideRightClick: Boolean, val noMove: Boolean ) + +data class NEUPetData( + val type: Int?, + val petLevels: List?, + val maxLevel: Int?, + val rarityOffset: Map?, + val xpMultiplier: Double?, +) From 82584b92f0ac5394cbb090a6e3231333b4e8f0c6 Mon Sep 17 00:00:00 2001 From: martimavocado Date: Tue, 22 Oct 2024 04:27:39 +0100 Subject: [PATCH 42/91] thanks david for adding detekt --- .../java/at/hannibal2/skyhanni/data/PetAPI.kt | 94 ++++++++----------- 1 file changed, 40 insertions(+), 54 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index 75db7e52284d..3f6656995135 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -54,10 +54,9 @@ object PetAPI { private var xpLeveling: List = listOf() private var customXpLeveling: JsonObject? = null - private var petRarityOffset = mapOf() private var customDisplayToInternalName = mapOf() - private var NEUPetsData: Map? = null + private var petsDataNEU: Map? = null /** * REGEX-TEST: §e⭐ §7[Lvl 200] §6Golden Dragon§d ✦ @@ -82,26 +81,6 @@ object PetAPI { "^(?:§e(?⭐) )?(?:§.)*\\[Lvl (?\\d+)] §(?.)(?[\\w ]+)(?§. ✦)?\$" ) - /** - * REGEX-TEST: §6Held Item: §9Mining Exp Boost - * REGEX-TEST: §6Held Item: §fAll Skills Exp Boost - * REGEX-TEST: §6Held Item: §9Dwarf Turtle Shelmet - */ - private val petItemMenuPattern by patternGroup.pattern( - "menu.pet.item", - "^§6Held Item: (?§.[\\w -]+)\$" - ) - - /** - * REGEX-TEST: §7Progress to Level 45: §e94.4% - * REGEX-TEST: §8▸ 25,396,280 XP - * REGEX-TEST: §7Progress to Level 58: §e3.3% - */ - private val petXPMenuPattern by patternGroup.pattern( - "menu.pet.xp", - "§.(?:Progress to Level (?\\d+): §e(?[\\d.]+)%|▸ (?[\\d,.]+) XP)\$" - ) - /** * REGEX-TEST: §7§cClick to despawn! */ @@ -147,7 +126,7 @@ object PetAPI { */ private val xpWidgetPattern by patternGroup.pattern( "widget.xp", - "^ §r§.(?:§l(?MAX LEVEL)|\\+§r§e(?[\\d,.]+) XP|(?[\\d,.]+)§r§6\\/§r§e(?[\\d.km]+) XP §r§6\\((?[\\d.%]+)\\))$", + "^ §r§.(?:§l(?MAX LEVEL)|\\+§r§e(?[\\d,.]+) XP|(?[\\d,.]+)§r§6/§r§e(?[\\d.km]+) XP §r§6\\((?[\\d.%]+)\\))$", ) /** @@ -284,9 +263,11 @@ object PetAPI { private fun handleWidgetPetLine(line: String, newPetLine: String): PetData? { return petWidgetPattern.matchMatcher(line) { - val rarity = LorenzRarity.getByColorCode(groupOrNull("rarity")?.get(0) ?: run { - throwUnknownRarity(group("rarity")) - }) ?: throwUnknownRarity(group("rarity")) + val rarity = LorenzRarity.getByColorCode( + groupOrNull("rarity")?.get(0) ?: run { + throwUnknownRarity(group("rarity")) + } + ) ?: throwUnknownRarity(group("rarity")) val petName = groupOrNull("name") ?: "" val level = groupOrNull("level")?.toInt() ?: 0 val xp = levelToXP(level, rarity, petName) ?: return null @@ -446,7 +427,7 @@ object PetAPI { petItem, level, petXP, - "§r§7[Lvl $level] §r${rarity.chatColorCode}$name${if (skin != "") "§r${skin}" else ""}", + "§r§7[Lvl $level] §r${rarity.chatColorCode}$name${if (skin != "") "§r$skin" else ""}", ) updatePet(newPet) } @@ -535,10 +516,10 @@ object PetAPI { val newPetName = petNameToFakeInternalName(petName) val petObject = customXpLeveling?.getAsJsonObject(newPetName) - val rarityOffset = getRarityOffset(rarity, petObject?.getAsJsonObject("rarity_offset")) ?: return null + val rarityOffset = getRarityOffset(rarity, newPetName) ?: return null if (!isValidLevel(level, petObject)) return null - val xpList = xpLeveling + getCustomLeveling(petObject) + val xpList = xpLeveling + getCustomLeveling(newPetName) return xpList.slice(0 + rarityOffset..= level } - private fun getCustomLeveling(petObject: JsonObject?): List { - return petObject?.getAsJsonArray("pet_levels")?.map { it.asInt } ?: listOf() + private fun getCustomLeveling(petName: String): List { + return petsDataNEU?.get(petName)?.petLevels ?: listOf() } - private fun getRarityOffset(rarity: LorenzRarity, petObject: JsonObject?): Int? { - return petObject?.entrySet()?.associate { (rarity, offset) -> - (LorenzRarity.getByName(rarity) ?: run { - ChatUtils.userError("Invalid Rarity '${rarity}''") - return null - }) to offset.asInt - }?.let { it[rarity] } - ?: when (rarity) { + private fun getRarityOffset(rarity: LorenzRarity, petName: String): Int? { + val petsData = petsDataNEU ?: run { + ErrorManager.skyHanniError("NEUPetsData is null") + } + + return if (petName in petsData.keys) { + val petData = petsData[petName] + petData?.rarityOffset?.get(rarity) + } else { + when (rarity) { LorenzRarity.COMMON -> 0 LorenzRarity.UNCOMMON -> 6 LorenzRarity.RARE -> 11 @@ -572,6 +555,7 @@ object PetAPI { null } } + } } private fun updatePet(newPet: PetData?) { @@ -609,26 +593,28 @@ object PetAPI { xpLeveling = data.petLevels val xpLevelingCustomJson = data.customPetLeveling.getAsJsonObject() -// customXpLeveling = xpLevelingCustomJson + val map = mutableMapOf() for ((petName, json) in xpLevelingCustomJson.entrySet()) { val petData = json.asJsonObject - val type = try { - petData.get("type").asInt - } catch (_: Exception) { - null + val type = petData.get("type")?.asInt + val maxLevel = petData.get("max_level")?.asInt + val xpMultiplier = petData.get("xp_multiplier")?.asDouble + val petLevels = petData.get("pet_levels")?.asJsonArray?.map { it.asInt } + val rarityOffset = petData.get("rarity_offset")?.asJsonObject?.entrySet()?.associate { (rarity, offset) -> + (LorenzRarity.getByName(rarity) ?: throwUnknownRarity(rarity)) to offset.asInt } - val data = NEUPetData( - type = petData.get("type").asInt, - petLevels = TODO(), - maxLevel = TODO(), - rarityOffset = TODO(), - xpMultiplier = petData?.get("xp_multiplier")?.asDouble + + val dataNEU = NEUPetData( + type = type, + petLevels = petLevels, + maxLevel = maxLevel, + rarityOffset = rarityOffset, + xpMultiplier = xpMultiplier, ) + map[petName] = dataNEU } + petsDataNEU = map - petRarityOffset = data.petRarityOffset.getAsJsonObject().entrySet().associate { (rarity, offset) -> - (LorenzRarity.getByName(rarity) ?: throwUnknownRarity(rarity)) to offset.asInt - } customDisplayToInternalName = data.internalToDisplayName } @@ -638,7 +624,7 @@ object PetAPI { if (petName in nameToInternalNameCache) return nameToInternalNameCache[petName].toString() val internalName = customDisplayToInternalName.entries.find { it.value == petName }?.key?.asString() ?: petName.uppercase().replace(" ", "_") - nameToInternalNameCache.put(petName, internalName) + nameToInternalNameCache[petName] = internalName return internalName } From afb18f8e93f4827a59cc6d1f1efa5c070e98b8b1 Mon Sep 17 00:00:00 2001 From: martimavocado Date: Tue, 22 Oct 2024 17:36:22 +0100 Subject: [PATCH 43/91] detekt --- src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt | 6 +++++- .../hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt | 1 - 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index 3f6656995135..d327db8c757e 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -104,6 +104,7 @@ object PetAPI { * REGEX-TEST: §r§7[Lvl 200] §r§8[§r§6108§r§8§r§4✦§r§8] §r§6Golden Dragon * REGEX-TEST: §r§7[Lvl 100] §r§dBlack Cat§r§d ✦ */ + @Suppress("MaxLineLength") private val petWidgetPattern by patternGroup.pattern( "widget.pet", "^ §r§7\\[Lvl (?\\d+)](?: (?:§.)+\\[(?:§.)+(?\\d+)(?:§.)+✦(?:§.)+])? §r§(?.)(?[\\w ]+)(?:§r(?§. ✦))?\$", @@ -124,6 +125,7 @@ object PetAPI { * REGEX-TEST: §r§6+§r§e21,248,020.7 XP * REGEX-TEST: §r§e15,986.6§r§6/§r§e29k XP §r§6(53.6%) */ + @Suppress("MaxLineLength") private val xpWidgetPattern by patternGroup.pattern( "widget.xp", "^ §r§.(?:§l(?MAX LEVEL)|\\+§r§e(?[\\d,.]+) XP|(?[\\d,.]+)§r§6/§r§e(?[\\d.km]+) XP §r§6\\((?[\\d.%]+)\\))$", @@ -416,6 +418,7 @@ object PetAPI { getPetDataFromItem(item) } + @Suppress("DestructuringDeclarationWithTooManyEntries") private fun getPetDataFromItem(item: ItemStack) { val (_, _, rarity, petItem, _, petXP, _) = parsePetNBT(item) val (internalName, name, _, _, level, _, skin) = parsePetName(item.displayName) ?: return @@ -633,7 +636,8 @@ object PetAPI { } private fun throwUnknownRarity(badRarity: String): Nothing { - ErrorManager.skyHanniError("Unknown rarity", + ErrorManager.skyHanniError( + "Unknown rarity", Pair("rarity", badRarity) ) } diff --git a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt index a063bcc0d019..64e7babce21e 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt @@ -8,6 +8,5 @@ import com.google.gson.annotations.SerializedName data class NEUPetsJson( @Expose @SerializedName("pet_levels") val petLevels: List, @Expose @SerializedName("custom_pet_leveling") val customPetLeveling: JsonObject, - @Expose @SerializedName("pet_rarity_offset") val petRarityOffset: JsonObject, @Expose @SerializedName("id_to_display_name") val internalToDisplayName: Map ) From 365c56653ada8aaac7afef48a4d8bd4de4fbd850 Mon Sep 17 00:00:00 2001 From: martimavocado Date: Tue, 22 Oct 2024 17:56:30 +0100 Subject: [PATCH 44/91] better caching --- .../java/at/hannibal2/skyhanni/data/PetAPI.kt | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index d327db8c757e..657fd8d59475 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -54,10 +54,12 @@ object PetAPI { private var xpLeveling: List = listOf() private var customXpLeveling: JsonObject? = null - private var customDisplayToInternalName = mapOf() private var petsDataNEU: Map? = null + private val nameToFakeInternalNameCache = mutableMapOf() + private val nameToInternalNameCache = mutableMapOf() + /** * REGEX-TEST: §e⭐ §7[Lvl 200] §6Golden Dragon§d ✦ * REGEX-TEST: ⭐ [Lvl 100] Black Cat ✦ @@ -594,7 +596,7 @@ object PetAPI { fun onNEURepoReload(event: NeuRepositoryReloadEvent) { val data = event.getConstant("pets") xpLeveling = data.petLevels - val xpLevelingCustomJson = data.customPetLeveling.getAsJsonObject() + val xpLevelingCustomJson = data.customPetLeveling val map = mutableMapOf() for ((petName, json) in xpLevelingCustomJson.entrySet()) { @@ -618,21 +620,21 @@ object PetAPI { } petsDataNEU = map - customDisplayToInternalName = data.internalToDisplayName + data.internalToDisplayName.forEach { (internalName, displayName) -> + nameToFakeInternalNameCache.put(displayName, internalName.asString()) + } } - private val nameToInternalNameCache = mutableMapOf() - private fun petNameToFakeInternalName(petName: String): String { - if (petName in nameToInternalNameCache) return nameToInternalNameCache[petName].toString() - val internalName = customDisplayToInternalName.entries.find { it.value == petName }?.key?.asString() - ?: petName.uppercase().replace(" ", "_") - nameToInternalNameCache[petName] = internalName - return internalName + return nameToFakeInternalNameCache.getOrPut(petName) { + petName.uppercase().replace(" ", "_") + } } private fun petNameToInternalName(petName: String, rarity: LorenzRarity): NEUInternalName { - return "${petNameToFakeInternalName(petName)};${rarity.id}".asInternalName() + return nameToInternalNameCache.getOrPut("$petName;${rarity.id}") { + "${petNameToFakeInternalName(petName)};${rarity.id}".asInternalName() + } } private fun throwUnknownRarity(badRarity: String): Nothing { From 5008ddf5083f7295e480f0cd6c7a43d10f7342d3 Mon Sep 17 00:00:00 2001 From: martimavocado Date: Tue, 22 Oct 2024 18:09:40 +0100 Subject: [PATCH 45/91] does it work this time --- src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index 657fd8d59475..ccb267701886 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -38,6 +38,7 @@ import com.google.gson.Gson import com.google.gson.JsonObject import net.minecraft.item.ItemStack import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import kotlin.collections.orEmpty @SkyHanniModule object PetAPI { @@ -183,7 +184,7 @@ object PetAPI { fun isPetMenu(inventoryTitle: String, inventoryItems: Map): Boolean { if (!petMenuPattern.matches(inventoryTitle)) return false - val goBackLore = inventoryItems[48]?.getLore() ?: emptyList() + val goBackLore = inventoryItems[48]?.getLore().orEmpty() return !goBackLore.any { forgeBackMenuPattern.matches(it) } } @@ -272,7 +273,7 @@ object PetAPI { throwUnknownRarity(group("rarity")) } ) ?: throwUnknownRarity(group("rarity")) - val petName = groupOrNull("name") ?: "" + val petName = groupOrNull("name").orEmpty() val level = groupOrNull("level")?.toInt() ?: 0 val xp = levelToXP(level, rarity, petName) ?: return null @@ -460,14 +461,14 @@ object PetAPI { private fun parsePetName(displayName: String): PetData? { petNameMenuPattern.matchMatcher(displayName) { - val name = group("name") ?: "" + val name = group("name").orEmpty() val rarity = LorenzRarity.getByColorCode(group("rarity")[0]) ?: ErrorManager.skyHanniError( "Couldn't parse pet rarity.", Pair("displayName", displayName), Pair("rarity", group("rarity")) ) val level = group("level").toInt() - val skin = group("skin") ?: "" + val skin = group("skin").orEmpty() return PetData( internalName = petNameToInternalName(name, rarity), @@ -536,7 +537,7 @@ object PetAPI { } private fun getCustomLeveling(petName: String): List { - return petsDataNEU?.get(petName)?.petLevels ?: listOf() + return petsDataNEU?.get(petName)?.petLevels.orEmpty() } private fun getRarityOffset(rarity: LorenzRarity, petName: String): Int? { From ec3b7e415841ca9e85606fee1f461ccd0c4726d0 Mon Sep 17 00:00:00 2001 From: martimavocado Date: Tue, 22 Oct 2024 18:18:55 +0100 Subject: [PATCH 46/91] i need help why does detekt on my pc not complain as much --- src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index ccb267701886..2f5f0dbe731a 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -35,7 +35,6 @@ import at.hannibal2.skyhanni.utils.StringUtils.convertToUnformatted import at.hannibal2.skyhanni.utils.chat.Text.hover import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern import com.google.gson.Gson -import com.google.gson.JsonObject import net.minecraft.item.ItemStack import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import kotlin.collections.orEmpty @@ -54,8 +53,6 @@ object PetAPI { private set private var xpLeveling: List = listOf() - private var customXpLeveling: JsonObject? = null - private var petsDataNEU: Map? = null private val nameToFakeInternalNameCache = mutableMapOf() @@ -520,19 +517,21 @@ object PetAPI { private fun levelToXP(level: Int, rarity: LorenzRarity, petName: String): Double? { val newPetName = petNameToFakeInternalName(petName) - val petObject = customXpLeveling?.getAsJsonObject(newPetName) val rarityOffset = getRarityOffset(rarity, newPetName) ?: return null - if (!isValidLevel(level, petObject)) return null + if (!isValidLevel(level, newPetName)) return null val xpList = xpLeveling + getCustomLeveling(newPetName) return xpList.slice(0 + rarityOffset..= level } From a969880dcb7a9e040f9abc100a0e1f137c35cc29 Mon Sep 17 00:00:00 2001 From: martimavocado Date: Tue, 22 Oct 2024 19:34:01 +0100 Subject: [PATCH 47/91] i thought this didn't work because i forgot the @Expose --- .../java/at/hannibal2/skyhanni/data/PetAPI.kt | 34 ++----------------- .../data/jsonobjects/repo/NEUPetsJson.kt | 12 +++++-- 2 files changed, 13 insertions(+), 33 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index 2f5f0dbe731a..1f5d25428f24 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -4,6 +4,7 @@ import at.hannibal2.skyhanni.SkyHanniMod import at.hannibal2.skyhanni.api.event.HandleEvent import at.hannibal2.skyhanni.config.commands.CommandCategory import at.hannibal2.skyhanni.config.commands.CommandRegistrationEvent +import at.hannibal2.skyhanni.data.jsonobjects.repo.NEUPetData import at.hannibal2.skyhanni.data.jsonobjects.repo.NEUPetsJson import at.hannibal2.skyhanni.data.model.TabWidget import at.hannibal2.skyhanni.events.DebugDataCollectEvent @@ -35,6 +36,7 @@ import at.hannibal2.skyhanni.utils.StringUtils.convertToUnformatted import at.hannibal2.skyhanni.utils.chat.Text.hover import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern import com.google.gson.Gson +import com.google.gson.annotations.SerializedName import net.minecraft.item.ItemStack import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import kotlin.collections.orEmpty @@ -596,29 +598,7 @@ object PetAPI { fun onNEURepoReload(event: NeuRepositoryReloadEvent) { val data = event.getConstant("pets") xpLeveling = data.petLevels - val xpLevelingCustomJson = data.customPetLeveling - - val map = mutableMapOf() - for ((petName, json) in xpLevelingCustomJson.entrySet()) { - val petData = json.asJsonObject - val type = petData.get("type")?.asInt - val maxLevel = petData.get("max_level")?.asInt - val xpMultiplier = petData.get("xp_multiplier")?.asDouble - val petLevels = petData.get("pet_levels")?.asJsonArray?.map { it.asInt } - val rarityOffset = petData.get("rarity_offset")?.asJsonObject?.entrySet()?.associate { (rarity, offset) -> - (LorenzRarity.getByName(rarity) ?: throwUnknownRarity(rarity)) to offset.asInt - } - - val dataNEU = NEUPetData( - type = type, - petLevels = petLevels, - maxLevel = maxLevel, - rarityOffset = rarityOffset, - xpMultiplier = xpMultiplier, - ) - map[petName] = dataNEU - } - petsDataNEU = map + petsDataNEU = data.customPetLeveling data.internalToDisplayName.forEach { (internalName, displayName) -> nameToFakeInternalNameCache.put(displayName, internalName.asString()) @@ -659,11 +639,3 @@ data class PetNBT( val hideRightClick: Boolean, val noMove: Boolean ) - -data class NEUPetData( - val type: Int?, - val petLevels: List?, - val maxLevel: Int?, - val rarityOffset: Map?, - val xpMultiplier: Double?, -) diff --git a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt index 64e7babce21e..46c8b6fb6d25 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt @@ -1,12 +1,20 @@ package at.hannibal2.skyhanni.data.jsonobjects.repo +import at.hannibal2.skyhanni.utils.LorenzRarity import at.hannibal2.skyhanni.utils.NEUInternalName -import com.google.gson.JsonObject import com.google.gson.annotations.Expose import com.google.gson.annotations.SerializedName data class NEUPetsJson( @Expose @SerializedName("pet_levels") val petLevels: List, - @Expose @SerializedName("custom_pet_leveling") val customPetLeveling: JsonObject, + @Expose @SerializedName("custom_pet_leveling") val customPetLeveling: Map, @Expose @SerializedName("id_to_display_name") val internalToDisplayName: Map ) + +data class NEUPetData( + @Expose @SerializedName("type") val type: Int? = null, + @Expose @SerializedName("pet_levels") val petLevels: List? = null, + @Expose @SerializedName("max_level") val maxLevel: Int? = null, + @Expose @SerializedName("rarity_offset") val rarityOffset: Map? = null, + @Expose @SerializedName("xp_multiplier") val xpMultiplier: Double? = null, +) From 13925e5d73b61d0c00762674da875b46b035ff6c Mon Sep 17 00:00:00 2001 From: hannibal2 <24389977+hannibal00212@users.noreply.github.com> Date: Tue, 22 Oct 2024 20:35:01 +0200 Subject: [PATCH 48/91] code cleanup --- .../java/at/hannibal2/skyhanni/SkyHanniMod.kt | 3 + .../java/at/hannibal2/skyhanni/data/PetAPI.kt | 204 +++++++++--------- 2 files changed, 102 insertions(+), 105 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt index 2c14076a93ba..7ee8303eed7f 100644 --- a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt +++ b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt @@ -14,6 +14,7 @@ import at.hannibal2.skyhanni.data.jsonobjects.local.VisualWordsJson import at.hannibal2.skyhanni.data.repo.RepoManager import at.hannibal2.skyhanni.events.LorenzTickEvent import at.hannibal2.skyhanni.events.utils.PreInitFinishedEvent +import at.hannibal2.skyhanni.features.misc.discordrpc.getPetDisplay import at.hannibal2.skyhanni.features.nether.reputationhelper.CrimsonIsleReputationHelper import at.hannibal2.skyhanni.skyhannimodule.LoadedModules import at.hannibal2.skyhanni.test.command.ErrorManager @@ -48,6 +49,8 @@ class SkyHanniMod { @Mod.EventHandler fun preInit(event: FMLPreInitializationEvent?) { + + getPetDisplay() checkIfNeuIsLoaded() HotswapSupport.load() diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index 2f5f0dbe731a..65a5b371abb0 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -37,11 +37,12 @@ import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern import com.google.gson.Gson import net.minecraft.item.ItemStack import net.minecraftforge.fml.common.eventhandler.SubscribeEvent -import kotlin.collections.orEmpty @SkyHanniModule object PetAPI { private val patternGroup = RepoPattern.group("misc.pet") + + //TODO add regex test private val petMenuPattern by patternGroup.pattern( "menu.title", "Pets(?: \\(\\d+/\\d+\\) )?", @@ -78,7 +79,7 @@ object PetAPI { */ private val petNameMenuPattern by patternGroup.pattern( "menu.pet.name", - "^(?:§e(?⭐) )?(?:§.)*\\[Lvl (?\\d+)] §(?.)(?[\\w ]+)(?§. ✦)?\$" + "^(?:§e(?⭐) )?(?:§.)*\\[Lvl (?\\d+)] §(?.)(?[\\w ]+)(?§. ✦)?\$", ) /** @@ -86,7 +87,7 @@ object PetAPI { */ private val petDespawnMenuPattern by patternGroup.pattern( "menu.pet.despawn", - "§7§cClick to despawn!" + "§7§cClick to despawn!", ) /** @@ -96,7 +97,7 @@ object PetAPI { */ private val forgeBackMenuPattern by patternGroup.pattern( "menu.forge.goback", - "§7To Select Process \\(Slot #\\d\\)" + "§7To Select Process \\(Slot #\\d\\)", ) /** @@ -138,7 +139,7 @@ object PetAPI { */ private val autopetMessagePattern by patternGroup.pattern( "chat.autopet", - "^§cAutopet §eequipped your §7(?\\[Lvl \\d{1,3}] §.[\\w ]+)(?:§. ✦)?§e! §a§lVIEW RULE\$" + "^§cAutopet §eequipped your §7(?\\[Lvl \\d{1,3}] §.[\\w ]+)(?:§. ✦)?§e! §a§lVIEW RULE\$", ) /** @@ -148,7 +149,7 @@ object PetAPI { */ private val autopetHoverPetPattern by patternGroup.pattern( "chat.autopet.hover.pet", - "^§r, §aEquip: §r,(?: §e⭐ §r,)? §7\\[Lvl (?\\d+)] §r, §(?.)(?[\\w ]+)(?:§r, (?§. ✦))?\$" + "^§r, §aEquip: §r,(?: §e⭐ §r,)? §7\\[Lvl (?\\d+)] §r, §(?.)(?[\\w ]+)(?:§r, (?§. ✦))?\$", ) /** @@ -158,7 +159,7 @@ object PetAPI { */ private val autopetHoverPetItemPattern by patternGroup.pattern( "chat.autopet.hover.item", - "^§r, §aHeld Item: §r, (?§.[\\w -]+)§r]\$" + "^§r, §aHeld Item: §r, (?§.[\\w -]+)§r]\$", ) /** @@ -166,7 +167,7 @@ object PetAPI { */ private val petItemMessagePattern by patternGroup.pattern( "chat.pet.item.equip", - "^§aYour pet is now holding §r(?§.[\\w -]+)§r§a\\.\$" + "^§aYour pet is now holding §r(?§.[\\w -]+)§r§a\\.\$", ) private val ignoredPetStrings = listOf( @@ -263,128 +264,121 @@ object PetAPI { updatePet(newPetData.copy(xp = newPetData.xp + overflowXP)) } - private fun handleWidgetPetLine(line: String, newPetLine: String): PetData? { - return petWidgetPattern.matchMatcher(line) { - val rarity = LorenzRarity.getByColorCode( - groupOrNull("rarity")?.get(0) ?: run { - throwUnknownRarity(group("rarity")) - } - ) ?: throwUnknownRarity(group("rarity")) - val petName = groupOrNull("name").orEmpty() - val level = groupOrNull("level")?.toInt() ?: 0 - val xp = levelToXP(level, rarity, petName) ?: return null + private fun handleWidgetPetLine(line: String, newPetLine: String): PetData? = petWidgetPattern.matchMatcher(line) { + val rarity = LorenzRarity.getByColorCode( + groupOrNull("rarity")?.get(0) ?: run { + throwUnknownRarity(group("rarity")) + }, + ) ?: throwUnknownRarity(group("rarity")) + val petName = groupOrNull("name").orEmpty() + val level = groupOrNull("level")?.toInt() ?: 0 + val xp = levelToXP(level, rarity, petName) ?: return null - return PetData( - petNameToInternalName(petName, rarity), - petName, - rarity, - null, - level, - xp, - newPetLine, - ) - } + return PetData( + petNameToInternalName(petName, rarity), + petName, + rarity, + null, + level, + xp, + newPetLine, + ) } - private fun handleWidgetStringLine(line: String): NEUInternalName? { - return widgetStringPattern.matchMatcher(line) { - val string = group("string") - if (string == "No pet selected") { - PetChangeEvent(pet, null).post() - pet = null - return null - } - return NEUInternalName.fromItemNameOrNull(string) + private fun handleWidgetStringLine(line: String): NEUInternalName? = widgetStringPattern.matchMatcher(line) { + val string = group("string") + if (string == "No pet selected") { + PetChangeEvent(pet, null).post() + pet = null + return null } + return NEUInternalName.fromItemNameOrNull(string) } - private fun handleWidgetXPLine(line: String): Double? { - xpWidgetPattern.matchMatcher(line) { - if (hasGroup("max")) return null + private fun handleWidgetXPLine(line: String): Double? = xpWidgetPattern.matchMatcher(line) { + if (hasGroup("max")) return null - return group("overflow")?.formatDouble() ?: group("currentXP")?.formatDouble() - } - return null + group("overflow")?.formatDouble() ?: group("currentXP")?.formatDouble() } @SubscribeEvent fun onChat(event: LorenzChatEvent) { if (autopetMessagePattern.matches(event.message)) { - val hoverMessage = event.chatComponent.hover?.siblings?.joinToString("")?.split("\n") ?: return - - var internalName: NEUInternalName? = null - var cleanName: String? = null - var rarity: LorenzRarity? = null - var level: Int? = null - var xp: Double? = null - var rawPetName: String? = null - var petItem: NEUInternalName? = null - for (line in hoverMessage) { - val item = readAutopetItemMessage(line) - if (item != null) { - petItem = item - continue - } - - val data = readAutopetMessage(line) - if (data != null) { - internalName = data.internalName - cleanName = data.cleanName - rarity = data.rarity - level = data.level - xp = data.xp - rawPetName = data.rawPetName - continue - } - } - val petData = PetData( - internalName ?: return, - cleanName ?: return, - rarity ?: return, - petItem, - level ?: return, - xp ?: return, - rawPetName ?: return, - ) - updatePet(petData.copy(petItem = petItem)) + onAutopetMessage(event) return } petItemMessagePattern.matchMatcher(event.message) { val item = NEUInternalName.fromItemNameOrNull(group("petItem")) ?: ErrorManager.skyHanniError( "Couldn't parse pet item name.", Pair("message", event.message), - Pair("item", group("petItem")) + Pair("item", group("petItem")), ) val newPet = pet?.copy(petItem = item) ?: return updatePet(newPet) } } - private fun readAutopetMessage(string: String): PetData? { - autopetHoverPetPattern.matchMatcher(string) { - val level = group("level").toInt() - val rarity = LorenzRarity.getByColorCode(group("rarity")[0]) ?: throwUnknownRarity(group("rarity")) - val petName = group("pet") - val hasSkin = group("skin") != null + // TODO change this function to be less confusing + private fun onAutopetMessage(event: LorenzChatEvent) { + val hoverMessage = event.chatComponent.hover?.siblings?.joinToString("")?.split("\n") ?: return - val fakePetLine = "§r§7[Lvl $level] §r${rarity.chatColorCode}$petName${if (hasSkin) "§r${group("skin")}" else ""}" + var internalName: NEUInternalName? = null + var cleanName: String? = null + var rarity: LorenzRarity? = null + var level: Int? = null + var xp: Double? = null + var rawPetName: String? = null + var petItem: NEUInternalName? = null + for (line in hoverMessage) { + val item = readAutopetItemMessage(line) + if (item != null) { + petItem = item + continue + } - return PetData( - internalName = petNameToInternalName(petName, rarity), - cleanName = petName, - rarity = rarity, - level = level, - xp = levelToXP(level, rarity, petName) ?: 0.0, - rawPetName = fakePetLine, - ) + val data = readAutopetMessage(line) + if (data != null) { + internalName = data.internalName + cleanName = data.cleanName + rarity = data.rarity + level = data.level + xp = data.xp + rawPetName = data.rawPetName + continue + } } - return null + val petData = PetData( + internalName ?: return, + cleanName ?: return, + rarity ?: return, + petItem, + level ?: return, + xp ?: return, + rawPetName ?: return, + ) + updatePet(petData.copy(petItem = petItem)) } - private fun readAutopetItemMessage(string: String): NEUInternalName? { - return autopetHoverPetItemPattern.matchMatcher(string) { - NEUInternalName.fromItemNameOrNull(group("item")) - } + private fun readAutopetMessage(string: String): PetData? = autopetHoverPetPattern.matchMatcher(string) { + val level = group("level").toInt() + val rarity = LorenzRarity.getByColorCode(group("rarity")[0]) ?: throwUnknownRarity(group("rarity")) + val petName = group("pet") + val hasSkin = group("skin") != null + + val fakePetLine = "§r§7[Lvl $level] §r${rarity.chatColorCode}$petName${if (hasSkin) "§r${group("skin")}" else ""}" + + return PetData( + internalName = petNameToInternalName(petName, rarity), + cleanName = petName, + rarity = rarity, + level = level, + xp = levelToXP(level, rarity, petName) ?: 0.0, + rawPetName = fakePetLine, + ) + } + + private fun readAutopetItemMessage(string: String): NEUInternalName? = autopetHoverPetItemPattern.matchMatcher(string) { + NEUInternalName.fromItemNameOrNull(group("item")) } @SubscribeEvent @@ -442,7 +436,7 @@ object PetAPI { val rarity = LorenzRarity.getByName(petInfo.tier) ?: ErrorManager.skyHanniError( "Couldn't parse pet rarity.", Pair("petNBT", petInfo), - Pair("rarity", petInfo.tier) + Pair("rarity", petInfo.tier), ) return PetData( @@ -462,7 +456,7 @@ object PetAPI { val rarity = LorenzRarity.getByColorCode(group("rarity")[0]) ?: ErrorManager.skyHanniError( "Couldn't parse pet rarity.", Pair("displayName", displayName), - Pair("rarity", group("rarity")) + Pair("rarity", group("rarity")), ) val level = group("level").toInt() val skin = group("skin").orEmpty() @@ -640,7 +634,7 @@ object PetAPI { private fun throwUnknownRarity(badRarity: String): Nothing { ErrorManager.skyHanniError( "Unknown rarity", - Pair("rarity", badRarity) + Pair("rarity", badRarity), ) } } @@ -657,7 +651,7 @@ data class PetNBT( val uuid: String, val uniqueId: String, val hideRightClick: Boolean, - val noMove: Boolean + val noMove: Boolean, ) data class NEUPetData( From a254f69354cf42a776dcf742a457f56d53f391bc Mon Sep 17 00:00:00 2001 From: hannibal2 <24389977+hannibal00212@users.noreply.github.com> Date: Tue, 22 Oct 2024 20:35:23 +0200 Subject: [PATCH 49/91] removed test --- src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt index 7ee8303eed7f..2c14076a93ba 100644 --- a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt +++ b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt @@ -14,7 +14,6 @@ import at.hannibal2.skyhanni.data.jsonobjects.local.VisualWordsJson import at.hannibal2.skyhanni.data.repo.RepoManager import at.hannibal2.skyhanni.events.LorenzTickEvent import at.hannibal2.skyhanni.events.utils.PreInitFinishedEvent -import at.hannibal2.skyhanni.features.misc.discordrpc.getPetDisplay import at.hannibal2.skyhanni.features.nether.reputationhelper.CrimsonIsleReputationHelper import at.hannibal2.skyhanni.skyhannimodule.LoadedModules import at.hannibal2.skyhanni.test.command.ErrorManager @@ -49,8 +48,6 @@ class SkyHanniMod { @Mod.EventHandler fun preInit(event: FMLPreInitializationEvent?) { - - getPetDisplay() checkIfNeuIsLoaded() HotswapSupport.load() From 32f6be7aa34f077456251860b31c4731c6ea1cfe Mon Sep 17 00:00:00 2001 From: David Cole <40234707+DavidArthurCole@users.noreply.github.com> Date: Tue, 10 Dec 2024 01:34:35 -0500 Subject: [PATCH 50/91] Inital round of fixes, imps --- .idea/dictionaries/default_user.xml | 6 +- .../storage/ProfileSpecificStorage.java | 3 +- .../java/at/hannibal2/skyhanni/data/PetAPI.kt | 709 ++++++++++-------- .../at/hannibal2/skyhanni/data/PetData.kt | 21 +- .../features/garden/fortuneguide/FFStats.kt | 6 +- .../ExperimentationTableAPI.kt | 5 +- .../features/misc/discordrpc/DiscordStatus.kt | 386 +++++----- .../features/misc/pets/CurrentPetDisplay.kt | 67 +- .../at/hannibal2/skyhanni/utils/ItemUtils.kt | 28 +- .../at/hannibal2/skyhanni/utils/RegexUtils.kt | 3 + .../utils/SkyBlockItemModifierUtils.kt | 7 +- 11 files changed, 642 insertions(+), 599 deletions(-) diff --git a/.idea/dictionaries/default_user.xml b/.idea/dictionaries/default_user.xml index 6b10b0a8ed68..06e3e9025513 100644 --- a/.idea/dictionaries/default_user.xml +++ b/.idea/dictionaries/default_user.xml @@ -61,6 +61,7 @@ demonlord derpy despawn + despawned dicer disintegrator disintegrators @@ -70,6 +71,7 @@ dreadlord dungeoneering dwarven + eequipped egglocator einary einary's @@ -94,6 +96,7 @@ ghast glacite glowstone + goback goldor golem gratitudes @@ -228,6 +231,7 @@ sethome shcopytranslation shcropstartlocation + shelmet shlanedetection shmarkplayer shmouselock @@ -286,4 +290,4 @@ yolkar - + \ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java b/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java index 5a5e884e0427..cc178da739f6 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java +++ b/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java @@ -4,6 +4,7 @@ import at.hannibal2.skyhanni.api.SkillAPI; import at.hannibal2.skyhanni.data.IslandType; import at.hannibal2.skyhanni.data.MaxwellAPI; +import at.hannibal2.skyhanni.data.PetData; import at.hannibal2.skyhanni.data.jsonobjects.local.HotmTree; import at.hannibal2.skyhanni.data.model.ComposterUpgrade; import at.hannibal2.skyhanni.data.model.SkyblockStat; @@ -66,7 +67,7 @@ private static SimpleTimeMark SimpleTimeMarkFarPast() { } @Expose - public String currentPet = ""; + public PetData currentPet = new PetData(); @Expose public ExperimentationStorage experimentation = new ExperimentationStorage(); diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index 4ff5771540fb..2ba5f6f52e40 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -26,6 +26,8 @@ import at.hannibal2.skyhanni.utils.NEUInternalName import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.asInternalName import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators import at.hannibal2.skyhanni.utils.NumberUtil.formatDouble +import at.hannibal2.skyhanni.utils.RegexUtils.firstMatchGroup +import at.hannibal2.skyhanni.utils.RegexUtils.firstMatcher import at.hannibal2.skyhanni.utils.RegexUtils.firstMatches import at.hannibal2.skyhanni.utils.RegexUtils.groupOrNull import at.hannibal2.skyhanni.utils.RegexUtils.hasGroup @@ -36,36 +38,71 @@ import at.hannibal2.skyhanni.utils.StringUtils.convertToUnformatted import at.hannibal2.skyhanni.utils.chat.Text.hover import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern import com.google.gson.Gson -import com.google.gson.annotations.SerializedName import net.minecraft.item.ItemStack import net.minecraftforge.fml.common.eventhandler.SubscribeEvent @SkyHanniModule object PetAPI { + private val config get() = SkyHanniMod.feature.misc.pets private val patternGroup = RepoPattern.group("misc.pet") + private const val FORGE_BACK_SLOT = 48 - //TODO add regex test - private val petMenuPattern by patternGroup.pattern( - "menu.title", - "Pets(?: \\(\\d+/\\d+\\) )?", + private var inPetMenu = false + private var baseXpLevelReqs: List = listOf() + private var customXpLevelReqs: Map? = null + + var currentPet: PetData? + get() = ProfileStorageData.profileSpecific?.currentPet?.takeIf { it.isInitialized() } + set(value) { + ProfileStorageData.profileSpecific?.currentPet = value + } + + // + /** + * REGEX-TEST: §7§7Selected pet: §6Hedgehog + */ + private val inventorySelectedPetPattern by patternGroup.pattern( + "inventory.selected", + "§7§7Selected pet: §?(?.)?(?.*)" ) - var pet: PetData? = null - private set - var inPetMenu = false - private set + /** + * REGEX-TEST: §7Progress to Level 91: §e0% + * REGEX-TEST: §7Progress to Level 147: §e37.1% + * REGEX-TEST: §b§lMAX LEVEL + */ + private val inventorySelectedProgressPattern by patternGroup.pattern( + "inventory.selected.progress", + "§b§lMAX LEVEL|§7Progress to Level (?\\d+): §e(?[\\d.]+)%" + ) - private var xpLeveling: List = listOf() - private var petsDataNEU: Map? = null + /** + * REGEX-TEST: §2§l§m §f§l§m §r §e713,241.8§6/§e1.4M + * REGEX-TEST: §2§l§m §f§l§m §r §e699,742.8§6/§e1.9M + * REGEX-TEST: §f§l§m §r §e0§6/§e660 + * REGEX-TEST: §8▸ 30,358,983 XP' + */ + private val inventorySelectedXpPattern by patternGroup.pattern( + "inventory.selected.xp", + "(?:§8▸ |(?:§.§l§m *)*)(?:§r §e)?(?[\\d,.kM]+)(?:§6\\/§e)?(?[\\d,.kM]+)?" + ) - private val nameToFakeInternalNameCache = mutableMapOf() - private val nameToInternalNameCache = mutableMapOf() + /** + * REGEX-TEST: Pets (1/3) + * REGEX-TEST: Pets + * REGEX-TEST: Pets (1/4) + * REGEX-TEST: Pets (1/2) + */ + private val petMenuPattern by patternGroup.pattern( + "menu.title", + "Pets(?: \\(\\d+/\\d+\\) )?", + ) /** * REGEX-TEST: §e⭐ §7[Lvl 200] §6Golden Dragon§d ✦ * REGEX-TEST: ⭐ [Lvl 100] Black Cat ✦ */ - private val petItemNamePattern by patternGroup.pattern( + val petItemNamePattern by patternGroup.pattern( "item.name", "(?(?:§.)*⭐ )?(?:§.)*\\[Lvl (?\\d+)] (?.*)", ) @@ -96,10 +133,11 @@ object PetAPI { * REGEX-TEST: §7To Select Process (Slot #2) * REGEX-TEST: §7To Select Process (Slot #4) * REGEX-TEST: §7To Select Process (Slot #7) + * REGEX-TEST: §7To Select Process */ private val forgeBackMenuPattern by patternGroup.pattern( "menu.forge.goback", - "§7To Select Process \\(Slot #\\d\\)", + "§7To Select Process(?: \\(Slot #\\d\\))?", ) /** @@ -144,6 +182,24 @@ object PetAPI { "^§cAutopet §eequipped your §7(?\\[Lvl \\d{1,3}] §.[\\w ]+)(?:§. ✦)?§e! §a§lVIEW RULE\$", ) + /** + * REGEX-TEST: §aYou despawned your §r§6Golden Dragon§r§a! + * REGEX-TEST: §aYou despawned your §r§6Silverfish§r§5 ✦§r§a! + */ + private val chatDespawnPattern by patternGroup.pattern( + "chat.despawn", + "§aYou despawned your §r.*§r§a!", + ) + + /** + * REGEX-TEST: §aYou summoned your §r§6Silverfish§r§5 ✦§r§a! + * REGEX-TEST: §aYou summoned your §r§6Golden Dragon§r§a! + */ + private val chatSpawnPattern by patternGroup.pattern( + "chat.spawn", + "§aYou summoned your §r(?.*)§r§a!" + ) + /** * REGEX-TEST: §r, §aEquip: §r, §7[Lvl 99] §r, §6Flying Fish * REGEX-TEST: §r, §aEquip: §r, §e⭐ §r, §7[Lvl 100] §r, §dBlack Cat§r, §d ✦ @@ -171,30 +227,19 @@ object PetAPI { "chat.pet.item.equip", "^§aYour pet is now holding §r(?§.[\\w -]+)§r§a\\.\$", ) + // - private val ignoredPetStrings = listOf( - "Archer", - "Berserk", - "Mage", - "Tank", - "Healer", - "➡", - ) - + // fun isPetMenu(inventoryTitle: String, inventoryItems: Map): Boolean { if (!petMenuPattern.matches(inventoryTitle)) return false - val goBackLore = inventoryItems[48]?.getLore().orEmpty() - return !goBackLore.any { forgeBackMenuPattern.matches(it) } - } - - var currentPet: String? - get() = ProfileStorageData.profileSpecific?.currentPet?.takeIf { it.isNotEmpty() } - set(value) { - ProfileStorageData.profileSpecific?.currentPet = value + // Otherwise make sure they're not in the Forge menu looking at pets + return inventoryItems[FORGE_BACK_SLOT]?.getLore().orEmpty().none { + forgeBackMenuPattern.matches(it) } + } - fun isCurrentPet(petName: String): Boolean = pet?.cleanName?.contains(petName) ?: false + fun isCurrentPet(petName: String): Boolean = currentPet?.cleanName?.contains(petName) ?: false fun getCleanName(nameWithLevel: String): String? { petItemNamePattern.matchMatcher(nameWithLevel) { @@ -207,211 +252,102 @@ object PetAPI { return null } - @Deprecated(message = "use PetAPI.pet.level") - fun getPetLevel(nameWithLevel: String): Int? = petItemNamePattern.matchMatcher(nameWithLevel) { - group("level").toInt() - } - - @Deprecated(message = "use PetAPI.pet.name") - fun hasPetName(name: String): Boolean = petItemNamePattern.matches(name) && !ignoredPetStrings.any { name.contains(it) } - - @SubscribeEvent - fun onWidgetUpdate(event: WidgetUpdateEvent) { - if (!event.isWidget(TabWidget.PET)) return - - val newPetLine = petWidgetPattern.firstMatches(event.lines)?.trim() ?: return - if (newPetLine == pet?.rawPetName) return - - var internalName: NEUInternalName? = null - var cleanName: String? = null - var rarity: LorenzRarity? = null - var level: Int? = null - var xp: Double? = null - var rawPetName: String? = null - var petItem: NEUInternalName? = null - var overflowXP = 0.0 - for (line in event.lines) { - val tempPetItem = handleWidgetStringLine(line) - if (tempPetItem != null) { - petItem = tempPetItem - continue - } - - val tempPetXP = handleWidgetXPLine(line) - if (tempPetXP != null) { - overflowXP = tempPetXP - continue - } + private fun petNameToInternalName(name: String, rarity: LorenzRarity): NEUInternalName = + "${name.convertToUnformatted()}${rarity.id}".asInternalName() - val tempPetMisc = handleWidgetPetLine(line, newPetLine) - if (tempPetMisc != null) { - internalName = tempPetMisc.internalName - cleanName = tempPetMisc.cleanName - rarity = tempPetMisc.rarity - level = tempPetMisc.level - xp = tempPetMisc.xp - rawPetName = tempPetMisc.rawPetName - continue - } - } - val newPetData = PetData( - internalName ?: return, - cleanName ?: return, - rarity ?: return, - petItem, - level ?: return, - xp ?: return, - rawPetName ?: return, - ) - updatePet(newPetData.copy(xp = newPetData.xp + overflowXP)) + private fun getFakePetLine(level: Int, rarity: LorenzRarity, petName: String, skin: String? = null): String { + return "§r§7[Lvl $level] §r${rarity.chatColorCode}$petName§r${skin.orEmpty()}" } - private fun handleWidgetPetLine(line: String, newPetLine: String): PetData? = petWidgetPattern.matchMatcher(line) { - val rarity = LorenzRarity.getByColorCode( - groupOrNull("rarity")?.get(0) ?: run { - throwUnknownRarity(group("rarity")) - }, - ) ?: throwUnknownRarity(group("rarity")) - val petName = groupOrNull("name").orEmpty() - val level = groupOrNull("level")?.toInt() ?: 0 - val xp = levelToXP(level, rarity, petName) ?: return null - - return PetData( - petNameToInternalName(petName, rarity), - petName, - rarity, - null, - level, - xp, - newPetLine, + private fun rarityByColorGroup(color: String): LorenzRarity = LorenzRarity.getByColorCode(color[0]) + ?: ErrorManager.skyHanniError( + "Unknown rarity", + Pair("rarity", color), ) - } - private fun handleWidgetStringLine(line: String): NEUInternalName? = widgetStringPattern.matchMatcher(line) { - val string = group("string") - if (string == "No pet selected") { - PetChangeEvent(pet, null).post() - pet = null - return null + private fun levelToXPCommand(input: Array) { + if (input.size < 3) { + ChatUtils.userError("Usage: /shcalcpetxp ") + return } - return NEUInternalName.fromItemNameOrNull(string) - } - - private fun handleWidgetXPLine(line: String): Double? = xpWidgetPattern.matchMatcher(line) { - if (hasGroup("max")) return null - - group("overflow")?.formatDouble() ?: group("currentXP")?.formatDouble() - } - @SubscribeEvent - fun onChat(event: LorenzChatEvent) { - if (autopetMessagePattern.matches(event.message)) { - onAutopetMessage(event) + val level = input[0].toIntOrNull() + if (level == null) { + ChatUtils.userError("Invalid level '${input[0]}'.") return } - petItemMessagePattern.matchMatcher(event.message) { - val item = NEUInternalName.fromItemNameOrNull(group("petItem")) ?: ErrorManager.skyHanniError( - "Couldn't parse pet item name.", - Pair("message", event.message), - Pair("item", group("petItem")), - ) - val newPet = pet?.copy(petItem = item) ?: return - updatePet(newPet) + val rarity = LorenzRarity.getByName(input[1]) + if (rarity == null) { + ChatUtils.userError("Invalid rarity '${input[1]}'.") + return } - } - - // TODO change this function to be less confusing - private fun onAutopetMessage(event: LorenzChatEvent) { - val hoverMessage = event.chatComponent.hover?.siblings?.joinToString("")?.split("\n") ?: return - - var internalName: NEUInternalName? = null - var cleanName: String? = null - var rarity: LorenzRarity? = null - var level: Int? = null - var xp: Double? = null - var rawPetName: String? = null - var petItem: NEUInternalName? = null - for (line in hoverMessage) { - val item = readAutopetItemMessage(line) - if (item != null) { - petItem = item - continue - } - val data = readAutopetMessage(line) - if (data != null) { - internalName = data.internalName - cleanName = data.cleanName - rarity = data.rarity - level = data.level - xp = data.xp - rawPetName = data.rawPetName - continue - } + val petName = input.slice(2..= level } - @SubscribeEvent - fun onSlotClick(event: GuiContainerEvent.SlotClickEvent) { - if (!inPetMenu) return - if (event.clickTypeEnum != GuiContainerEvent.ClickType.NORMAL) return - val category = event.item?.getItemCategoryOrNull() ?: return - if (category != ItemCategory.PET) return - - parsePetAsItem(event.item) + private fun getCustomLeveling(petName: String): List { + return customXpLevelReqs?.get(petName)?.petLevels.orEmpty() } - private fun parsePetAsItem(item: ItemStack) { - val lore = item.getLore() + private fun getRarityOffset(rarity: LorenzRarity, petName: String): Int? { + val petsData = customXpLevelReqs ?: run { + ErrorManager.skyHanniError("NEUPetsData is null") + } - if (lore.any { petDespawnMenuPattern.matches(it) }) { - updatePet(null) - return + return if (petName in petsData.keys) { + val petData = petsData[petName] + petData?.rarityOffset?.get(rarity) + } else { + when (rarity) { + LorenzRarity.COMMON -> 0 + LorenzRarity.UNCOMMON -> 6 + LorenzRarity.RARE -> 11 + LorenzRarity.EPIC -> 16 + LorenzRarity.LEGENDARY -> 20 + LorenzRarity.MYTHIC -> 20 + else -> { + ChatUtils.userError("Invalid Rarity \"${rarity.name}\"") + null + } + } } + } - getPetDataFromItem(item) + private fun updatePet(newPet: PetData?) { + if (newPet == currentPet) return + val oldPet = currentPet + currentPet = newPet + if (SkyHanniMod.feature.dev.debug.petEventMessages) { + ChatUtils.debug("oldPet: " + oldPet.toString().convertToUnformatted()) + ChatUtils.debug("newPet: " + newPet?.toString()?.convertToUnformatted()) + } + PetChangeEvent(oldPet, newPet).post() } @Suppress("DestructuringDeclarationWithTooManyEntries") @@ -426,26 +362,83 @@ object PetAPI { petItem, level, petXP, - "§r§7[Lvl $level] §r${rarity.chatColorCode}$name${if (skin != "") "§r$skin" else ""}", + "§r§7[Lvl $level] §r${rarity?.chatColorCode}$name${if (skin != "") "§r$skin" else ""}", ) updatePet(newPet) } - private fun parsePetNBT(item: ItemStack): PetData { - val petInfo = Gson().fromJson(item.getExtraAttributes()?.getString("petInfo"), PetNBT::class.java) + private fun handlePetMessageBlock(event: LorenzChatEvent) { + if (!config.hideAutopet) return + val spawnMatches = chatSpawnPattern.matches(event.message) + val despawnMatches = chatDespawnPattern.matches(event.message) + val autoPetMatches = autopetMessagePattern.matches(event.message) + if (spawnMatches || despawnMatches || autoPetMatches) { + event.blockedReason = "pets" + } + } + // + + // + private fun parsePetData( + lines: List, + itemHandler: (String) -> NEUInternalName?, + xpHandler: (String) -> Double?, + petHandler: (String) -> PetData? + ): Pair? { + return parsePetDataLists( + lines, + itemHandlerList = { it.firstNotNullOfOrNull(itemHandler) }, + xpHandlerList = { it.firstNotNullOfOrNull(xpHandler) }, + petHandlerList = { it.firstNotNullOfOrNull(petHandler) } + ) + } + + private fun parsePetDataLists( + lines: List, + itemHandlerList: (List) -> NEUInternalName?, + xpHandlerList: (List) -> Double?, + petHandlerList: (List) -> PetData? + ): Pair? { + val petItem = itemHandlerList(lines) ?: return null + val overflowXP = xpHandlerList(lines) ?: 0.0 - println(petInfo) - val rarity = LorenzRarity.getByName(petInfo.tier) ?: ErrorManager.skyHanniError( - "Couldn't parse pet rarity.", - Pair("petNBT", petInfo), - Pair("rarity", petInfo.tier), + val data = petHandlerList(lines) ?: return null + val petData = PetData( + internalName = data.internalName, + cleanName = data.cleanName, + rarity = data.rarity, + petItem = petItem, + level = data.level, + xp = data.xp, + rawPetName = data.rawPetName, ) + return petData to overflowXP + } + + private fun parsePetAsItem(item: ItemStack) { + val lore = item.getLore() + + if (lore.any { petDespawnMenuPattern.matches(it) }) { + updatePet(null) + return + } + + getPetDataFromItem(item) + } + + private fun parsePetNBT(item: ItemStack): PetData { + val petInfo = Gson().fromJson(item.getExtraAttributes()?.getString("petInfo"), PetNBT::class.java) + return PetData( internalName = NEUInternalName.NONE, cleanName = "", level = 0, - rarity = rarity, + rarity = LorenzRarity.getByName(petInfo.tier) ?: ErrorManager.skyHanniError( + "Couldn't parse pet rarity.", + Pair("petNBT", petInfo), + Pair("rarity", petInfo.tier), + ), petItem = petInfo.heldItem?.asInternalName(), xp = petInfo.exp, rawPetName = "", @@ -455,11 +448,7 @@ object PetAPI { private fun parsePetName(displayName: String): PetData? { petNameMenuPattern.matchMatcher(displayName) { val name = group("name").orEmpty() - val rarity = LorenzRarity.getByColorCode(group("rarity")[0]) ?: ErrorManager.skyHanniError( - "Couldn't parse pet rarity.", - Pair("displayName", displayName), - Pair("rarity", group("rarity")), - ) + val rarity = rarityByColorGroup(group("rarity")) val level = group("level").toInt() val skin = group("skin").orEmpty() @@ -475,7 +464,120 @@ object PetAPI { } return null } + // + + // + private fun handleWidgetPetLine(line: String, newPetLine: String): PetData? = petWidgetPattern.matchMatcher(line) { + val rarity = rarityByColorGroup(group("rarity")) + val petName = groupOrNull("name").orEmpty() + val level = groupOrNull("level")?.toInt() ?: 0 + val xp = levelToXP(level, rarity, petName) ?: return null + + return PetData( + petNameToInternalName(petName, rarity), + petName, + rarity, + null, + level, + xp, + newPetLine, + ) + } + + private fun handleWidgetStringLine(line: String): NEUInternalName? = widgetStringPattern.matchMatcher(line) { + val string = group("string") + if (string == "No pet selected") { + updatePet(null) + return null + } + return NEUInternalName.fromItemNameOrNull(string) + } + private fun handleWidgetXPLine(line: String): Double? = xpWidgetPattern.matchMatcher(line) { + if (hasGroup("max")) return null + + group("overflow")?.formatDouble() ?: group("currentXP")?.formatDouble() + } + // + + // + private fun onAutopetMessage(event: LorenzChatEvent) { + val hoverMessage = event.chatComponent.hover?.siblings?.joinToString("")?.split("\n") ?: return + + val (petData, _) = parsePetData( + hoverMessage, + { readAutopetItemMessage(it) }, + { null }, // No overflow XP handling in this case + { readAutopetMessage(it) } + ) ?: return + + updatePet(petData) + } + + private fun readAutopetMessage(string: String): PetData? = autopetHoverPetPattern.matchMatcher(string) { + val level = group("level").toInt() + val rarity = rarityByColorGroup(group("rarity")) + val petName = group("pet") + val skin = groupOrNull("skin").takeIf { it != null } + + return PetData( + internalName = petNameToInternalName(petName, rarity), + cleanName = petName, + rarity = rarity, + level = level, + xp = levelToXP(level, rarity, petName) ?: 0.0, + rawPetName = getFakePetLine(level, rarity, petName, skin), + ) + } + + private fun readAutopetItemMessage(string: String): NEUInternalName? = autopetHoverPetItemPattern.matchMatcher(string) { + NEUInternalName.fromItemNameOrNull(group("item")) + } + // + + // + private fun extractSelectedPetData(lore: List): Triple? { + val level = inventorySelectedProgressPattern.firstMatchGroup(lore, "level")?.toInt() + val rarity = inventorySelectedPetPattern.firstMatchGroup(lore, "rarity")?.let { rarityByColorGroup(it) } + val petName = inventorySelectedPetPattern.firstMatchGroup(lore, "pet") + + return if (level != null && rarity != null && petName != null) { + Triple(level, rarity, petName) + } else null + } + + private fun handleSelectedPetName(lore: List): NEUInternalName? = inventorySelectedPetPattern.firstMatcher(lore) { + val (_, rarity, petName) = extractSelectedPetData(lore) ?: return null + petNameToInternalName(petName, rarity) + } + + private fun handleSelectedPetOverflowXp(lore: List): Double? { + // Only have overflow if `next` group is absent + if (inventorySelectedXpPattern.firstMatchGroup(lore, "next") != null) return 0.0 + val (level, rarity, petName) = extractSelectedPetData(lore) ?: return null + val maxXpNeeded = levelToXP(level, rarity, petName) + val currentXp = inventorySelectedXpPattern.firstMatchGroup(lore, "current")?.formatDouble() ?: 0.0 + return maxXpNeeded?.minus(currentXp) ?: 0.0 + } + + private fun handleSelectedPetData(lore: List): PetData? { + val (level, rarity, petName) = extractSelectedPetData(lore) ?: return null + val partialXp = inventorySelectedXpPattern.firstMatchGroup(lore, "current")?.formatDouble() ?: 0.0 + val nextExists = inventorySelectedXpPattern.firstMatchGroup(lore, "next") != null + val totalXp = partialXp + if (nextExists) (levelToXP(level, rarity, petName) ?: return null) else 0.0 + return PetData( + internalName = petNameToInternalName(petName, rarity), + cleanName = petName, + rarity = rarity, + petItem = null, + rawPetName = getFakePetLine(level, rarity, petName), + level = level, + xp = totalXp, + ) + } + // + + // @HandleEvent fun onCommandRegistration(event: CommandRegistrationEvent) { event.register("shpetxp") { @@ -485,138 +587,95 @@ object PetAPI { } } - private fun levelToXPCommand(input: Array) { - if (input.size < 3) { - ChatUtils.userError("Usage: /shcalcpetxp ") - return - } - - val level = input[0].toIntOrNull() - if (level == null) { - ChatUtils.userError("Invalid level '${input[0]}'.") - return - } - val rarity = LorenzRarity.getByName(input[1]) - if (rarity == null) { - ChatUtils.userError("Invalid rarity '${input[1]}'.") + @SubscribeEvent + fun onChat(event: LorenzChatEvent) { + handlePetMessageBlock(event) + if (autopetMessagePattern.matches(event.message)) { + onAutopetMessage(event) return } - - val petName = input.slice(2..= level + val lore = event.inventoryItems[4]?.getLore() ?: return + val (petData, overflowXp) = parsePetDataLists( + lore, + { handleSelectedPetName(lore) }, + { handleSelectedPetOverflowXp(lore) }, + { handleSelectedPetData(lore) } + ) ?: return + updatePet(petData.copy(xp = petData.xp?.plus(overflowXp))) } - private fun getCustomLeveling(petName: String): List { - return petsDataNEU?.get(petName)?.petLevels.orEmpty() + @SubscribeEvent + fun onInventoryClose(event: InventoryCloseEvent) { + inPetMenu = false } - private fun getRarityOffset(rarity: LorenzRarity, petName: String): Int? { - val petsData = petsDataNEU ?: run { - ErrorManager.skyHanniError("NEUPetsData is null") - } - - return if (petName in petsData.keys) { - val petData = petsData[petName] - petData?.rarityOffset?.get(rarity) - } else { - when (rarity) { - LorenzRarity.COMMON -> 0 - LorenzRarity.UNCOMMON -> 6 - LorenzRarity.RARE -> 11 - LorenzRarity.EPIC -> 16 - LorenzRarity.LEGENDARY -> 20 - LorenzRarity.MYTHIC -> 20 - else -> { - ChatUtils.userError("Invalid Rarity \"${rarity.name}\"") - null - } - } - } - } + @SubscribeEvent + fun onSlotClick(event: GuiContainerEvent.SlotClickEvent) { + if (!inPetMenu) return + if (event.clickTypeEnum != GuiContainerEvent.ClickType.NORMAL) return + val category = event.item?.getItemCategoryOrNull() ?: return + if (category != ItemCategory.PET) return - private fun updatePet(newPet: PetData?) { - if (newPet == pet) return - val oldPet = pet - pet = newPet - if (SkyHanniMod.feature.dev.debug.petEventMessages) { - ChatUtils.debug("oldPet: " + oldPet.toString().convertToUnformatted()) - ChatUtils.debug("newPet: " + newPet.toString().convertToUnformatted()) - } - currentPet = if (newPet == null) null else "§${newPet.rarity.chatColorCode}${newPet.cleanName}" - PetChangeEvent(oldPet, newPet).post() + parsePetAsItem(event.item) } @SubscribeEvent fun onDebug(event: DebugDataCollectEvent) { event.title("PetAPI") - if (pet == null) { + if (currentPet?.isInitialized() == false) { event.addIrrelevant("no pet equipped") return } event.addIrrelevant { - add("petName: '${pet?.internalName}'") - add("petRarity: '${pet?.rarity}'") - add("petItem: '${pet?.petItem}'") - add("petLevel: '${pet?.level}'") - add("petXP: '${pet?.xp}'") - add("rawPetLine: '${pet?.rawPetName}'") + add("petName: '${currentPet?.internalName ?: ""}'") + add("petRarity: '${currentPet?.rarity?.rawName.orEmpty()}'") + add("petItem: '${currentPet?.petItem ?: ""}'") + add("petLevel: '${currentPet?.level ?: 0}'") + add("petXP: '${currentPet?.xp ?: 0.0}'") + add("rawPetLine: '${currentPet?.rawPetName.orEmpty()}'") } } @SubscribeEvent fun onNEURepoReload(event: NeuRepositoryReloadEvent) { val data = event.getConstant("pets") - xpLeveling = data.petLevels - petsDataNEU = data.customPetLeveling - - data.internalToDisplayName.forEach { (internalName, displayName) -> - nameToFakeInternalNameCache.put(displayName, internalName.asString()) - } - } - - private fun petNameToFakeInternalName(petName: String): String { - return nameToFakeInternalNameCache.getOrPut(petName) { - petName.uppercase().replace(" ", "_") - } - } - - private fun petNameToInternalName(petName: String, rarity: LorenzRarity): NEUInternalName { - return nameToInternalNameCache.getOrPut("$petName;${rarity.id}") { - "${petNameToFakeInternalName(petName)};${rarity.id}".asInternalName() - } - } - - private fun throwUnknownRarity(badRarity: String): Nothing { - ErrorManager.skyHanniError( - "Unknown rarity", - Pair("rarity", badRarity), - ) + baseXpLevelReqs = data.petLevels + customXpLevelReqs = data.customPetLeveling } + // } data class PetNBT( diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetData.kt b/src/main/java/at/hannibal2/skyhanni/data/PetData.kt index c5de2814a2fe..b2e02ff83e1c 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetData.kt @@ -1,17 +1,20 @@ package at.hannibal2.skyhanni.data +import at.hannibal2.skyhanni.utils.ItemUtils.itemName import at.hannibal2.skyhanni.utils.LorenzRarity import at.hannibal2.skyhanni.utils.NEUInternalName data class PetData( - val internalName: NEUInternalName, - val cleanName: String, - val rarity: LorenzRarity, + val internalName: NEUInternalName? = null, + val cleanName: String? = null, + val rarity: LorenzRarity? = null, val petItem: NEUInternalName? = null, - val level: Int, - val xp: Double, - val rawPetName: String, + val level: Int? = null, + val xp: Double? = null, + val rawPetName: String? = null, ) { + val displayName = internalName?.itemName + override fun equals(other: Any?): Boolean { if (other !is PetData) return false return this.internalName == other.internalName && @@ -26,8 +29,12 @@ data class PetData( var result = cleanName.hashCode() result = 31 * result + rarity.hashCode() result = 31 * result + (petItem?.hashCode() ?: 0) - result = 31 * result + level + result = 31 * result + (level ?: 0) result = 31 * result + rawPetName.hashCode() return result } + + fun isInitialized(): Boolean { + return internalName != null && cleanName != null && rarity != null && level != null && xp != null && rawPetName != null + } } diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/fortuneguide/FFStats.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/fortuneguide/FFStats.kt index 77862b74daf5..aa31e1e43f45 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/fortuneguide/FFStats.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/fortuneguide/FFStats.kt @@ -166,10 +166,10 @@ object FFStats { FFGuideGUI.updateDisplay() } - fun List.getFFData(): Map = combineFFData(this.map { it.getFFData() }) + private fun List.getFFData(): Map = combineFFData(this.map { it.getFFData() }) - fun combineFFData(vararg value: Map) = combineFFData(value.toList()) - fun combineFFData(value: List>) = + private fun combineFFData(vararg value: Map) = combineFFData(value.toList()) + private fun combineFFData(value: List>) = value.map { it.toList() }.flatten().groupBy({ it.first }, { it.second }) .mapValues { (_, values) -> values.sum() } diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentationTableAPI.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentationTableAPI.kt index be0f08a5bafc..0818d8e02180 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentationTableAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentationTableAPI.kt @@ -169,11 +169,12 @@ object ExperimentationTableAPI { /** * REGEX-TEST: §dGuardian * REGEX-TEST: §9Guardian§e + * REGEX-TEST: Guardian */ private val petNamePattern by patternGroup.pattern( "guardianpet", - "§[956d]Guardian.*", + "(?:§[956d])?Guardian.*", ) - fun hasGuardianPet(): Boolean = petNamePattern.matches(PetAPI.currentPet) + fun hasGuardianPet(): Boolean = petNamePattern.matches(PetAPI.currentPet?.rawPetName) } diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt index cc206a7e94e8..2d7c45ea9762 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt @@ -52,8 +52,6 @@ private fun getVisitingName(): String { var beenAfkFor = SimpleTimeMark.now() -fun getPetDisplay(): String = PetAPI.pet?.rawPetName ?: "No pet equipped" - private fun getCropMilestoneDisplay(): String { val crop = InventoryUtils.getItemInHand()?.getCropType() val cropCounter = crop?.getCounter() @@ -73,91 +71,103 @@ private fun getCropMilestoneDisplay(): String { return "${crop.cropName}: $text" } +private fun getPetDisplay(): String = PetAPI.currentPet?.rawPetName ?: "No pet equipped" + enum class DiscordStatus(private val displayMessageSupplier: (() -> String?)) { NONE({ null }), - LOCATION({ - var location = LorenzUtils.skyBlockArea ?: "invalid" - val island = LorenzUtils.skyBlockIsland + LOCATION( + { + var location = LorenzUtils.skyBlockArea ?: "invalid" + val island = LorenzUtils.skyBlockIsland - if (location == "Your Island") location = "Private Island" - when { - island == IslandType.PRIVATE_ISLAND_GUEST -> lastKnownDisplayStrings[LOCATION] = - "${getVisitingName()}'s Island" + if (location == "Your Island") location = "Private Island" + when { + island == IslandType.PRIVATE_ISLAND_GUEST -> lastKnownDisplayStrings[LOCATION] = + "${getVisitingName()}'s Island" + + island == IslandType.GARDEN -> { + if (location.startsWith("Plot: ")) { + lastKnownDisplayStrings[LOCATION] = "Personal Garden ($location)" // Personal Garden (Plot: 8) + } else { + lastKnownDisplayStrings[LOCATION] = "Personal Garden" + } + } - island == IslandType.GARDEN -> { - if (location.startsWith("Plot: ")) { - lastKnownDisplayStrings[LOCATION] = "Personal Garden ($location)" // Personal Garden (Plot: 8) - } else { - lastKnownDisplayStrings[LOCATION] = "Personal Garden" + island == IslandType.GARDEN_GUEST -> { + lastKnownDisplayStrings[LOCATION] = "${getVisitingName()}'s Garden" + if (location.startsWith("Plot: ")) { + lastKnownDisplayStrings[LOCATION] = "${lastKnownDisplayStrings[LOCATION]} ($location)" + } // "MelonKingDe's Garden (Plot: 8)" } - } - island == IslandType.GARDEN_GUEST -> { - lastKnownDisplayStrings[LOCATION] = "${getVisitingName()}'s Garden" - if (location.startsWith("Plot: ")) { - lastKnownDisplayStrings[LOCATION] = "${lastKnownDisplayStrings[LOCATION]} ($location)" - } // "MelonKingDe's Garden (Plot: 8)" + location != "None" && location != "invalid" -> { + lastKnownDisplayStrings[LOCATION] = location + } } + lastKnownDisplayStrings[LOCATION] ?: "None"// only display None if we don't have a last known area + }, + ), - location != "None" && location != "invalid" -> { - lastKnownDisplayStrings[LOCATION] = location + PURSE( + { + val scoreboard = ScoreboardData.sidebarLinesFormatted + // Matches coins amount in purse or piggy, with optional decimal points + val coins = scoreboard.firstOrNull { purseRegex.matches(it.removeColor()) }?.let { + purseRegex.find(it.removeColor())?.groupValues?.get(1).orEmpty() } - } - lastKnownDisplayStrings[LOCATION] ?: "None"// only display None if we don't have a last known area - }), - - PURSE({ - val scoreboard = ScoreboardData.sidebarLinesFormatted - // Matches coins amount in purse or piggy, with optional decimal points - val coins = scoreboard.firstOrNull { purseRegex.matches(it.removeColor()) }?.let { - purseRegex.find(it.removeColor())?.groupValues?.get(1).orEmpty() - } - val motes = scoreboard.firstOrNull { motesRegex.matches(it.removeColor()) }?.let { - motesRegex.find(it.removeColor())?.groupValues?.get(1).orEmpty() - } - lastKnownDisplayStrings[PURSE] = when { - coins == "1" -> "1 Coin" - coins != "" && coins != null -> "$coins Coins" - motes == "1" -> "1 Mote" - motes != "" && motes != null -> "$motes Motes" + val motes = scoreboard.firstOrNull { motesRegex.matches(it.removeColor()) }?.let { + motesRegex.find(it.removeColor())?.groupValues?.get(1).orEmpty() + } + lastKnownDisplayStrings[PURSE] = when { + coins == "1" -> "1 Coin" + coins != "" && coins != null -> "$coins Coins" + motes == "1" -> "1 Mote" + motes != "" && motes != null -> "$motes Motes" - else -> lastKnownDisplayStrings[PURSE].orEmpty() - } - lastKnownDisplayStrings[PURSE].orEmpty() - }), + else -> lastKnownDisplayStrings[PURSE].orEmpty() + } + lastKnownDisplayStrings[PURSE].orEmpty() + }, + ), - BITS({ - val scoreboard = ScoreboardData.sidebarLinesFormatted - val bits = scoreboard.firstOrNull { bitsRegex.matches(it.removeColor()) }?.let { - bitsRegex.find(it.removeColor())?.groupValues?.get(1) - } + BITS( + { + val scoreboard = ScoreboardData.sidebarLinesFormatted + val bits = scoreboard.firstOrNull { bitsRegex.matches(it.removeColor()) }?.let { + bitsRegex.find(it.removeColor())?.groupValues?.get(1) + } - when (bits) { - "1" -> "1 Bit" - null -> "0 Bits" - else -> "$bits Bits" - } - }), + when (bits) { + "1" -> "1 Bit" + null -> "0 Bits" + else -> "$bits Bits" + } + }, + ), - STATS({ - val statString = if (!RiftAPI.inRift()) { - "❤${ActionBarStatsData.HEALTH.value} ❈${ActionBarStatsData.DEFENSE.value} ✎${ActionBarStatsData.MANA.value}" - } else { - "${ActionBarStatsData.RIFT_TIME.value}ф ✎${ActionBarStatsData.MANA.value}" - } - if (ActionBarStatsData.MANA.value != "") { - lastKnownDisplayStrings[STATS] = statString - } - lastKnownDisplayStrings[STATS].orEmpty() - }), + STATS( + { + val statString = if (!RiftAPI.inRift()) { + "❤${ActionBarStatsData.HEALTH.value} ❈${ActionBarStatsData.DEFENSE.value} ✎${ActionBarStatsData.MANA.value}" + } else { + "${ActionBarStatsData.RIFT_TIME.value}ф ✎${ActionBarStatsData.MANA.value}" + } + if (ActionBarStatsData.MANA.value != "") { + lastKnownDisplayStrings[STATS] = statString + } + lastKnownDisplayStrings[STATS].orEmpty() + }, + ), - ITEM({ - InventoryUtils.getItemInHand()?.let { - String.format(java.util.Locale.US, "Holding ${it.displayName.removeColor()}") - } ?: "No item in hand" - }), + ITEM( + { + InventoryUtils.getItemInHand()?.let { + String.format(java.util.Locale.US, "Holding ${it.displayName.removeColor()}") + } ?: "No item in hand" + }, + ), TIME( { @@ -165,60 +175,66 @@ enum class DiscordStatus(private val displayMessageSupplier: (() -> String?)) { }, ), - PROFILE({ - val sbLevel = AdvancedPlayerList.tabPlayerData[LorenzUtils.getPlayerName()]?.sbLevel?.toString() ?: "?" - var profile = "SkyBlock Level: [$sbLevel] on " + PROFILE( + { + val sbLevel = AdvancedPlayerList.tabPlayerData[LorenzUtils.getPlayerName()]?.sbLevel?.toString() ?: "?" + var profile = "SkyBlock Level: [$sbLevel] on " - profile += when { + profile += when { - LorenzUtils.isIronmanProfile -> "♲" - LorenzUtils.isBingoProfile -> "Ⓑ" - LorenzUtils.isStrandedProfile -> "☀" - else -> "" - } + LorenzUtils.isIronmanProfile -> "♲" + LorenzUtils.isBingoProfile -> "Ⓑ" + LorenzUtils.isStrandedProfile -> "☀" + else -> "" + } - val fruit = HypixelData.profileName.firstLetterUppercase() - if (fruit == "") profile = - lastKnownDisplayStrings[PROFILE] ?: "SkyBlock Level: [$sbLevel]" // profile fruit hasn't loaded in yet - else profile += fruit - - lastKnownDisplayStrings[PROFILE] = profile - profile - }), - - SLAYER({ - var slayerName = "" - var slayerLevel = "" - var bossAlive = "spawning" - val slayerRegex = - Pattern.compile("(?(?:\\w| )*) (?[IV]+)") // Samples: Revenant Horror I; Tarantula Broodfather IV - - for (line in ScoreboardData.sidebarLinesFormatted) { - val noColorLine = line.removeColor() - val match = slayerRegex.matcher(noColorLine) - when { - match.matches() -> { - slayerName = match.group("name") - slayerLevel = match.group("level") - } + val fruit = HypixelData.profileName.firstLetterUppercase() + if (fruit == "") profile = + lastKnownDisplayStrings[PROFILE] ?: "SkyBlock Level: [$sbLevel]" // profile fruit hasn't loaded in yet + else profile += fruit + + lastKnownDisplayStrings[PROFILE] = profile + profile + }, + ), - noColorLine == "Slay the boss!" -> bossAlive = "slaying" - noColorLine == "Boss slain!" -> bossAlive = "slain" + SLAYER( + { + var slayerName = "" + var slayerLevel = "" + var bossAlive = "spawning" + val slayerRegex = + Pattern.compile("(?(?:\\w| )*) (?[IV]+)") // Samples: Revenant Horror I; Tarantula Broodfather IV + + for (line in ScoreboardData.sidebarLinesFormatted) { + val noColorLine = line.removeColor() + val match = slayerRegex.matcher(noColorLine) + when { + match.matches() -> { + slayerName = match.group("name") + slayerLevel = match.group("level") + } + + noColorLine == "Slay the boss!" -> bossAlive = "slaying" + noColorLine == "Boss slain!" -> bossAlive = "slain" + } } - } - when { - slayerLevel == "" -> AutoStatus.SLAYER.placeholderText // selected slayer in rpc but hasn't started a quest - bossAlive == "spawning" -> "Spawning a $slayerName $slayerLevel boss." - bossAlive == "slaying" -> "Slaying a $slayerName $slayerLevel boss." - bossAlive == "slain" -> "Finished slaying a $slayerName $slayerLevel boss." - else -> "Something went wrong with slayer detection!" - } - }), + when { + slayerLevel == "" -> AutoStatus.SLAYER.placeholderText // selected slayer in rpc but hasn't started a quest + bossAlive == "spawning" -> "Spawning a $slayerName $slayerLevel boss." + bossAlive == "slaying" -> "Slaying a $slayerName $slayerLevel boss." + bossAlive == "slain" -> "Finished slaying a $slayerName $slayerLevel boss." + else -> "Something went wrong with slayer detection!" + } + }, + ), - CUSTOM({ - DiscordRPCManager.config.customText.get() // custom field in the config - }), + CUSTOM( + { + DiscordRPCManager.config.customText.get() // custom field in the config + }, + ), AUTO( { @@ -250,81 +266,87 @@ enum class DiscordStatus(private val displayMessageSupplier: (() -> String?)) { PETS({ getPetDisplay() }), // Dynamic-only - STACKING({ - // Logic for getting the currently held stacking enchant is from Skytils, except for getExtraAttributes() which they got from BiscuitDevelopment - - fun getExtraAttributes(item: ItemStack?): NBTTagCompound? { - return if (item == null || !item.hasTagCompound()) { - null - } else item.getSubCompound("ExtraAttributes", false) - } - - val itemInHand = InventoryUtils.getItemInHand() - val itemName = itemInHand?.displayName?.removeColor().orEmpty() + STACKING( + { + // Logic for getting the currently held stacking enchant is from Skytils, except for getExtraAttributes() which they got from BiscuitDevelopment - val extraAttributes = getExtraAttributes(itemInHand) + fun getExtraAttributes(item: ItemStack?): NBTTagCompound? { + return if (item == null || !item.hasTagCompound()) { + null + } else item.getSubCompound("ExtraAttributes", false) + } - fun getProgressPercent(amount: Int, levels: List): String { - var percent = "MAXED" - for (level in levels.indices) { - if (amount > levels[level]) { - continue - } - percent = if (amount.toDouble() == 0.0) { - "" - } else { - LorenzUtils.formatPercentage((amount.toDouble() - levels[level - 1]) / (levels[level] - levels[level - 1])) + val itemInHand = InventoryUtils.getItemInHand() + val itemName = itemInHand?.displayName?.removeColor().orEmpty() + + val extraAttributes = getExtraAttributes(itemInHand) + + fun getProgressPercent(amount: Int, levels: List): String { + var percent = "MAXED" + for (level in levels.indices) { + if (amount > levels[level]) { + continue + } + percent = if (amount.toDouble() == 0.0) { + "" + } else { + LorenzUtils.formatPercentage((amount.toDouble() - levels[level - 1]) / (levels[level] - levels[level - 1])) + } + break } - break + return percent } - return percent - } - var stackingReturn = AutoStatus.STACKING.placeholderText - if (extraAttributes != null) { - val enchantments = extraAttributes.getCompoundTag("enchantments") - var stackingEnchant = "" - for (enchant in DiscordRPCManager.stackingEnchants) { - if (extraAttributes.hasKey(enchant.value.statName)) { - stackingEnchant = enchant.key - break + var stackingReturn = AutoStatus.STACKING.placeholderText + if (extraAttributes != null) { + val enchantments = extraAttributes.getCompoundTag("enchantments") + var stackingEnchant = "" + for (enchant in DiscordRPCManager.stackingEnchants) { + if (extraAttributes.hasKey(enchant.value.statName)) { + stackingEnchant = enchant.key + break + } } + val levels = DiscordRPCManager.stackingEnchants[stackingEnchant]?.levels ?: listOf(0) + val level = enchantments.getInteger(stackingEnchant) + val amount = extraAttributes.getInteger(DiscordRPCManager.stackingEnchants[stackingEnchant]?.statName) + val stackingPercent = getProgressPercent(amount, levels) + + stackingReturn = + if (stackingPercent == "" || amount == 0) AutoStatus.STACKING.placeholderText // outdated info is useless for AUTO + else "$itemName: ${stackingEnchant.firstLetterUppercase()} $level ($stackingPercent)" // Hecatomb 100: (55.55%) } - val levels = DiscordRPCManager.stackingEnchants[stackingEnchant]?.levels ?: listOf(0) - val level = enchantments.getInteger(stackingEnchant) - val amount = extraAttributes.getInteger(DiscordRPCManager.stackingEnchants[stackingEnchant]?.statName) - val stackingPercent = getProgressPercent(amount, levels) - - stackingReturn = - if (stackingPercent == "" || amount == 0) AutoStatus.STACKING.placeholderText // outdated info is useless for AUTO - else "$itemName: ${stackingEnchant.firstLetterUppercase()} $level ($stackingPercent)" // Hecatomb 100: (55.55%) - } - stackingReturn + stackingReturn - }), + }, + ), - DUNGEONS({ - if (!DungeonAPI.inDungeon()) { - AutoStatus.DUNGEONS.placeholderText - } else { - val boss = DungeonAPI.getCurrentBoss() - if (boss == null) { - "Unknown dungeon boss" + DUNGEONS( + { + if (!DungeonAPI.inDungeon()) { + AutoStatus.DUNGEONS.placeholderText } else { - val floor = DungeonAPI.dungeonFloor ?: AutoStatus.DUNGEONS.placeholderText - val amountKills = DungeonAPI.bossStorage?.get(boss)?.addSeparators() ?: "Unknown" - val time = DungeonAPI.getTime() - "$floor Kills: $amountKills ($time)" + val boss = DungeonAPI.getCurrentBoss() + if (boss == null) { + "Unknown dungeon boss" + } else { + val floor = DungeonAPI.dungeonFloor ?: AutoStatus.DUNGEONS.placeholderText + val amountKills = DungeonAPI.bossStorage?.get(boss)?.addSeparators() ?: "Unknown" + val time = DungeonAPI.getTime() + "$floor Kills: $amountKills ($time)" + } } - } - }), - - AFK({ - if (beenAfkFor.passedSince() > 5.minutes) { - val format = beenAfkFor.passedSince().format(maxUnits = 1, longName = true) - "AFK for $format" - } else AutoStatus.AFK.placeholderText - }) + }, + ), + + AFK( + { + if (beenAfkFor.passedSince() > 5.minutes) { + val format = beenAfkFor.passedSince().format(maxUnits = 1, longName = true) + "AFK for $format" + } else AutoStatus.AFK.placeholderText + }, + ) ; fun getDisplayString(): String = displayMessageSupplier().orEmpty() diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt index 10310c3687c3..6edd1bb59e40 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt @@ -4,17 +4,10 @@ import at.hannibal2.skyhanni.SkyHanniMod import at.hannibal2.skyhanni.config.ConfigUpdaterMigrator import at.hannibal2.skyhanni.data.PetAPI import at.hannibal2.skyhanni.events.GuiRenderEvent -import at.hannibal2.skyhanni.events.InventoryFullyOpenedEvent -import at.hannibal2.skyhanni.events.LorenzChatEvent import at.hannibal2.skyhanni.features.rift.RiftAPI import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule -import at.hannibal2.skyhanni.utils.ItemUtils.getLore import at.hannibal2.skyhanni.utils.LorenzUtils -import at.hannibal2.skyhanni.utils.RegexUtils.matchFirst -import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher -import at.hannibal2.skyhanni.utils.RegexUtils.matches import at.hannibal2.skyhanni.utils.RenderUtils.renderString -import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern import net.minecraftforge.fml.common.eventhandler.SubscribeEvent @SkyHanniModule @@ -22,64 +15,6 @@ object CurrentPetDisplay { private val config get() = SkyHanniMod.feature.misc.pets - private val patternGroup = RepoPattern.group("misc.currentpet") - private val inventorySelectedPetPattern by patternGroup.pattern( - "inventory.selected", - "§7§7Selected pet: (?.*)" - ) - private val chatSpawnPattern by patternGroup.pattern( - "chat.spawn", - "§aYou summoned your §r(?.*)§r§a!" - ) - private val chatDespawnPattern by patternGroup.pattern( - "chat.despawn", - "§aYou despawned your §r.*§r§a!" - ) - - /** - * REGEX-TEST: §cAutopet §eequipped your §7[Lvl 100] §6Griffin§4 ✦§e! §a§lVIEW RULE - * REGEX-TEST: §cAutopet §eequipped your §7[Lvl 100] §6Elephant§e! §a§lVIEW RULE - */ - private val chatPetRulePattern by patternGroup.pattern( - "chat.rule", - "§cAutopet §eequipped your §7\\[Lvl .*] (?.*)§e! §a§lVIEW RULE" - ) - - @SubscribeEvent - fun onChat(event: LorenzChatEvent) { - findPetInChat(event.message)?.let { - PetAPI.currentPet = it - if (config.hideAutopet) { - event.blockedReason = "pets" - } - } - } - - private fun findPetInChat(message: String): String? { - chatSpawnPattern.matchMatcher(message) { - return group("pet") - } - if (chatDespawnPattern.matches(message)) { - return "" - } - chatPetRulePattern.matchMatcher(message) { - return group("pet") - } - - return null - } - - @SubscribeEvent - fun onInventoryOpen(event: InventoryFullyOpenedEvent) { - if (!PetAPI.isPetMenu(event.inventoryName, event.inventoryItems)) return - - val lore = event.inventoryItems[4]?.getLore() ?: return - lore.matchFirst(inventorySelectedPetPattern) { - val newPet = group("pet") - PetAPI.currentPet = if (newPet != "§cNone") newPet else "" - } - } - @SubscribeEvent fun onRenderOverlay(event: GuiRenderEvent.GuiOverlayRenderEvent) { if (!LorenzUtils.inSkyBlock) return @@ -87,7 +22,7 @@ object CurrentPetDisplay { if (!config.display) return - config.displayPos.renderString(PetAPI.currentPet, posLabel = "Current Pet") + config.displayPos.renderString(PetAPI.currentPet?.rawPetName, posLabel = "Current Pet") } @SubscribeEvent diff --git a/src/main/java/at/hannibal2/skyhanni/utils/ItemUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/ItemUtils.kt index 9a2e6857edee..73dd7f29e345 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/ItemUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/ItemUtils.kt @@ -2,6 +2,7 @@ package at.hannibal2.skyhanni.utils import at.hannibal2.skyhanni.data.NotificationManager import at.hannibal2.skyhanni.data.PetAPI +import at.hannibal2.skyhanni.data.PetAPI.petItemNamePattern import at.hannibal2.skyhanni.data.SkyHanniNotification import at.hannibal2.skyhanni.events.DebugDataCollectEvent import at.hannibal2.skyhanni.features.misc.items.EstimatedItemValueCalculator.getAttributeName @@ -258,19 +259,28 @@ object ItemUtils { LorenzRarity.entries.joinToString(separator = "|") { it.name }, ) - private fun ItemStack.readItemCategoryAndRarity(): Pair { - val cleanName = this.cleanName() + private val ignoredPetStrings = listOf( + "Archer", + "Berserk", + "Mage", + "Tank", + "Healer", + "➡", + ) - if (PetAPI.hasPetName(cleanName)) { - return getPetRarity(this) to ItemCategory.PET - } + private fun ItemStack.isPet() = petItemNamePattern.matches(cleanName()) && !ignoredPetStrings.any { + cleanName().contains(it) + } + + private fun ItemStack.readItemCategoryAndRarity(): Pair { + if (this.isPet()) return getPetRarity(this) to ItemCategory.PET for (line in this.getLore().reversed()) { val (category, rarity) = UtilsPatterns.rarityLoreLinePattern.matchMatcher(line) { group("itemCategory").replace(" ", "_") to group("rarity").replace(" ", "_") } ?: continue - val itemCategory = getItemCategory(category, name, cleanName) + val itemCategory = getItemCategory(category) val itemRarity = LorenzRarity.getByName(rarity) if (itemCategory == null) { @@ -305,11 +315,11 @@ object ItemUtils { return null to null } - private fun getItemCategory(itemCategory: String, name: String, cleanName: String = name.removeColor()) = + private fun ItemStack.getItemCategory(itemCategory: String) = if (itemCategory.isEmpty()) when { UtilsPatterns.abiPhonePattern.matches(name) -> ItemCategory.ABIPHONE - PetAPI.hasPetName(cleanName) -> ItemCategory.PET - UtilsPatterns.baitPattern.matches(cleanName) -> ItemCategory.FISHING_BAIT + isPet() -> ItemCategory.PET + UtilsPatterns.baitPattern.matches(cleanName()) -> ItemCategory.FISHING_BAIT UtilsPatterns.enchantedBookPattern.matches(name) -> ItemCategory.ENCHANTED_BOOK UtilsPatterns.potionPattern.matches(name) -> ItemCategory.POTION UtilsPatterns.sackPattern.matches(name) -> ItemCategory.SACK diff --git a/src/main/java/at/hannibal2/skyhanni/utils/RegexUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/RegexUtils.kt index 91a53f62bad4..4e7f0dedb8c0 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/RegexUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/RegexUtils.kt @@ -66,6 +66,9 @@ object RegexUtils { fun Pattern.anyMatches(list: Sequence?): Boolean = anyMatches(list?.toList()) fun Pattern.matchGroup(text: String, groupName: String): String? = matchMatcher(text) { groupOrNull(groupName) } + fun Pattern.firstMatchGroup(list: List, groupName: String): String? = firstMatcher(list) { + groupOrNull(groupName) + } fun Pattern.matchGroups(text: String, vararg groups: String): List? = matchMatcher(text) { groups.toList().map { groupOrNull(it) } } diff --git a/src/main/java/at/hannibal2/skyhanni/utils/SkyBlockItemModifierUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/SkyBlockItemModifierUtils.kt index 128b5d11e877..4f2e01a934b8 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/SkyBlockItemModifierUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/SkyBlockItemModifierUtils.kt @@ -1,13 +1,14 @@ package at.hannibal2.skyhanni.utils import at.hannibal2.skyhanni.config.ConfigManager -import at.hannibal2.skyhanni.data.PetAPI +import at.hannibal2.skyhanni.data.PetAPI.petItemNamePattern import at.hannibal2.skyhanni.mixins.hooks.ItemStackCachedData import at.hannibal2.skyhanni.utils.ItemUtils.extraAttributes 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.NEUInternalName.Companion.asInternalName +import at.hannibal2.skyhanni.utils.RegexUtils.matchGroup import at.hannibal2.skyhanni.utils.StringUtils.removeColor import com.google.gson.JsonObject import net.minecraft.item.Item @@ -93,9 +94,9 @@ object SkyBlockItemModifierUtils { ConfigManager.gson.fromJson(getExtraAttributes()?.getString("petInfo"), JsonObject::class.java) @Suppress("CAST_NEVER_SUCCEEDS") - inline val ItemStack.cachedData get() = (this as ItemStackCachedData).skyhanni_cachedData + inline val ItemStack.cachedData: CachedItemData get() = (this as ItemStackCachedData).skyhanni_cachedData - fun ItemStack.getPetLevel(): Int = PetAPI.getPetLevel(displayName) ?: 0 + fun ItemStack.getPetLevel(): Int = petItemNamePattern.matchGroup(displayName, "level")?.toInt() ?: 0 fun ItemStack.getMaxPetLevel() = if (this.getInternalName() == "GOLDEN_DRAGON;4".asInternalName()) 200 else 100 From ea21a70f8a142f4a3e923f9f90f35d02d4e0848f Mon Sep 17 00:00:00 2001 From: David Cole <40234707+DavidArthurCole@users.noreply.github.com> Date: Tue, 10 Dec 2024 01:54:16 -0500 Subject: [PATCH 51/91] Merge cleanup --- .../features/misc/pets/CurrentPetDisplay.kt | 67 ------------------- 1 file changed, 67 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt index e38fe0fa9d24..6edd1bb59e40 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt @@ -7,12 +7,6 @@ import at.hannibal2.skyhanni.events.GuiRenderEvent import at.hannibal2.skyhanni.features.rift.RiftAPI import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.LorenzUtils -<<<<<<< HEAD -======= -import at.hannibal2.skyhanni.utils.RegexUtils.firstMatcher -import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher -import at.hannibal2.skyhanni.utils.RegexUtils.matches ->>>>>>> upstream/beta import at.hannibal2.skyhanni.utils.RenderUtils.renderString import net.minecraftforge.fml.common.eventhandler.SubscribeEvent @@ -21,67 +15,6 @@ object CurrentPetDisplay { private val config get() = SkyHanniMod.feature.misc.pets -<<<<<<< HEAD -======= - private val patternGroup = RepoPattern.group("misc.currentpet") - private val inventorySelectedPetPattern by patternGroup.pattern( - "inventory.selected", - "§7§7Selected pet: (?.*)", - ) - private val chatSpawnPattern by patternGroup.pattern( - "chat.spawn", - "§aYou summoned your §r(?.*)§r§a!", - ) - private val chatDespawnPattern by patternGroup.pattern( - "chat.despawn", - "§aYou despawned your §r.*§r§a!", - ) - - /** - * REGEX-TEST: §cAutopet §eequipped your §7[Lvl 100] §6Griffin§4 ✦§e! §a§lVIEW RULE - * REGEX-TEST: §cAutopet §eequipped your §7[Lvl 100] §6Elephant§e! §a§lVIEW RULE - */ - private val chatPetRulePattern by patternGroup.pattern( - "chat.rule", - "§cAutopet §eequipped your §7\\[Lvl .*] (?.*)§e! §a§lVIEW RULE", - ) - - @SubscribeEvent - fun onChat(event: LorenzChatEvent) { - findPetInChat(event.message)?.let { - PetAPI.currentPet = it - if (config.hideAutopet) { - event.blockedReason = "pets" - } - } - } - - private fun findPetInChat(message: String): String? { - chatSpawnPattern.matchMatcher(message) { - return group("pet") - } - if (chatDespawnPattern.matches(message)) { - return "" - } - chatPetRulePattern.matchMatcher(message) { - return group("pet") - } - - return null - } - - @SubscribeEvent - fun onInventoryOpen(event: InventoryFullyOpenedEvent) { - if (!PetAPI.isPetMenu(event.inventoryName)) return - - val lore = event.inventoryItems[4]?.getLore() ?: return - inventorySelectedPetPattern.firstMatcher(lore) { - val newPet = group("pet") - PetAPI.currentPet = if (newPet != "§cNone") newPet else "" - } - } - ->>>>>>> upstream/beta @SubscribeEvent fun onRenderOverlay(event: GuiRenderEvent.GuiOverlayRenderEvent) { if (!LorenzUtils.inSkyBlock) return From f6d45aac4b88996309d7384ebf85265d8d5346cc Mon Sep 17 00:00:00 2001 From: David Cole <40234707+DavidArthurCole@users.noreply.github.com> Date: Tue, 10 Dec 2024 01:57:28 -0500 Subject: [PATCH 52/91] Detekt --- .../skyhanni/features/misc/discordrpc/DiscordStatus.kt | 2 -- .../at/hannibal2/skyhanni/utils/SkyBlockItemModifierUtils.kt | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt index 2e80db3187ff..e9bb50567546 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt @@ -17,7 +17,6 @@ import at.hannibal2.skyhanni.features.garden.GardenAPI.getCropType import at.hannibal2.skyhanni.features.misc.compacttablist.AdvancedPlayerList import at.hannibal2.skyhanni.features.rift.RiftAPI import at.hannibal2.skyhanni.utils.InventoryUtils -import at.hannibal2.skyhanni.utils.ItemUtils.extraAttributes import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators import at.hannibal2.skyhanni.utils.SimpleTimeMark @@ -29,7 +28,6 @@ import at.hannibal2.skyhanni.utils.TimeUtils.format import at.hannibal2.skyhanni.utils.TimeUtils.formatted import net.minecraft.item.ItemStack import net.minecraft.nbt.NBTTagCompound -import io.github.moulberry.notenoughupdates.miscfeatures.PetInfoOverlay.getCurrentPet import java.util.regex.Pattern import kotlin.time.Duration.Companion.minutes diff --git a/src/main/java/at/hannibal2/skyhanni/utils/SkyBlockItemModifierUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/SkyBlockItemModifierUtils.kt index 29454b0e0caf..0775fb188525 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/SkyBlockItemModifierUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/SkyBlockItemModifierUtils.kt @@ -7,8 +7,8 @@ import at.hannibal2.skyhanni.utils.ItemUtils.extraAttributes 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.RegexUtils.matchGroup import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.toInternalName +import at.hannibal2.skyhanni.utils.RegexUtils.matchGroup import at.hannibal2.skyhanni.utils.StringUtils.removeColor import com.google.gson.JsonObject import net.minecraft.item.Item From 2245290e84483c0f9e5e00d97b2b16a5cda19b21 Mon Sep 17 00:00:00 2001 From: David Cole <40234707+DavidArthurCole@users.noreply.github.com> Date: Tue, 10 Dec 2024 02:18:06 -0500 Subject: [PATCH 53/91] Extract data parsing logic to PetData --- .../java/at/hannibal2/skyhanni/data/PetAPI.kt | 278 +++++------------- .../at/hannibal2/skyhanni/data/PetData.kt | 150 ++++++++++ 2 files changed, 220 insertions(+), 208 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt index c3a79b457b75..2703f048b88f 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt @@ -4,6 +4,10 @@ import at.hannibal2.skyhanni.SkyHanniMod import at.hannibal2.skyhanni.api.event.HandleEvent import at.hannibal2.skyhanni.config.commands.CommandCategory import at.hannibal2.skyhanni.config.commands.CommandRegistrationEvent +import at.hannibal2.skyhanni.data.PetData.Companion.parsePetAsItem +import at.hannibal2.skyhanni.data.PetData.Companion.parsePetData +import at.hannibal2.skyhanni.data.PetData.Companion.parsePetDataLists +import at.hannibal2.skyhanni.data.PetData.Companion.petNameToInternalName import at.hannibal2.skyhanni.data.jsonobjects.repo.NEUPetData import at.hannibal2.skyhanni.data.jsonobjects.repo.NEUPetsJson import at.hannibal2.skyhanni.data.model.TabWidget @@ -23,7 +27,7 @@ import at.hannibal2.skyhanni.utils.ItemUtils.getItemCategoryOrNull import at.hannibal2.skyhanni.utils.ItemUtils.getLore import at.hannibal2.skyhanni.utils.LorenzRarity import at.hannibal2.skyhanni.utils.NEUInternalName -import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.asInternalName +import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.toInternalName import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators import at.hannibal2.skyhanni.utils.NumberUtil.formatDouble import at.hannibal2.skyhanni.utils.RegexUtils.firstMatchGroup @@ -33,20 +37,19 @@ import at.hannibal2.skyhanni.utils.RegexUtils.groupOrNull import at.hannibal2.skyhanni.utils.RegexUtils.hasGroup import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.RegexUtils.matches -import at.hannibal2.skyhanni.utils.SkyBlockItemModifierUtils.getExtraAttributes import at.hannibal2.skyhanni.utils.StringUtils.convertToUnformatted import at.hannibal2.skyhanni.utils.chat.Text.hover import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern -import com.google.gson.Gson import net.minecraft.item.ItemStack import net.minecraftforge.fml.common.eventhandler.SubscribeEvent @SkyHanniModule object PetAPI { private val config get() = SkyHanniMod.feature.misc.pets - private val patternGroup = RepoPattern.group("misc.pet") private const val FORGE_BACK_SLOT = 48 + val patternGroup = RepoPattern.group("misc.pet") + private var inPetMenu = false private var baseXpLevelReqs: List = listOf() private var customXpLevelReqs: Map? = null @@ -58,35 +61,6 @@ object PetAPI { } // - /** - * REGEX-TEST: §7§7Selected pet: §6Hedgehog - */ - private val inventorySelectedPetPattern by patternGroup.pattern( - "inventory.selected", - "§7§7Selected pet: §?(?.)?(?.*)" - ) - - /** - * REGEX-TEST: §7Progress to Level 91: §e0% - * REGEX-TEST: §7Progress to Level 147: §e37.1% - * REGEX-TEST: §b§lMAX LEVEL - */ - private val inventorySelectedProgressPattern by patternGroup.pattern( - "inventory.selected.progress", - "§b§lMAX LEVEL|§7Progress to Level (?\\d+): §e(?[\\d.]+)%" - ) - - /** - * REGEX-TEST: §2§l§m §f§l§m §r §e713,241.8§6/§e1.4M - * REGEX-TEST: §2§l§m §f§l§m §r §e699,742.8§6/§e1.9M - * REGEX-TEST: §f§l§m §r §e0§6/§e660 - * REGEX-TEST: §8▸ 30,358,983 XP' - */ - private val inventorySelectedXpPattern by patternGroup.pattern( - "inventory.selected.xp", - "(?:§8▸ |(?:§.§l§m *)*)(?:§r §e)?(?[\\d,.kM]+)(?:§6\\/§e)?(?[\\d,.kM]+)?" - ) - /** * REGEX-TEST: Pets (1/3) * REGEX-TEST: Pets @@ -116,24 +90,6 @@ object PetAPI { "(?:§f§f)?§7\\[Lvl (?:1➡(?:100|200)|\\{LVL})] (?.*)", ) - /** - * REGEX-TEST: §e⭐ §7[Lvl 100] §6Ender Dragon - * REGEX-TEST: §e⭐ §7[Lvl 100] §dBlack Cat§d ✦ - * REGEX-TEST: §7[Lvl 100] §6Mole - */ - private val petNameMenuPattern by patternGroup.pattern( - "menu.pet.name", - "^(?:§e(?⭐) )?(?:§.)*\\[Lvl (?\\d+)] §(?.)(?[\\w ]+)(?§. ✦)?\$", - ) - - /** - * REGEX-TEST: §7§cClick to despawn! - */ - private val petDespawnMenuPattern by patternGroup.pattern( - "menu.pet.despawn", - "§7§cClick to despawn!", - ) - /** * REGEX-TEST: §7To Select Process (Slot #2) * REGEX-TEST: §7To Select Process (Slot #4) @@ -156,27 +112,6 @@ object PetAPI { "^ §r§7\\[Lvl (?\\d+)](?: (?:§.)+\\[(?:§.)+(?\\d+)(?:§.)+✦(?:§.)+])? §r§(?.)(?[\\w ]+)(?:§r(?§. ✦))?\$", ) - /** - * REGEX-TEST: §r§7No pet selected - * REGEX-TEST: §r§6Washed-up Souvenir - * REGEX-TEST: §r§9Dwarf Turtle Shelmet - */ - private val widgetStringPattern by patternGroup.pattern( - "widget.string", - "^ §r(?§.[\\w -]+)\$", - ) - - /** - * REGEX-TEST: §r§b§lMAX LEVEL - * REGEX-TEST: §r§6+§r§e21,248,020.7 XP - * REGEX-TEST: §r§e15,986.6§r§6/§r§e29k XP §r§6(53.6%) - */ - @Suppress("MaxLineLength") - private val xpWidgetPattern by patternGroup.pattern( - "widget.xp", - "^ §r§.(?:§l(?MAX LEVEL)|\\+§r§e(?[\\d,.]+) XP|(?[\\d,.]+)§r§6/§r§e(?[\\d.km]+) XP §r§6\\((?[\\d.%]+)\\))$", - ) - /** * REGEX-TEST: §cAutopet §eequipped your §7[Lvl 100] §6Scatha§e! §a§lVIEW RULE * REGEX-TEST: §cAutopet §eequipped your §7[Lvl 99] §6Flying Fish§e! §a§lVIEW RULE @@ -205,12 +140,70 @@ object PetAPI { "§aYou summoned your §r(?.*)§r§a!" ) + /** + * REGEX-TEST: §aYour pet is now holding §r§9Bejeweled Collar§r§a. + */ + private val petItemMessagePattern by patternGroup.pattern( + "chat.pet.item.equip", + "^§aYour pet is now holding §r(?§.[\\w -]+)§r§a\\.\$", + ) + + /** + * REGEX-TEST: §7§7Selected pet: §6Hedgehog + */ + private val inventorySelectedPetPattern by PetAPI.patternGroup.pattern( + "inventory.selected", + "§7§7Selected pet: §?(?.)?(?.*)" + ) + + /** + * REGEX-TEST: §7Progress to Level 91: §e0% + * REGEX-TEST: §7Progress to Level 147: §e37.1% + * REGEX-TEST: §b§lMAX LEVEL + */ + private val inventorySelectedProgressPattern by PetAPI.patternGroup.pattern( + "inventory.selected.progress", + "§b§lMAX LEVEL|§7Progress to Level (?\\d+): §e(?[\\d.]+)%" + ) + + /** + * REGEX-TEST: §2§l§m §f§l§m §r §e713,241.8§6/§e1.4M + * REGEX-TEST: §2§l§m §f§l§m §r §e699,742.8§6/§e1.9M + * REGEX-TEST: §f§l§m §r §e0§6/§e660 + * REGEX-TEST: §8▸ 30,358,983 XP' + */ + private val inventorySelectedXpPattern by PetAPI.patternGroup.pattern( + "inventory.selected.xp", + "(?:§8▸ |(?:§.§l§m *)*)(?:§r §e)?(?[\\d,.kM]+)(?:§6\\/§e)?(?[\\d,.kM]+)?" + ) + + /** + * REGEX-TEST: §r§7No pet selected + * REGEX-TEST: §r§6Washed-up Souvenir + * REGEX-TEST: §r§9Dwarf Turtle Shelmet + */ + private val widgetStringPattern by PetAPI.patternGroup.pattern( + "widget.string", + "^ §r(?§.[\\w -]+)\$", + ) + + /** + * REGEX-TEST: §r§b§lMAX LEVEL + * REGEX-TEST: §r§6+§r§e21,248,020.7 XP + * REGEX-TEST: §r§e15,986.6§r§6/§r§e29k XP §r§6(53.6%) + */ + @Suppress("MaxLineLength") + private val xpWidgetPattern by PetAPI.patternGroup.pattern( + "widget.xp", + "^ §r§.(?:§l(?MAX LEVEL)|\\+§r§e(?[\\d,.]+) XP|(?[\\d,.]+)§r§6/§r§e(?[\\d.km]+) XP §r§6\\((?[\\d.%]+)\\))$", + ) + /** * REGEX-TEST: §r, §aEquip: §r, §7[Lvl 99] §r, §6Flying Fish * REGEX-TEST: §r, §aEquip: §r, §e⭐ §r, §7[Lvl 100] §r, §dBlack Cat§r, §d ✦ * REGEX-TEST: §r, §aEquip: §r, §7[Lvl 47] §r, §5Lion */ - private val autopetHoverPetPattern by patternGroup.pattern( + private val autopetHoverPetPattern by PetAPI.patternGroup.pattern( "chat.autopet.hover.pet", "^§r, §aEquip: §r,(?: §e⭐ §r,)? §7\\[Lvl (?\\d+)] §r, §(?.)(?[\\w ]+)(?:§r, (?§. ✦))?\$", ) @@ -220,18 +213,10 @@ object PetAPI { * REGEX-TEST: §r, §aHeld Item: §r, §5Lucky Clover§r] * REGEX-TEST: §r, §aHeld Item: §r, §5Fishing Exp Boost§r] */ - private val autopetHoverPetItemPattern by patternGroup.pattern( + private val autopetHoverPetItemPattern by PetAPI.patternGroup.pattern( "chat.autopet.hover.item", "^§r, §aHeld Item: §r, (?§.[\\w -]+)§r]\$", ) - - /** - * REGEX-TEST: §aYour pet is now holding §r§9Bejeweled Collar§r§a. - */ - private val petItemMessagePattern by patternGroup.pattern( - "chat.pet.item.equip", - "^§aYour pet is now holding §r(?§.[\\w -]+)§r§a\\.\$", - ) // // @@ -257,14 +242,11 @@ object PetAPI { return null } - private fun petNameToInternalName(name: String, rarity: LorenzRarity): NEUInternalName = - "${name.convertToUnformatted()}${rarity.id}".asInternalName() - private fun getFakePetLine(level: Int, rarity: LorenzRarity, petName: String, skin: String? = null): String { return "§r§7[Lvl $level] §r${rarity.chatColorCode}$petName§r${skin.orEmpty()}" } - private fun rarityByColorGroup(color: String): LorenzRarity = LorenzRarity.getByColorCode(color[0]) + fun rarityByColorGroup(color: String): LorenzRarity = LorenzRarity.getByColorCode(color[0]) ?: ErrorManager.skyHanniError( "Unknown rarity", Pair("rarity", color), @@ -297,7 +279,7 @@ object PetAPI { } private fun levelToXP(level: Int, rarity: LorenzRarity, petName: String): Double? { - val newPetName = petName.asInternalName().toString() + val newPetName = petName.toInternalName().toString() val rarityOffset = getRarityOffset(rarity, newPetName) ?: return null if (!isValidLevel(level, newPetName)) return null @@ -355,23 +337,6 @@ object PetAPI { PetChangeEvent(oldPet, newPet).post() } - @Suppress("DestructuringDeclarationWithTooManyEntries") - private fun getPetDataFromItem(item: ItemStack) { - val (_, _, rarity, petItem, _, petXP, _) = parsePetNBT(item) - val (internalName, name, _, _, level, _, skin) = parsePetName(item.displayName) ?: return - - val newPet = PetData( - internalName, - name, - rarity, - petItem, - level, - petXP, - "§r§7[Lvl $level] §r${rarity?.chatColorCode}$name${if (skin != "") "§r$skin" else ""}", - ) - updatePet(newPet) - } - private fun handlePetMessageBlock(event: LorenzChatEvent) { if (!config.hideAutopet) return val spawnMatches = chatSpawnPattern.matches(event.message) @@ -383,94 +348,6 @@ object PetAPI { } // - // - private fun parsePetData( - lines: List, - itemHandler: (String) -> NEUInternalName?, - xpHandler: (String) -> Double?, - petHandler: (String) -> PetData? - ): Pair? { - return parsePetDataLists( - lines, - itemHandlerList = { it.firstNotNullOfOrNull(itemHandler) }, - xpHandlerList = { it.firstNotNullOfOrNull(xpHandler) }, - petHandlerList = { it.firstNotNullOfOrNull(petHandler) } - ) - } - - private fun parsePetDataLists( - lines: List, - itemHandlerList: (List) -> NEUInternalName?, - xpHandlerList: (List) -> Double?, - petHandlerList: (List) -> PetData? - ): Pair? { - val petItem = itemHandlerList(lines) ?: return null - val overflowXP = xpHandlerList(lines) ?: 0.0 - - val data = petHandlerList(lines) ?: return null - val petData = PetData( - internalName = data.internalName, - cleanName = data.cleanName, - rarity = data.rarity, - petItem = petItem, - level = data.level, - xp = data.xp, - rawPetName = data.rawPetName, - ) - - return petData to overflowXP - } - - private fun parsePetAsItem(item: ItemStack) { - val lore = item.getLore() - - if (lore.any { petDespawnMenuPattern.matches(it) }) { - updatePet(null) - return - } - - getPetDataFromItem(item) - } - - private fun parsePetNBT(item: ItemStack): PetData { - val petInfo = Gson().fromJson(item.getExtraAttributes()?.getString("petInfo"), PetNBT::class.java) - - return PetData( - internalName = NEUInternalName.NONE, - cleanName = "", - level = 0, - rarity = LorenzRarity.getByName(petInfo.tier) ?: ErrorManager.skyHanniError( - "Couldn't parse pet rarity.", - Pair("petNBT", petInfo), - Pair("rarity", petInfo.tier), - ), - petItem = petInfo.heldItem?.asInternalName(), - xp = petInfo.exp, - rawPetName = "", - ) - } - - private fun parsePetName(displayName: String): PetData? { - petNameMenuPattern.matchMatcher(displayName) { - val name = group("name").orEmpty() - val rarity = rarityByColorGroup(group("rarity")) - val level = group("level").toInt() - val skin = group("skin").orEmpty() - - return PetData( - internalName = petNameToInternalName(name, rarity), - cleanName = name, - rarity = rarity, - petItem = null, - level = level, - xp = 0.0, - rawPetName = skin, - ) - } - return null - } - // - // private fun handleWidgetPetLine(line: String, newPetLine: String): PetData? = petWidgetPattern.matchMatcher(line) { val rarity = rarityByColorGroup(group("rarity")) @@ -661,7 +538,7 @@ object PetAPI { val category = event.item?.getItemCategoryOrNull() ?: return if (category != ItemCategory.PET) return - parsePetAsItem(event.item) + updatePet(parsePetAsItem(event.item)) } @SubscribeEvent @@ -682,18 +559,3 @@ object PetAPI { } // } - -data class PetNBT( - val type: String, - val active: Boolean, - val exp: Double, - val tier: String, - val hideInfo: Boolean, - val heldItem: String?, - val candyUsed: Int, - val skin: String?, - val uuid: String, - val uniqueId: String, - val hideRightClick: Boolean, - val noMove: Boolean, -) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetData.kt b/src/main/java/at/hannibal2/skyhanni/data/PetData.kt index b2e02ff83e1c..ffee68acddb4 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetData.kt @@ -1,8 +1,39 @@ package at.hannibal2.skyhanni.data +import at.hannibal2.skyhanni.data.PetAPI.rarityByColorGroup +import at.hannibal2.skyhanni.test.command.ErrorManager +import at.hannibal2.skyhanni.utils.ItemUtils.getLore import at.hannibal2.skyhanni.utils.ItemUtils.itemName import at.hannibal2.skyhanni.utils.LorenzRarity import at.hannibal2.skyhanni.utils.NEUInternalName +import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.asInternalName +import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.toInternalName +import at.hannibal2.skyhanni.utils.RegexUtils.anyMatches +import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher +import at.hannibal2.skyhanni.utils.SkyBlockItemModifierUtils.getExtraAttributes +import at.hannibal2.skyhanni.utils.StringUtils.convertToUnformatted +import com.google.gson.Gson +import net.minecraft.item.ItemStack + +// +/** + * REGEX-TEST: §e⭐ §7[Lvl 100] §6Ender Dragon + * REGEX-TEST: §e⭐ §7[Lvl 100] §dBlack Cat§d ✦ + * REGEX-TEST: §7[Lvl 100] §6Mole + */ +private val petNameMenuPattern by PetAPI.patternGroup.pattern( + "menu.pet.name", + "^(?:§e(?⭐) )?(?:§.)*\\[Lvl (?\\d+)] §(?.)(?[\\w ]+)(?§. ✦)?\$", +) + +/** + * REGEX-TEST: §7§cClick to despawn! + */ +private val petDespawnMenuPattern by PetAPI.patternGroup.pattern( + "menu.pet.despawn", + "§7§cClick to despawn!", +) +// data class PetData( val internalName: NEUInternalName? = null, @@ -37,4 +68,123 @@ data class PetData( fun isInitialized(): Boolean { return internalName != null && cleanName != null && rarity != null && level != null && xp != null && rawPetName != null } + + companion object { + // + fun parsePetData( + lines: List, + itemHandler: (String) -> NEUInternalName?, + xpHandler: (String) -> Double?, + petHandler: (String) -> PetData? + ): Pair? { + return parsePetDataLists( + lines, + itemHandlerList = { it.firstNotNullOfOrNull(itemHandler) }, + xpHandlerList = { it.firstNotNullOfOrNull(xpHandler) }, + petHandlerList = { it.firstNotNullOfOrNull(petHandler) } + ) + } + + fun parsePetDataLists( + lines: List, + itemHandlerList: (List) -> NEUInternalName?, + xpHandlerList: (List) -> Double?, + petHandlerList: (List) -> PetData? + ): Pair? { + val petItem = itemHandlerList(lines) ?: return null + val overflowXP = xpHandlerList(lines) ?: 0.0 + + val data = petHandlerList(lines) ?: return null + val petData = PetData( + internalName = data.internalName, + cleanName = data.cleanName, + rarity = data.rarity, + petItem = petItem, + level = data.level, + xp = data.xp, + rawPetName = data.rawPetName, + ) + + return petData to overflowXP + } + + private fun parsePetNBT(item: ItemStack): PetData { + val petInfo = Gson().fromJson(item.getExtraAttributes()?.getString("petInfo"), PetNBT::class.java) + + return PetData( + internalName = NEUInternalName.NONE, + cleanName = "", + level = 0, + rarity = LorenzRarity.getByName(petInfo.tier) ?: ErrorManager.skyHanniError( + "Couldn't parse pet rarity.", + Pair("petNBT", petInfo), + Pair("rarity", petInfo.tier), + ), + petItem = petInfo.heldItem?.asInternalName(), + xp = petInfo.exp, + rawPetName = "", + ) + } + + fun parsePetName(displayName: String): PetData? { + petNameMenuPattern.matchMatcher(displayName) { + val name = group("name").orEmpty() + val rarity = rarityByColorGroup(group("rarity")) + val level = group("level").toInt() + val skin = group("skin").orEmpty() + + return PetData( + internalName = petNameToInternalName(name, rarity), + cleanName = name, + rarity = rarity, + petItem = null, + level = level, + xp = 0.0, + rawPetName = skin, + ) + } + return null + } + + fun petNameToInternalName(name: String, rarity: LorenzRarity): NEUInternalName = + "${name.convertToUnformatted()}${rarity.id}".toInternalName() + + fun parsePetAsItem(item: ItemStack): PetData? { + val lore = item.getLore() + if (petDespawnMenuPattern.anyMatches(lore)) return null + return getPetDataFromItem(item) + } + + @Suppress("DestructuringDeclarationWithTooManyEntries") + private fun getPetDataFromItem(item: ItemStack): PetData? { + val (_, _, rarity, petItem, _, petXP, _) = parsePetNBT(item) + val (internalName, name, _, _, level, _, skin) = parsePetName(item.displayName) ?: return null + + return PetData( + internalName, + name, + rarity, + petItem, + level, + petXP, + "§r§7[Lvl $level] §r${rarity?.chatColorCode}$name${if (skin != "") "§r$skin" else ""}", + ) + } + // + } } + +data class PetNBT( + val type: String, + val active: Boolean, + val exp: Double, + val tier: String, + val hideInfo: Boolean, + val heldItem: String?, + val candyUsed: Int, + val skin: String?, + val uuid: String, + val uniqueId: String, + val hideRightClick: Boolean, + val noMove: Boolean, +) From 9239dc412abf304d62273bc698a3d40b46b0c341 Mon Sep 17 00:00:00 2001 From: David Cole <40234707+DavidArthurCole@users.noreply.github.com> Date: Tue, 10 Dec 2024 02:34:38 -0500 Subject: [PATCH 54/91] Refactor to Utils + API, improvements --- .../{data/PetAPI.kt => api/CurrentPetAPI.kt} | 236 +++--------------- .../at/hannibal2/skyhanni/data/PetData.kt | 7 +- .../skyhanni/features/event/diana/DianaAPI.kt | 4 +- .../event/hoppity/MythicRabbitPetWarning.kt | 4 +- .../skyhanni/features/garden/GardenAPI.kt | 4 +- .../garden/fortuneguide/CaptureFarmingGear.kt | 4 +- .../inventory/ItemDisplayOverlayFeatures.kt | 5 +- .../ExperimentationTableAPI.kt | 6 +- .../features/misc/discordrpc/DiscordStatus.kt | 4 +- .../features/misc/pets/CurrentPetDisplay.kt | 4 +- .../at/hannibal2/skyhanni/utils/ItemUtils.kt | 6 +- .../at/hannibal2/skyhanni/utils/PetUtils.kt | 191 ++++++++++++++ .../utils/SkyBlockItemModifierUtils.kt | 2 +- 13 files changed, 252 insertions(+), 225 deletions(-) rename src/main/java/at/hannibal2/skyhanni/{data/PetAPI.kt => api/CurrentPetAPI.kt} (69%) create mode 100644 src/main/java/at/hannibal2/skyhanni/utils/PetUtils.kt diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt b/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt similarity index 69% rename from src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt rename to src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt index 2703f048b88f..f09e13ac1142 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt @@ -1,22 +1,19 @@ -package at.hannibal2.skyhanni.data +package at.hannibal2.skyhanni.api import at.hannibal2.skyhanni.SkyHanniMod import at.hannibal2.skyhanni.api.event.HandleEvent -import at.hannibal2.skyhanni.config.commands.CommandCategory -import at.hannibal2.skyhanni.config.commands.CommandRegistrationEvent +import at.hannibal2.skyhanni.data.PetData import at.hannibal2.skyhanni.data.PetData.Companion.parsePetAsItem import at.hannibal2.skyhanni.data.PetData.Companion.parsePetData import at.hannibal2.skyhanni.data.PetData.Companion.parsePetDataLists import at.hannibal2.skyhanni.data.PetData.Companion.petNameToInternalName -import at.hannibal2.skyhanni.data.jsonobjects.repo.NEUPetData -import at.hannibal2.skyhanni.data.jsonobjects.repo.NEUPetsJson +import at.hannibal2.skyhanni.data.ProfileStorageData import at.hannibal2.skyhanni.data.model.TabWidget import at.hannibal2.skyhanni.events.DebugDataCollectEvent import at.hannibal2.skyhanni.events.GuiContainerEvent import at.hannibal2.skyhanni.events.InventoryCloseEvent import at.hannibal2.skyhanni.events.InventoryFullyOpenedEvent import at.hannibal2.skyhanni.events.LorenzChatEvent -import at.hannibal2.skyhanni.events.NeuRepositoryReloadEvent import at.hannibal2.skyhanni.events.WidgetUpdateEvent import at.hannibal2.skyhanni.events.skyblock.PetChangeEvent import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule @@ -27,9 +24,11 @@ import at.hannibal2.skyhanni.utils.ItemUtils.getItemCategoryOrNull import at.hannibal2.skyhanni.utils.ItemUtils.getLore import at.hannibal2.skyhanni.utils.LorenzRarity import at.hannibal2.skyhanni.utils.NEUInternalName -import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.toInternalName -import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators import at.hannibal2.skyhanni.utils.NumberUtil.formatDouble +import at.hannibal2.skyhanni.utils.PetUtils.getFakePetLine +import at.hannibal2.skyhanni.utils.PetUtils.isPetMenu +import at.hannibal2.skyhanni.utils.PetUtils.levelToXP +import at.hannibal2.skyhanni.utils.PetUtils.rarityByColorGroup import at.hannibal2.skyhanni.utils.RegexUtils.firstMatchGroup import at.hannibal2.skyhanni.utils.RegexUtils.firstMatcher import at.hannibal2.skyhanni.utils.RegexUtils.firstMatches @@ -40,19 +39,14 @@ import at.hannibal2.skyhanni.utils.RegexUtils.matches import at.hannibal2.skyhanni.utils.StringUtils.convertToUnformatted import at.hannibal2.skyhanni.utils.chat.Text.hover import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern -import net.minecraft.item.ItemStack import net.minecraftforge.fml.common.eventhandler.SubscribeEvent @SkyHanniModule -object PetAPI { +object CurrentPetAPI { private val config get() = SkyHanniMod.feature.misc.pets - private const val FORGE_BACK_SLOT = 48 - val patternGroup = RepoPattern.group("misc.pet") private var inPetMenu = false - private var baseXpLevelReqs: List = listOf() - private var customXpLevelReqs: Map? = null var currentPet: PetData? get() = ProfileStorageData.profileSpecific?.currentPet?.takeIf { it.isInitialized() } @@ -60,47 +54,9 @@ object PetAPI { ProfileStorageData.profileSpecific?.currentPet = value } - // - /** - * REGEX-TEST: Pets (1/3) - * REGEX-TEST: Pets - * REGEX-TEST: Pets (1/4) - * REGEX-TEST: Pets (1/2) - */ - private val petMenuPattern by patternGroup.pattern( - "menu.title", - "Pets(?: \\(\\d+/\\d+\\) )?", - ) - - /** - * REGEX-TEST: §e⭐ §7[Lvl 200] §6Golden Dragon§d ✦ - * REGEX-TEST: ⭐ [Lvl 100] Black Cat ✦ - */ - val petItemNamePattern by patternGroup.pattern( - "item.name", - "(?(?:§.)*⭐ )?(?:§.)*\\[Lvl (?\\d+)] (?.*)", - ) - - /** - * REGEX-TEST: §7[Lvl 1➡200] §6Golden Dragon - * REGEX-TEST: §7[Lvl {LVL}] §6Golden Dragon - */ - private val neuRepoPetItemNamePattern by patternGroup.pattern( - "item.name.neu.format", - "(?:§f§f)?§7\\[Lvl (?:1➡(?:100|200)|\\{LVL})] (?.*)", - ) - - /** - * REGEX-TEST: §7To Select Process (Slot #2) - * REGEX-TEST: §7To Select Process (Slot #4) - * REGEX-TEST: §7To Select Process (Slot #7) - * REGEX-TEST: §7To Select Process - */ - private val forgeBackMenuPattern by patternGroup.pattern( - "menu.forge.goback", - "§7To Select Process(?: \\(Slot #\\d\\))?", - ) + fun isCurrentPet(petName: String): Boolean = currentPet?.cleanName?.contains(petName) ?: false + // /** * REGEX-TEST: §r§7[Lvl 100] §r§dEndermite * REGEX-TEST: §r§7[Lvl 200] §r§8[§r§6108§r§8§r§4✦§r§8] §r§6Golden Dragon @@ -122,24 +78,6 @@ object PetAPI { "^§cAutopet §eequipped your §7(?\\[Lvl \\d{1,3}] §.[\\w ]+)(?:§. ✦)?§e! §a§lVIEW RULE\$", ) - /** - * REGEX-TEST: §aYou despawned your §r§6Golden Dragon§r§a! - * REGEX-TEST: §aYou despawned your §r§6Silverfish§r§5 ✦§r§a! - */ - private val chatDespawnPattern by patternGroup.pattern( - "chat.despawn", - "§aYou despawned your §r.*§r§a!", - ) - - /** - * REGEX-TEST: §aYou summoned your §r§6Silverfish§r§5 ✦§r§a! - * REGEX-TEST: §aYou summoned your §r§6Golden Dragon§r§a! - */ - private val chatSpawnPattern by patternGroup.pattern( - "chat.spawn", - "§aYou summoned your §r(?.*)§r§a!" - ) - /** * REGEX-TEST: §aYour pet is now holding §r§9Bejeweled Collar§r§a. */ @@ -151,7 +89,7 @@ object PetAPI { /** * REGEX-TEST: §7§7Selected pet: §6Hedgehog */ - private val inventorySelectedPetPattern by PetAPI.patternGroup.pattern( + private val inventorySelectedPetPattern by patternGroup.pattern( "inventory.selected", "§7§7Selected pet: §?(?.)?(?.*)" ) @@ -161,7 +99,7 @@ object PetAPI { * REGEX-TEST: §7Progress to Level 147: §e37.1% * REGEX-TEST: §b§lMAX LEVEL */ - private val inventorySelectedProgressPattern by PetAPI.patternGroup.pattern( + private val inventorySelectedProgressPattern by patternGroup.pattern( "inventory.selected.progress", "§b§lMAX LEVEL|§7Progress to Level (?\\d+): §e(?[\\d.]+)%" ) @@ -172,7 +110,7 @@ object PetAPI { * REGEX-TEST: §f§l§m §r §e0§6/§e660 * REGEX-TEST: §8▸ 30,358,983 XP' */ - private val inventorySelectedXpPattern by PetAPI.patternGroup.pattern( + private val inventorySelectedXpPattern by patternGroup.pattern( "inventory.selected.xp", "(?:§8▸ |(?:§.§l§m *)*)(?:§r §e)?(?[\\d,.kM]+)(?:§6\\/§e)?(?[\\d,.kM]+)?" ) @@ -182,7 +120,7 @@ object PetAPI { * REGEX-TEST: §r§6Washed-up Souvenir * REGEX-TEST: §r§9Dwarf Turtle Shelmet */ - private val widgetStringPattern by PetAPI.patternGroup.pattern( + private val widgetStringPattern by patternGroup.pattern( "widget.string", "^ §r(?§.[\\w -]+)\$", ) @@ -193,7 +131,7 @@ object PetAPI { * REGEX-TEST: §r§e15,986.6§r§6/§r§e29k XP §r§6(53.6%) */ @Suppress("MaxLineLength") - private val xpWidgetPattern by PetAPI.patternGroup.pattern( + private val xpWidgetPattern by patternGroup.pattern( "widget.xp", "^ §r§.(?:§l(?MAX LEVEL)|\\+§r§e(?[\\d,.]+) XP|(?[\\d,.]+)§r§6/§r§e(?[\\d.km]+) XP §r§6\\((?[\\d.%]+)\\))$", ) @@ -203,7 +141,7 @@ object PetAPI { * REGEX-TEST: §r, §aEquip: §r, §e⭐ §r, §7[Lvl 100] §r, §dBlack Cat§r, §d ✦ * REGEX-TEST: §r, §aEquip: §r, §7[Lvl 47] §r, §5Lion */ - private val autopetHoverPetPattern by PetAPI.patternGroup.pattern( + private val autopetHoverPetPattern by patternGroup.pattern( "chat.autopet.hover.pet", "^§r, §aEquip: §r,(?: §e⭐ §r,)? §7\\[Lvl (?\\d+)] §r, §(?.)(?[\\w ]+)(?:§r, (?§. ✦))?\$", ) @@ -213,119 +151,31 @@ object PetAPI { * REGEX-TEST: §r, §aHeld Item: §r, §5Lucky Clover§r] * REGEX-TEST: §r, §aHeld Item: §r, §5Fishing Exp Boost§r] */ - private val autopetHoverPetItemPattern by PetAPI.patternGroup.pattern( + private val autopetHoverPetItemPattern by patternGroup.pattern( "chat.autopet.hover.item", "^§r, §aHeld Item: §r, (?§.[\\w -]+)§r]\$", ) - // - // - fun isPetMenu(inventoryTitle: String, inventoryItems: Map): Boolean { - if (!petMenuPattern.matches(inventoryTitle)) return false - - // Otherwise make sure they're not in the Forge menu looking at pets - return inventoryItems[FORGE_BACK_SLOT]?.getLore().orEmpty().none { - forgeBackMenuPattern.matches(it) - } - } - - fun isCurrentPet(petName: String): Boolean = currentPet?.cleanName?.contains(petName) ?: false - - fun getCleanName(nameWithLevel: String): String? { - petItemNamePattern.matchMatcher(nameWithLevel) { - return group("name") - } - neuRepoPetItemNamePattern.matchMatcher(nameWithLevel) { - return group("name") - } - - return null - } - - private fun getFakePetLine(level: Int, rarity: LorenzRarity, petName: String, skin: String? = null): String { - return "§r§7[Lvl $level] §r${rarity.chatColorCode}$petName§r${skin.orEmpty()}" - } - - fun rarityByColorGroup(color: String): LorenzRarity = LorenzRarity.getByColorCode(color[0]) - ?: ErrorManager.skyHanniError( - "Unknown rarity", - Pair("rarity", color), - ) - - private fun levelToXPCommand(input: Array) { - if (input.size < 3) { - ChatUtils.userError("Usage: /shcalcpetxp ") - return - } - - val level = input[0].toIntOrNull() - if (level == null) { - ChatUtils.userError("Invalid level '${input[0]}'.") - return - } - val rarity = LorenzRarity.getByName(input[1]) - if (rarity == null) { - ChatUtils.userError("Invalid rarity '${input[1]}'.") - return - } - - val petName = input.slice(2..= level - } - - private fun getCustomLeveling(petName: String): List { - return customXpLevelReqs?.get(petName)?.petLevels.orEmpty() - } - - private fun getRarityOffset(rarity: LorenzRarity, petName: String): Int? { - val petsData = customXpLevelReqs ?: run { - ErrorManager.skyHanniError("NEUPetsData is null") - } + /** + * REGEX-TEST: §aYou despawned your §r§6Golden Dragon§r§a! + * REGEX-TEST: §aYou despawned your §r§6Silverfish§r§5 ✦§r§a! + */ + private val chatDespawnPattern by CurrentPetAPI.patternGroup.pattern( + "chat.despawn", + "§aYou despawned your §r.*§r§a!", + ) - return if (petName in petsData.keys) { - val petData = petsData[petName] - petData?.rarityOffset?.get(rarity) - } else { - when (rarity) { - LorenzRarity.COMMON -> 0 - LorenzRarity.UNCOMMON -> 6 - LorenzRarity.RARE -> 11 - LorenzRarity.EPIC -> 16 - LorenzRarity.LEGENDARY -> 20 - LorenzRarity.MYTHIC -> 20 - else -> { - ChatUtils.userError("Invalid Rarity \"${rarity.name}\"") - null - } - } - } - } + /** + * REGEX-TEST: §aYou summoned your §r§6Silverfish§r§5 ✦§r§a! + * REGEX-TEST: §aYou summoned your §r§6Golden Dragon§r§a! + */ + private val chatSpawnPattern by CurrentPetAPI.patternGroup.pattern( + "chat.spawn", + "§aYou summoned your §r(?.*)§r§a!" + ) + // + // private fun updatePet(newPet: PetData?) { if (newPet == currentPet) return val oldPet = currentPet @@ -460,15 +310,6 @@ object PetAPI { // // - @HandleEvent - fun onCommandRegistration(event: CommandRegistrationEvent) { - event.register("shpetxp") { - description = "Calculates the pet xp from a given level and rarity." - category = CommandCategory.DEVELOPER_TEST - callback { levelToXPCommand(it) } - } - } - @HandleEvent fun onWidgetUpdate(event: WidgetUpdateEvent) { if (!event.isWidget(TabWidget.PET)) return @@ -486,13 +327,6 @@ object PetAPI { updatePet(petData.copy(xp = petData.xp?.plus(overflowXP))) } - @HandleEvent - fun onNEURepoReload(event: NeuRepositoryReloadEvent) { - val data = event.getConstant("pets") - baseXpLevelReqs = data.petLevels - customXpLevelReqs = data.customPetLeveling - } - @SubscribeEvent fun onChat(event: LorenzChatEvent) { handlePetMessageBlock(event) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetData.kt b/src/main/java/at/hannibal2/skyhanni/data/PetData.kt index ffee68acddb4..8529ca914945 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetData.kt @@ -1,6 +1,6 @@ package at.hannibal2.skyhanni.data -import at.hannibal2.skyhanni.data.PetAPI.rarityByColorGroup +import at.hannibal2.skyhanni.api.CurrentPetAPI import at.hannibal2.skyhanni.test.command.ErrorManager import at.hannibal2.skyhanni.utils.ItemUtils.getLore import at.hannibal2.skyhanni.utils.ItemUtils.itemName @@ -8,6 +8,7 @@ import at.hannibal2.skyhanni.utils.LorenzRarity import at.hannibal2.skyhanni.utils.NEUInternalName import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.asInternalName import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.toInternalName +import at.hannibal2.skyhanni.utils.PetUtils.rarityByColorGroup import at.hannibal2.skyhanni.utils.RegexUtils.anyMatches import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.SkyBlockItemModifierUtils.getExtraAttributes @@ -21,7 +22,7 @@ import net.minecraft.item.ItemStack * REGEX-TEST: §e⭐ §7[Lvl 100] §dBlack Cat§d ✦ * REGEX-TEST: §7[Lvl 100] §6Mole */ -private val petNameMenuPattern by PetAPI.patternGroup.pattern( +private val petNameMenuPattern by CurrentPetAPI.patternGroup.pattern( "menu.pet.name", "^(?:§e(?⭐) )?(?:§.)*\\[Lvl (?\\d+)] §(?.)(?[\\w ]+)(?§. ✦)?\$", ) @@ -29,7 +30,7 @@ private val petNameMenuPattern by PetAPI.patternGroup.pattern( /** * REGEX-TEST: §7§cClick to despawn! */ -private val petDespawnMenuPattern by PetAPI.patternGroup.pattern( +private val petDespawnMenuPattern by CurrentPetAPI.patternGroup.pattern( "menu.pet.despawn", "§7§cClick to despawn!", ) diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/diana/DianaAPI.kt b/src/main/java/at/hannibal2/skyhanni/features/event/diana/DianaAPI.kt index d06c187ee9d3..883336977ba8 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/event/diana/DianaAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/event/diana/DianaAPI.kt @@ -1,9 +1,9 @@ package at.hannibal2.skyhanni.features.event.diana +import at.hannibal2.skyhanni.api.CurrentPetAPI import at.hannibal2.skyhanni.api.event.HandleEvent import at.hannibal2.skyhanni.data.IslandType import at.hannibal2.skyhanni.data.Perk -import at.hannibal2.skyhanni.data.PetAPI import at.hannibal2.skyhanni.events.diana.InquisitorFoundEvent import at.hannibal2.skyhanni.events.entity.EntityEnterWorldEvent import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule @@ -24,7 +24,7 @@ object DianaAPI { private fun isRitualActive() = Perk.MYTHOLOGICAL_RITUAL.isActive || Perk.PERKPOCALYPSE.isActive - fun hasGriffinPet() = PetAPI.isCurrentPet("Griffin") + fun hasGriffinPet() = CurrentPetAPI.isCurrentPet("Griffin") fun isDoingDiana() = IslandType.HUB.isInIsland() && isRitualActive() && hasSpadeInInventory() diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/MythicRabbitPetWarning.kt b/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/MythicRabbitPetWarning.kt index 833583ad05bb..2eb11dab154c 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/MythicRabbitPetWarning.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/MythicRabbitPetWarning.kt @@ -1,6 +1,6 @@ package at.hannibal2.skyhanni.features.event.hoppity -import at.hannibal2.skyhanni.data.PetAPI +import at.hannibal2.skyhanni.api.CurrentPetAPI import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.SimpleTimeMark @@ -21,7 +21,7 @@ object MythicRabbitPetWarning { } } - fun correctPet() = PetAPI.isCurrentPet(MYTHIC_RABBIT_DISPLAY_NAME) + fun correctPet() = CurrentPetAPI.isCurrentPet(MYTHIC_RABBIT_DISPLAY_NAME) private fun warn() { ChatUtils.chat("Use a §dMythic Rabbit Pet §efor more chocolate!") diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenAPI.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenAPI.kt index ebcc82491e4c..b6e0dac7d643 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenAPI.kt @@ -1,9 +1,9 @@ package at.hannibal2.skyhanni.features.garden import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.api.CurrentPetAPI import at.hannibal2.skyhanni.api.event.HandleEvent import at.hannibal2.skyhanni.data.IslandType -import at.hannibal2.skyhanni.data.PetAPI import at.hannibal2.skyhanni.data.ProfileStorageData import at.hannibal2.skyhanni.data.jsonobjects.repo.GardenJson import at.hannibal2.skyhanni.events.BlockClickEvent @@ -60,7 +60,7 @@ object GardenAPI { var itemInHand: ItemStack? = null var cropInHand: CropType? = null val mushroomCowPet - get() = PetAPI.isCurrentPet("Mooshroom Cow") && + get() = CurrentPetAPI.isCurrentPet("Mooshroom Cow") && storage?.fortune?.farmingItems?.get(FarmingItems.MOOSHROOM_COW) ?.let { it.getItemRarityOrNull()?.isAtLeast(LorenzRarity.RARE) } ?: false private var inBarn = false diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/fortuneguide/CaptureFarmingGear.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/fortuneguide/CaptureFarmingGear.kt index 12a09636e035..e039793107e1 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/fortuneguide/CaptureFarmingGear.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/fortuneguide/CaptureFarmingGear.kt @@ -3,7 +3,6 @@ package at.hannibal2.skyhanni.features.garden.fortuneguide import at.hannibal2.skyhanni.api.event.HandleEvent import at.hannibal2.skyhanni.config.ConfigUpdaterMigrator import at.hannibal2.skyhanni.config.storage.ProfileSpecificStorage -import at.hannibal2.skyhanni.data.PetAPI import at.hannibal2.skyhanni.data.ProfileStorageData import at.hannibal2.skyhanni.events.GardenToolChangeEvent import at.hannibal2.skyhanni.events.InventoryFullyOpenedEvent @@ -23,6 +22,7 @@ import at.hannibal2.skyhanni.utils.ItemUtils.getLore import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.NumberUtil.romanToDecimal import at.hannibal2.skyhanni.utils.NumberUtil.romanToDecimalIfNecessary +import at.hannibal2.skyhanni.utils.PetUtils.isPetMenu import at.hannibal2.skyhanni.utils.RegexUtils.firstMatcher import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.SimpleTimeMark.Companion.fromNow @@ -175,7 +175,7 @@ object CaptureFarmingGear { val storage = GardenAPI.storage?.fortune ?: return val outdatedItems = outdatedItems ?: return val items = event.inventoryItems - if (PetAPI.isPetMenu(event.inventoryName, event.inventoryItems)) { + if (isPetMenu(event.inventoryName, event.inventoryItems)) { pets(items, outdatedItems) return } diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/ItemDisplayOverlayFeatures.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/ItemDisplayOverlayFeatures.kt index e4ec55351758..653fe306e753 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/inventory/ItemDisplayOverlayFeatures.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/ItemDisplayOverlayFeatures.kt @@ -2,6 +2,7 @@ package at.hannibal2.skyhanni.features.inventory import at.hannibal2.skyhanni.SkyHanniMod import at.hannibal2.skyhanni.api.CollectionAPI +import at.hannibal2.skyhanni.api.CurrentPetAPI import at.hannibal2.skyhanni.api.SkillAPI import at.hannibal2.skyhanni.api.event.HandleEvent import at.hannibal2.skyhanni.config.ConfigUpdaterMigrator @@ -26,7 +27,6 @@ import at.hannibal2.skyhanni.config.features.inventory.InventoryConfig.ItemNumbe import at.hannibal2.skyhanni.config.features.inventory.InventoryConfig.ItemNumberEntry.SKILL_LEVEL import at.hannibal2.skyhanni.config.features.inventory.InventoryConfig.ItemNumberEntry.SKYBLOCK_LEVEL import at.hannibal2.skyhanni.config.features.inventory.InventoryConfig.ItemNumberEntry.VACUUM_GARDEN -import at.hannibal2.skyhanni.data.PetAPI import at.hannibal2.skyhanni.events.RenderItemTipEvent import at.hannibal2.skyhanni.features.garden.GardenAPI import at.hannibal2.skyhanni.features.garden.pests.PestAPI @@ -76,6 +76,7 @@ object ItemDisplayOverlayFeatures { "masterskull.id", "MASTER_SKULL_TIER_(?\\d)", ) + /** * REGEX-TEST: §7Vacuum Bag: §21 Pest * REGEX-TEST: §7Vacuum Bag: §2444 Pests @@ -232,7 +233,7 @@ object ItemDisplayOverlayFeatures { if (RANCHERS_BOOTS_SPEED.isSelected() && internalName == "RANCHERS_BOOTS".toInternalName()) { item.getRanchersSpeed()?.let { - val isUsingBlackCat = PetAPI.isCurrentPet("Black Cat") + val isUsingBlackCat = CurrentPetAPI.isCurrentPet("Black Cat") val helmet = InventoryUtils.getHelmet()?.getInternalName() val hand = InventoryUtils.getItemInHand()?.getInternalName() val racingHelmet = "RACING_HELMET".toInternalName() diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentationTableAPI.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentationTableAPI.kt index bfaab71a321f..77b901517589 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentationTableAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentationTableAPI.kt @@ -1,7 +1,7 @@ package at.hannibal2.skyhanni.features.inventory.experimentationtable +import at.hannibal2.skyhanni.api.CurrentPetAPI import at.hannibal2.skyhanni.data.IslandType -import at.hannibal2.skyhanni.data.PetAPI import at.hannibal2.skyhanni.data.ProfileStorageData import at.hannibal2.skyhanni.events.InventoryUpdatedEvent import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule @@ -136,7 +136,7 @@ object ExperimentationTableAPI { */ val remainingClicksPattern by patternGroup.pattern( "clicks", - "Remaining Clicks: (?\\d+)" + "Remaining Clicks: (?\\d+)", ) /** @@ -173,5 +173,5 @@ object ExperimentationTableAPI { "(?:§[956d])?Guardian.*", ) - fun hasGuardianPet(): Boolean = petNamePattern.matches(PetAPI.currentPet?.rawPetName) + fun hasGuardianPet(): Boolean = petNamePattern.matches(CurrentPetAPI.currentPet?.rawPetName) } diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt index e9bb50567546..4fd2cd698adc 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt @@ -2,6 +2,7 @@ package at.hannibal2.skyhanni.features.misc.discordrpc // SkyblockAddons code, adapted for SkyHanni with some additions and fixes +import at.hannibal2.skyhanni.api.CurrentPetAPI import at.hannibal2.skyhanni.data.ActionBarStatsData import at.hannibal2.skyhanni.data.GardenCropMilestones.getCounter import at.hannibal2.skyhanni.data.GardenCropMilestones.getTierForCropCount @@ -9,7 +10,6 @@ import at.hannibal2.skyhanni.data.GardenCropMilestones.isMaxed import at.hannibal2.skyhanni.data.GardenCropMilestones.progressToNextLevel import at.hannibal2.skyhanni.data.HypixelData import at.hannibal2.skyhanni.data.IslandType -import at.hannibal2.skyhanni.data.PetAPI import at.hannibal2.skyhanni.data.ScoreboardData import at.hannibal2.skyhanni.features.dungeon.DungeonAPI import at.hannibal2.skyhanni.features.garden.GardenAPI @@ -71,7 +71,7 @@ private fun getCropMilestoneDisplay(): String { return "${crop.cropName}: $text" } -private fun getPetDisplay(): String = PetAPI.currentPet?.rawPetName ?: "No pet equipped" +private fun getPetDisplay(): String = CurrentPetAPI.currentPet?.rawPetName ?: "No pet equipped" enum class DiscordStatus(private val displayMessageSupplier: (() -> String?)) { diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt index 6edd1bb59e40..386d95274282 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt @@ -1,8 +1,8 @@ package at.hannibal2.skyhanni.features.misc.pets import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.api.CurrentPetAPI import at.hannibal2.skyhanni.config.ConfigUpdaterMigrator -import at.hannibal2.skyhanni.data.PetAPI import at.hannibal2.skyhanni.events.GuiRenderEvent import at.hannibal2.skyhanni.features.rift.RiftAPI import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule @@ -22,7 +22,7 @@ object CurrentPetDisplay { if (!config.display) return - config.displayPos.renderString(PetAPI.currentPet?.rawPetName, posLabel = "Current Pet") + config.displayPos.renderString(CurrentPetAPI.currentPet?.rawPetName, posLabel = "Current Pet") } @SubscribeEvent diff --git a/src/main/java/at/hannibal2/skyhanni/utils/ItemUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/ItemUtils.kt index 0da0f8ded5ca..bc76ab798f3c 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/ItemUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/ItemUtils.kt @@ -1,8 +1,6 @@ package at.hannibal2.skyhanni.utils import at.hannibal2.skyhanni.data.NotificationManager -import at.hannibal2.skyhanni.data.PetAPI -import at.hannibal2.skyhanni.data.PetAPI.petItemNamePattern import at.hannibal2.skyhanni.data.SkyHanniNotification import at.hannibal2.skyhanni.events.DebugDataCollectEvent import at.hannibal2.skyhanni.features.misc.items.EstimatedItemValueCalculator.getAttributeName @@ -13,6 +11,8 @@ import at.hannibal2.skyhanni.utils.ItemPriceUtils.getPrice import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.toInternalName import at.hannibal2.skyhanni.utils.NEUItems.getItemStackOrNull import at.hannibal2.skyhanni.utils.NumberUtil.formatInt +import at.hannibal2.skyhanni.utils.PetUtils.getCleanName +import at.hannibal2.skyhanni.utils.PetUtils.petItemNamePattern import at.hannibal2.skyhanni.utils.PrimitiveIngredient.Companion.toPrimitiveItemStacks import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.RegexUtils.matches @@ -521,7 +521,7 @@ object ItemUtils { } // hide pet level - PetAPI.getCleanName(name)?.let { + getCleanName(name)?.let { return "$it Pet" } return name diff --git a/src/main/java/at/hannibal2/skyhanni/utils/PetUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/PetUtils.kt new file mode 100644 index 000000000000..80e6d1ec9484 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/utils/PetUtils.kt @@ -0,0 +1,191 @@ +package at.hannibal2.skyhanni.utils + +import at.hannibal2.skyhanni.api.CurrentPetAPI +import at.hannibal2.skyhanni.api.event.HandleEvent +import at.hannibal2.skyhanni.config.commands.CommandCategory +import at.hannibal2.skyhanni.config.commands.CommandRegistrationEvent +import at.hannibal2.skyhanni.data.jsonobjects.repo.NEUPetData +import at.hannibal2.skyhanni.data.jsonobjects.repo.NEUPetsJson +import at.hannibal2.skyhanni.events.NeuRepositoryReloadEvent +import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule +import at.hannibal2.skyhanni.test.command.ErrorManager +import at.hannibal2.skyhanni.utils.ItemUtils.getLore +import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.toInternalName +import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators +import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher +import at.hannibal2.skyhanni.utils.RegexUtils.matches +import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern +import net.minecraft.item.ItemStack + +@SkyHanniModule +object PetUtils { + private val patternGroup = RepoPattern.group("misc.pet") + private const val FORGE_BACK_SLOT = 48 + + private var baseXpLevelReqs: List = listOf() + private var customXpLevelReqs: Map? = null + + // + /** + * REGEX-TEST: §e⭐ §7[Lvl 200] §6Golden Dragon§d ✦ + * REGEX-TEST: ⭐ [Lvl 100] Black Cat ✦ + */ + val petItemNamePattern by CurrentPetAPI.patternGroup.pattern( + "item.name", + "(?(?:§.)*⭐ )?(?:§.)*\\[Lvl (?\\d+)] (?.*)", + ) + + /** + * REGEX-TEST: Pets (1/3) + * REGEX-TEST: Pets + * REGEX-TEST: Pets (1/4) + * REGEX-TEST: Pets (1/2) + */ + private val petMenuPattern by patternGroup.pattern( + "menu.title", + "Pets(?: \\(\\d+/\\d+\\) )?", + ) + + /** + * REGEX-TEST: §7[Lvl 1➡200] §6Golden Dragon + * REGEX-TEST: §7[Lvl {LVL}] §6Golden Dragon + */ + private val neuRepoPetItemNamePattern by CurrentPetAPI.patternGroup.pattern( + "item.name.neu.format", + "(?:§f§f)?§7\\[Lvl (?:1➡(?:100|200)|\\{LVL})] (?.*)", + ) + + /** + * REGEX-TEST: §7To Select Process (Slot #2) + * REGEX-TEST: §7To Select Process (Slot #4) + * REGEX-TEST: §7To Select Process (Slot #7) + * REGEX-TEST: §7To Select Process + */ + private val forgeBackMenuPattern by CurrentPetAPI.patternGroup.pattern( + "menu.forge.goback", + "§7To Select Process(?: \\(Slot #\\d\\))?", + ) + // + + // + fun isPetMenu(inventoryTitle: String, inventoryItems: Map): Boolean { + if (!petMenuPattern.matches(inventoryTitle)) return false + + // Otherwise make sure they're not in the Forge menu looking at pets + return inventoryItems[FORGE_BACK_SLOT]?.getLore().orEmpty().none { + forgeBackMenuPattern.matches(it) + } + } + + fun getCleanName(nameWithLevel: String): String? { + petItemNamePattern.matchMatcher(nameWithLevel) { + return group("name") + } + neuRepoPetItemNamePattern.matchMatcher(nameWithLevel) { + return group("name") + } + + return null + } + + fun getFakePetLine(level: Int, rarity: LorenzRarity, petName: String, skin: String? = null): String { + return "§r§7[Lvl $level] §r${rarity.chatColorCode}$petName§r${skin.orEmpty()}" + } + + fun rarityByColorGroup(color: String): LorenzRarity = LorenzRarity.getByColorCode(color[0]) + ?: ErrorManager.skyHanniError( + "Unknown rarity", + Pair("rarity", color), + ) + + private fun levelToXPCommand(input: Array) { + if (input.size < 3) { + ChatUtils.userError("Usage: /shcalcpetxp ") + return + } + + val level = input[0].toIntOrNull() + if (level == null) { + ChatUtils.userError("Invalid level '${input[0]}'.") + return + } + val rarity = LorenzRarity.getByName(input[1]) + if (rarity == null) { + ChatUtils.userError("Invalid rarity '${input[1]}'.") + return + } + + val petName = input.slice(2..= level + } + + private fun getCustomLeveling(petName: String): List { + return customXpLevelReqs?.get(petName)?.petLevels.orEmpty() + } + + private fun getRarityOffset(rarity: LorenzRarity, petName: String): Int? { + val petsData = customXpLevelReqs ?: run { + ErrorManager.skyHanniError("NEUPetsData is null") + } + + return if (petName in petsData.keys) { + val petData = petsData[petName] + petData?.rarityOffset?.get(rarity) + } else { + when (rarity) { + LorenzRarity.COMMON -> 0 + LorenzRarity.UNCOMMON -> 6 + LorenzRarity.RARE -> 11 + LorenzRarity.EPIC -> 16 + LorenzRarity.LEGENDARY -> 20 + LorenzRarity.MYTHIC -> 20 + else -> { + ChatUtils.userError("Invalid Rarity \"${rarity.name}\"") + null + } + } + } + } + // + + @HandleEvent + fun onNEURepoReload(event: NeuRepositoryReloadEvent) { + val data = event.getConstant("pets") + baseXpLevelReqs = data.petLevels + customXpLevelReqs = data.customPetLeveling + } + + @HandleEvent + fun onCommandRegistration(event: CommandRegistrationEvent) { + event.register("shpetxp") { + description = "Calculates the pet xp from a given level and rarity." + category = CommandCategory.DEVELOPER_TEST + callback { levelToXPCommand(it) } + } + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/utils/SkyBlockItemModifierUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/SkyBlockItemModifierUtils.kt index 0775fb188525..26c59549fdae 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/SkyBlockItemModifierUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/SkyBlockItemModifierUtils.kt @@ -1,13 +1,13 @@ package at.hannibal2.skyhanni.utils import at.hannibal2.skyhanni.config.ConfigManager -import at.hannibal2.skyhanni.data.PetAPI.petItemNamePattern import at.hannibal2.skyhanni.mixins.hooks.ItemStackCachedData import at.hannibal2.skyhanni.utils.ItemUtils.extraAttributes 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.NEUInternalName.Companion.toInternalName +import at.hannibal2.skyhanni.utils.PetUtils.petItemNamePattern import at.hannibal2.skyhanni.utils.RegexUtils.matchGroup import at.hannibal2.skyhanni.utils.StringUtils.removeColor import com.google.gson.JsonObject From affe69119866ded69803a1086f6fcd976b37d9ac Mon Sep 17 00:00:00 2001 From: David Cole <40234707+DavidArthurCole@users.noreply.github.com> Date: Tue, 10 Dec 2024 02:35:27 -0500 Subject: [PATCH 55/91] Bump storage name --- src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt | 4 ++-- .../skyhanni/config/storage/ProfileSpecificStorage.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt b/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt index f09e13ac1142..c39b4a31a42c 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt @@ -49,9 +49,9 @@ object CurrentPetAPI { private var inPetMenu = false var currentPet: PetData? - get() = ProfileStorageData.profileSpecific?.currentPet?.takeIf { it.isInitialized() } + get() = ProfileStorageData.profileSpecific?.currentPetData?.takeIf { it.isInitialized() } set(value) { - ProfileStorageData.profileSpecific?.currentPet = value + ProfileStorageData.profileSpecific?.currentPetData = value } fun isCurrentPet(petName: String): Boolean = currentPet?.cleanName?.contains(petName) ?: false diff --git a/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java b/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java index 37f35d6da33a..23114caa8398 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java +++ b/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java @@ -75,7 +75,7 @@ private static Duration DurationZero() { } @Expose - public PetData currentPet = new PetData(); + public PetData currentPetData = new PetData(); @Expose public ExperimentationStorage experimentation = new ExperimentationStorage(); From 6a996212883c9fcf06d1d162b7873d233279416b Mon Sep 17 00:00:00 2001 From: David Cole <40234707+DavidArthurCole@users.noreply.github.com> Date: Tue, 10 Dec 2024 02:42:41 -0500 Subject: [PATCH 56/91] improvements --- src/main/java/at/hannibal2/skyhanni/data/PetData.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetData.kt b/src/main/java/at/hannibal2/skyhanni/data/PetData.kt index 8529ca914945..cd844c9df637 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetData.kt @@ -12,7 +12,7 @@ import at.hannibal2.skyhanni.utils.PetUtils.rarityByColorGroup import at.hannibal2.skyhanni.utils.RegexUtils.anyMatches import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.SkyBlockItemModifierUtils.getExtraAttributes -import at.hannibal2.skyhanni.utils.StringUtils.convertToUnformatted +import at.hannibal2.skyhanni.utils.StringUtils.removeColor import com.google.gson.Gson import net.minecraft.item.ItemStack @@ -127,7 +127,7 @@ data class PetData( ) } - fun parsePetName(displayName: String): PetData? { + private fun parsePetName(displayName: String): PetData? { petNameMenuPattern.matchMatcher(displayName) { val name = group("name").orEmpty() val rarity = rarityByColorGroup(group("rarity")) @@ -148,7 +148,7 @@ data class PetData( } fun petNameToInternalName(name: String, rarity: LorenzRarity): NEUInternalName = - "${name.convertToUnformatted()}${rarity.id}".toInternalName() + "${name.removeColor()}${rarity.id}".toInternalName() fun parsePetAsItem(item: ItemStack): PetData? { val lore = item.getLore() From ecf71f84c699a00b1e06f3b054344ff1e7221169 Mon Sep 17 00:00:00 2001 From: David Cole <40234707+DavidArthurCole@users.noreply.github.com> Date: Tue, 10 Dec 2024 19:09:48 -0500 Subject: [PATCH 57/91] More work --- .../hannibal2/skyhanni/api/CurrentPetAPI.kt | 70 +++++---- .../config/features/misc/pets/PetConfig.java | 5 + .../at/hannibal2/skyhanni/data/PetData.kt | 136 ++++++------------ .../jsonobjects/repo/neu/NeuPetSkinJson.kt | 39 +++++ .../ExperimentationTableAPI.kt | 14 +- .../experimentationtable/GuardianReminder.kt | 4 +- .../features/misc/discordrpc/DiscordStatus.kt | 2 +- .../features/misc/pets/CurrentPetDisplay.kt | 21 ++- .../at/hannibal2/skyhanni/utils/PetUtils.kt | 75 +++++++++- 9 files changed, 222 insertions(+), 144 deletions(-) create mode 100644 src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/neu/NeuPetSkinJson.kt diff --git a/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt b/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt index c39b4a31a42c..149645291b62 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt @@ -25,9 +25,8 @@ import at.hannibal2.skyhanni.utils.ItemUtils.getLore import at.hannibal2.skyhanni.utils.LorenzRarity import at.hannibal2.skyhanni.utils.NEUInternalName import at.hannibal2.skyhanni.utils.NumberUtil.formatDouble -import at.hannibal2.skyhanni.utils.PetUtils.getFakePetLine import at.hannibal2.skyhanni.utils.PetUtils.isPetMenu -import at.hannibal2.skyhanni.utils.PetUtils.levelToXP +import at.hannibal2.skyhanni.utils.PetUtils.levelToXp import at.hannibal2.skyhanni.utils.PetUtils.rarityByColorGroup import at.hannibal2.skyhanni.utils.RegexUtils.firstMatchGroup import at.hannibal2.skyhanni.utils.RegexUtils.firstMatcher @@ -47,6 +46,7 @@ object CurrentPetAPI { val patternGroup = RepoPattern.group("misc.pet") private var inPetMenu = false + private var lastPetLine: String? = null var currentPet: PetData? get() = ProfileStorageData.profileSpecific?.currentPetData?.takeIf { it.isInitialized() } @@ -160,7 +160,7 @@ object CurrentPetAPI { * REGEX-TEST: §aYou despawned your §r§6Golden Dragon§r§a! * REGEX-TEST: §aYou despawned your §r§6Silverfish§r§5 ✦§r§a! */ - private val chatDespawnPattern by CurrentPetAPI.patternGroup.pattern( + private val chatDespawnPattern by patternGroup.pattern( "chat.despawn", "§aYou despawned your §r.*§r§a!", ) @@ -169,10 +169,28 @@ object CurrentPetAPI { * REGEX-TEST: §aYou summoned your §r§6Silverfish§r§5 ✦§r§a! * REGEX-TEST: §aYou summoned your §r§6Golden Dragon§r§a! */ - private val chatSpawnPattern by CurrentPetAPI.patternGroup.pattern( + private val chatSpawnPattern by patternGroup.pattern( "chat.spawn", "§aYou summoned your §r(?.*)§r§a!" ) + + /** + * REGEX-TEST: §e⭐ §7[Lvl 100] §6Ender Dragon + * REGEX-TEST: §e⭐ §7[Lvl 100] §dBlack Cat§d ✦ + * REGEX-TEST: §7[Lvl 100] §6Mole + */ + val petNameMenuPattern by patternGroup.pattern( + "menu.pet.name", + "^(?:§e(?⭐) )?(?:§.)*\\[Lvl (?\\d+)] §(?.)(?[\\w ]+)(?§. ✦)?\$", + ) + + /** + * REGEX-TEST: §7§cClick to despawn! + */ + val petDespawnMenuPattern by patternGroup.pattern( + "menu.pet.despawn", + "§7§cClick to despawn!", + ) // // @@ -199,20 +217,20 @@ object CurrentPetAPI { // // - private fun handleWidgetPetLine(line: String, newPetLine: String): PetData? = petWidgetPattern.matchMatcher(line) { + private fun handleWidgetPetLine(line: String): PetData? = petWidgetPattern.matchMatcher(line) { val rarity = rarityByColorGroup(group("rarity")) val petName = groupOrNull("name").orEmpty() val level = groupOrNull("level")?.toInt() ?: 0 - val xp = levelToXP(level, rarity, petName) ?: return null + val xp = levelToXp(level, rarity, petName) ?: return null return PetData( - petNameToInternalName(petName, rarity), - petName, - rarity, - null, - level, - xp, - newPetLine, + petItem = petNameToInternalName(petName, rarity), + skinItem = null, + heldItem = null, + cleanName = petName, + rarity = rarity, + level = level, + xp = xp, ) } @@ -253,12 +271,11 @@ object CurrentPetAPI { val skin = groupOrNull("skin").takeIf { it != null } return PetData( - internalName = petNameToInternalName(petName, rarity), + petItem = petNameToInternalName(petName, rarity), cleanName = petName, rarity = rarity, level = level, - xp = levelToXP(level, rarity, petName) ?: 0.0, - rawPetName = getFakePetLine(level, rarity, petName, skin), + xp = levelToXp(level, rarity, petName) ?: 0.0, ) } @@ -287,7 +304,7 @@ object CurrentPetAPI { // Only have overflow if `next` group is absent if (inventorySelectedXpPattern.firstMatchGroup(lore, "next") != null) return 0.0 val (level, rarity, petName) = extractSelectedPetData(lore) ?: return null - val maxXpNeeded = levelToXP(level, rarity, petName) + val maxXpNeeded = levelToXp(level, rarity, petName) val currentXp = inventorySelectedXpPattern.firstMatchGroup(lore, "current")?.formatDouble() ?: 0.0 return maxXpNeeded?.minus(currentXp) ?: 0.0 } @@ -296,13 +313,12 @@ object CurrentPetAPI { val (level, rarity, petName) = extractSelectedPetData(lore) ?: return null val partialXp = inventorySelectedXpPattern.firstMatchGroup(lore, "current")?.formatDouble() ?: 0.0 val nextExists = inventorySelectedXpPattern.firstMatchGroup(lore, "next") != null - val totalXp = partialXp + if (nextExists) (levelToXP(level, rarity, petName) ?: return null) else 0.0 + val totalXp = partialXp + if (nextExists) (levelToXp(level, rarity, petName) ?: return null) else 0.0 return PetData( - internalName = petNameToInternalName(petName, rarity), + petItem = petNameToInternalName(petName, rarity), cleanName = petName, rarity = rarity, - petItem = null, - rawPetName = getFakePetLine(level, rarity, petName), + heldItem = null, level = level, xp = totalXp, ) @@ -315,13 +331,14 @@ object CurrentPetAPI { if (!event.isWidget(TabWidget.PET)) return val newPetLine = petWidgetPattern.firstMatches(event.lines)?.trim() ?: return - if (newPetLine == currentPet?.rawPetName) return + if (newPetLine == lastPetLine) return + lastPetLine = newPetLine val (petData, overflowXP) = parsePetData( event.lines, { handleWidgetStringLine(it) }, { handleWidgetXPLine(it) }, - { handleWidgetPetLine(it, newPetLine) } + { handleWidgetPetLine(it) } ) ?: return updatePet(petData.copy(xp = petData.xp?.plus(overflowXP))) @@ -340,7 +357,7 @@ object CurrentPetAPI { Pair("message", event.message), Pair("item", group("petItem")), ) - val newPet = currentPet?.copy(petItem = item) ?: return + val newPet = currentPet?.copy(heldItem = item) ?: return updatePet(newPet) } } @@ -383,12 +400,11 @@ object CurrentPetAPI { return } event.addIrrelevant { - add("petName: '${currentPet?.internalName ?: ""}'") + add("petName: '${currentPet?.petItem ?: ""}'") add("petRarity: '${currentPet?.rarity?.rawName.orEmpty()}'") - add("petItem: '${currentPet?.petItem ?: ""}'") + add("petItem: '${currentPet?.heldItem ?: ""}'") add("petLevel: '${currentPet?.level ?: 0}'") add("petXP: '${currentPet?.xp ?: 0.0}'") - add("rawPetLine: '${currentPet?.rawPetName.orEmpty()}'") } } // diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/misc/pets/PetConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/misc/pets/PetConfig.java index 02c2b2ed45fd..cae9e1ebd885 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/misc/pets/PetConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/misc/pets/PetConfig.java @@ -21,6 +21,11 @@ public class PetConfig { @FeatureToggle public boolean display = false; + @Expose + @ConfigOption(name = "Rarity Circle", desc = "Display a circle around the pet icon based on rarity.") + @ConfigEditorBoolean + public boolean rarityCircle = true; + @Expose @ConfigLink(owner = PetConfig.class, field = "display") public Position displayPos = new Position(-330, -15, false, true); diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetData.kt b/src/main/java/at/hannibal2/skyhanni/data/PetData.kt index cd844c9df637..f70138998277 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetData.kt @@ -1,73 +1,56 @@ package at.hannibal2.skyhanni.data -import at.hannibal2.skyhanni.api.CurrentPetAPI +import at.hannibal2.skyhanni.api.CurrentPetAPI.petDespawnMenuPattern import at.hannibal2.skyhanni.test.command.ErrorManager import at.hannibal2.skyhanni.utils.ItemUtils.getLore import at.hannibal2.skyhanni.utils.ItemUtils.itemName import at.hannibal2.skyhanni.utils.LorenzRarity import at.hannibal2.skyhanni.utils.NEUInternalName -import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.asInternalName import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.toInternalName -import at.hannibal2.skyhanni.utils.PetUtils.rarityByColorGroup +import at.hannibal2.skyhanni.utils.PetUtils.xpToLevel import at.hannibal2.skyhanni.utils.RegexUtils.anyMatches -import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.SkyBlockItemModifierUtils.getExtraAttributes +import at.hannibal2.skyhanni.utils.StringUtils.firstLetterUppercase import at.hannibal2.skyhanni.utils.StringUtils.removeColor import com.google.gson.Gson import net.minecraft.item.ItemStack -// -/** - * REGEX-TEST: §e⭐ §7[Lvl 100] §6Ender Dragon - * REGEX-TEST: §e⭐ §7[Lvl 100] §dBlack Cat§d ✦ - * REGEX-TEST: §7[Lvl 100] §6Mole - */ -private val petNameMenuPattern by CurrentPetAPI.patternGroup.pattern( - "menu.pet.name", - "^(?:§e(?⭐) )?(?:§.)*\\[Lvl (?\\d+)] §(?.)(?[\\w ]+)(?§. ✦)?\$", -) - -/** - * REGEX-TEST: §7§cClick to despawn! - */ -private val petDespawnMenuPattern by CurrentPetAPI.patternGroup.pattern( - "menu.pet.despawn", - "§7§cClick to despawn!", -) -// - data class PetData( - val internalName: NEUInternalName? = null, - val cleanName: String? = null, - val rarity: LorenzRarity? = null, - val petItem: NEUInternalName? = null, - val level: Int? = null, - val xp: Double? = null, - val rawPetName: String? = null, + val petItem: NEUInternalName? = null, // The internal name of the pet, e.g., `RABBIT;5` + val skinItem: NEUInternalName? = null, // The skin of the pet, e.g., `PET_SKIN_WOLF_DOGE` + val heldItem: NEUInternalName? = null, // The held item of the pet, e.g., `PET_ITEM_COMBAT_SKILL_BOOST_EPIC` + val cleanName: String? = null, // The clean name of the pet, e.g., `Rabbit` + val rarity: LorenzRarity? = null, // The rarity of the pet, e.g., `COMMON` + val level: Int? = null, // The current level of the pet as an integer, e.g., `100` + val xp: Double? = null, // The total XP of the pet as a double, e.g., `0.0` ) { - val displayName = internalName?.itemName + val displayName = petItem?.itemName + + // Please god only use this for UI, not for comparisons + private val skinName = skinItem?.itemName?.takeIf { it.isNotEmpty() }?.let { " §r$it" }.orEmpty() + val userFriendlyName = if (this.isInitialized()) "§r§7[Lvl $level] §r${rarity?.chatColorCode}$cleanName$skinName" else "" override fun equals(other: Any?): Boolean { if (other !is PetData) return false - return this.internalName == other.internalName && + return this.petItem == other.petItem && + this.skinItem == other.skinItem && + this.heldItem == other.heldItem && this.cleanName == other.cleanName && this.rarity == other.rarity && - this.petItem == other.petItem && this.level == other.level && - this.rawPetName == other.rawPetName + this.xp == other.xp } override fun hashCode(): Int { var result = cleanName.hashCode() result = 31 * result + rarity.hashCode() - result = 31 * result + (petItem?.hashCode() ?: 0) + result = 31 * result + (heldItem?.hashCode() ?: 0) result = 31 * result + (level ?: 0) - result = 31 * result + rawPetName.hashCode() return result } fun isInitialized(): Boolean { - return internalName != null && cleanName != null && rarity != null && level != null && xp != null && rawPetName != null + return petItem != null && cleanName != null && rarity != null && level != null && xp != null } companion object { @@ -97,79 +80,52 @@ data class PetData( val data = petHandlerList(lines) ?: return null val petData = PetData( - internalName = data.internalName, + petItem = data.petItem, cleanName = data.cleanName, rarity = data.rarity, - petItem = petItem, + heldItem = petItem, level = data.level, xp = data.xp, - rawPetName = data.rawPetName, ) return petData to overflowXP } - private fun parsePetNBT(item: ItemStack): PetData { + private fun parseFromItem(item: ItemStack): PetData { val petInfo = Gson().fromJson(item.getExtraAttributes()?.getString("petInfo"), PetNBT::class.java) + val petName = petInfo.type + val petRarity = LorenzRarity.getByName(petInfo.tier) ?: ErrorManager.skyHanniError( + "Couldn't parse pet rarity.", + Pair("petNBT", petInfo), + Pair("rarity", petInfo.tier), + ) + val internalName = petNameToInternalName(petName, petRarity) + val level = xpToLevel(petInfo.exp, internalName) ?: 0 + return PetData( - internalName = NEUInternalName.NONE, - cleanName = "", - level = 0, - rarity = LorenzRarity.getByName(petInfo.tier) ?: ErrorManager.skyHanniError( - "Couldn't parse pet rarity.", - Pair("petNBT", petInfo), - Pair("rarity", petInfo.tier), - ), - petItem = petInfo.heldItem?.asInternalName(), + petItem = internalName, + cleanName = petName.firstLetterUppercase(), + level = level, + rarity = petRarity, + heldItem = petInfo.heldItem?.toInternalName(), xp = petInfo.exp, - rawPetName = "", ) } - private fun parsePetName(displayName: String): PetData? { - petNameMenuPattern.matchMatcher(displayName) { - val name = group("name").orEmpty() - val rarity = rarityByColorGroup(group("rarity")) - val level = group("level").toInt() - val skin = group("skin").orEmpty() - - return PetData( - internalName = petNameToInternalName(name, rarity), - cleanName = name, - rarity = rarity, - petItem = null, - level = level, - xp = 0.0, - rawPetName = skin, - ) - } - return null - } - fun petNameToInternalName(name: String, rarity: LorenzRarity): NEUInternalName = - "${name.removeColor()}${rarity.id}".toInternalName() + "${name.removeColor()};${rarity.id}".toInternalName() + + fun internalNameToPetName(internalName: NEUInternalName): Pair? { + val (name, rarityStr) = internalName.asString().split(";") + val rarity = LorenzRarity.getById(rarityStr.toInt()) ?: return null + return Pair(name, rarity) + } fun parsePetAsItem(item: ItemStack): PetData? { val lore = item.getLore() if (petDespawnMenuPattern.anyMatches(lore)) return null - return getPetDataFromItem(item) - } - - @Suppress("DestructuringDeclarationWithTooManyEntries") - private fun getPetDataFromItem(item: ItemStack): PetData? { - val (_, _, rarity, petItem, _, petXP, _) = parsePetNBT(item) - val (internalName, name, _, _, level, _, skin) = parsePetName(item.displayName) ?: return null - - return PetData( - internalName, - name, - rarity, - petItem, - level, - petXP, - "§r§7[Lvl $level] §r${rarity?.chatColorCode}$name${if (skin != "") "§r$skin" else ""}", - ) + return parseFromItem(item) } // } diff --git a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/neu/NeuPetSkinJson.kt b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/neu/NeuPetSkinJson.kt new file mode 100644 index 000000000000..bc9d107c882a --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/neu/NeuPetSkinJson.kt @@ -0,0 +1,39 @@ +package at.hannibal2.skyhanni.data.jsonobjects.repo.neu + +import com.google.gson.annotations.Expose +import com.google.gson.annotations.SerializedName +import net.minecraft.nbt.CompressedStreamTools +import net.minecraft.nbt.NBTTagCompound +import java.io.ByteArrayInputStream +import java.util.Base64 + +data class NeuPetSkinJson( + @Expose @SerializedName("itemid") val itemId: String, + @Expose @SerializedName("displayname") val displayName: String, + @Expose @SerializedName("nbttag") val nbtTagString: String, + @Expose val damage: Int, + @Expose val lore: List, + @Expose @SerializedName("internalname") val internalName: String, + @Expose @SerializedName("crafttext") val craftText: String, + @Expose @SerializedName("clickcommand") val clickCommand: String, + @Expose @SerializedName("modver") val modVersion: String, + @Expose val infoType: String, + @Expose val info: List +) { + /** + * Parses the NBT tag from the JSON into an NBTTagCompound. + * @return Parsed NBTTagCompound object. + * @throws IllegalArgumentException if the NBT parsing fails. + */ + private fun getParsedNBT(): NBTTagCompound { + return try { + val decodedBytes = Base64.getDecoder().decode(nbtTagString.toByteArray(Charsets.UTF_8)) + val inputStream = ByteArrayInputStream(decodedBytes) + CompressedStreamTools.readCompressed(inputStream) + } catch (e: Exception) { + throw IllegalArgumentException("Failed to parse NBT tag: $nbtTagString", e) + } + } + + val nbtTag get() = getParsedNBT() +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentationTableAPI.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentationTableAPI.kt index 77b901517589..4a085b59fadd 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentationTableAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentationTableAPI.kt @@ -23,7 +23,7 @@ object ExperimentationTableAPI { private val storage get() = ProfileStorageData.profileSpecific?.experimentation - val inTable get() = inventoriesPattern.matches(openInventoryName()) + private val inTable get() = inventoriesPattern.matches(openInventoryName()) fun inDistanceToTable(vec: LorenzVec, max: Double): Boolean = storage?.tablePos?.let { it.distance(vec) <= max } ?: false @@ -163,15 +163,5 @@ object ExperimentationTableAPI { "§9(?.*)", ) - /** - * REGEX-TEST: §dGuardian - * REGEX-TEST: §9Guardian§e - * REGEX-TEST: Guardian - */ - private val petNamePattern by patternGroup.pattern( - "guardianpet", - "(?:§[956d])?Guardian.*", - ) - - fun hasGuardianPet(): Boolean = petNamePattern.matches(CurrentPetAPI.currentPet?.rawPetName) + fun guardianPetActive(): Boolean = CurrentPetAPI.currentPet?.cleanName == "Guardian" } diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/GuardianReminder.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/GuardianReminder.kt index 0d683072cea8..fb2b5ddae249 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/GuardianReminder.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/GuardianReminder.kt @@ -40,7 +40,7 @@ object GuardianReminder { } private fun warn() { - if (ExperimentationTableAPI.hasGuardianPet()) return + if (ExperimentationTableAPI.guardianPetActive()) return ChatUtils.clickToActionOrDisable( "Use a §9§lGuardian Pet §efor more Exp in the Experimentation Table.", @@ -55,7 +55,7 @@ object GuardianReminder { if (!isEnabled()) return if (InventoryUtils.openInventoryName() != "Experimentation Table") return if (lastInventoryOpen.passedSince() > 2.seconds) return - if (ExperimentationTableAPI.hasGuardianPet()) return + if (ExperimentationTableAPI.guardianPetActive()) return val gui = Minecraft.getMinecraft().currentScreen as? GuiContainer ?: return sendTitle(gui.width, gui.height) diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt index 4fd2cd698adc..61a00bb598e4 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt @@ -71,7 +71,7 @@ private fun getCropMilestoneDisplay(): String { return "${crop.cropName}: $text" } -private fun getPetDisplay(): String = CurrentPetAPI.currentPet?.rawPetName ?: "No pet equipped" +private fun getPetDisplay(): String = CurrentPetAPI.currentPet?.userFriendlyName ?: "No pet equipped" enum class DiscordStatus(private val displayMessageSupplier: (() -> String?)) { diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt index 386d95274282..3df57cc13587 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt @@ -7,7 +7,9 @@ import at.hannibal2.skyhanni.events.GuiRenderEvent import at.hannibal2.skyhanni.features.rift.RiftAPI import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.LorenzUtils -import at.hannibal2.skyhanni.utils.RenderUtils.renderString +import at.hannibal2.skyhanni.utils.NEUItems.getItemStack +import at.hannibal2.skyhanni.utils.RenderUtils.renderRenderable +import at.hannibal2.skyhanni.utils.renderables.Renderable import net.minecraftforge.fml.common.eventhandler.SubscribeEvent @SkyHanniModule @@ -17,12 +19,21 @@ object CurrentPetDisplay { @SubscribeEvent fun onRenderOverlay(event: GuiRenderEvent.GuiOverlayRenderEvent) { - if (!LorenzUtils.inSkyBlock) return - if (RiftAPI.inRift()) return + if (!LorenzUtils.inSkyBlock || RiftAPI.inRift() || !config.display) return + val currentPet = CurrentPetAPI.currentPet ?: return - if (!config.display) return + val petItemStack = currentPet.petItem?.getItemStack() ?: return + val skinItem = currentPet.skinItem?.getItemStack() + // When we have a skin item, we want to display that instead of the pet item + val displayStack = skinItem ?: petItemStack - config.displayPos.renderString(CurrentPetAPI.currentPet?.rawPetName, posLabel = "Current Pet") + config.displayPos.renderRenderable( + Renderable.itemStack( + displayStack, + 1.0, + ), + posLabel = "Current Pet" + ) } @SubscribeEvent diff --git a/src/main/java/at/hannibal2/skyhanni/utils/PetUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/PetUtils.kt index 80e6d1ec9484..a7216c430276 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/PetUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/PetUtils.kt @@ -4,23 +4,29 @@ import at.hannibal2.skyhanni.api.CurrentPetAPI import at.hannibal2.skyhanni.api.event.HandleEvent import at.hannibal2.skyhanni.config.commands.CommandCategory import at.hannibal2.skyhanni.config.commands.CommandRegistrationEvent +import at.hannibal2.skyhanni.data.PetData.Companion.internalNameToPetName import at.hannibal2.skyhanni.data.jsonobjects.repo.NEUPetData import at.hannibal2.skyhanni.data.jsonobjects.repo.NEUPetsJson +import at.hannibal2.skyhanni.data.jsonobjects.repo.neu.NeuPetSkinJson import at.hannibal2.skyhanni.events.NeuRepositoryReloadEvent import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.test.command.ErrorManager import at.hannibal2.skyhanni.utils.ItemUtils.getLore import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.toInternalName import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators +import at.hannibal2.skyhanni.utils.RegexUtils.groupOrNull import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.RegexUtils.matches import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern +import com.google.gson.Gson import net.minecraft.item.ItemStack @SkyHanniModule object PetUtils { private val patternGroup = RepoPattern.group("misc.pet") private const val FORGE_BACK_SLOT = 48 + // Map of Pet Name to a Map of Skin Name to NeuPetSkinJson + val petSkins = mutableMapOf>() private var baseXpLevelReqs: List = listOf() private var customXpLevelReqs: Map? = null @@ -65,6 +71,24 @@ object PetUtils { "menu.forge.goback", "§7To Select Process(?: \\(Slot #\\d\\))?", ) + + /** + * REGEX-TEST: PET_SKIN_ENDERMAN + * REGEX-TEST: PET_SKIN_PARROT_TOUCAN + * REGEX-TEST: PET_SKIN_PHEONIX_FLAMINGO + * REGEX-TEST: PET_SKIN_PHOENIX_ICE + * REGEX-TEST: PET_SKIN_PIGMAN_LUNAR_PIG + * REGEX-TEST: PET_SKIN_RABBIT + * REGEX-TEST: PET_SKIN_RABBIT_AQUAMARINE + * REGEX-TEST: PET_SKIN_RABBIT_LUNAR + * REGEX-TEST: PET_SKIN_RABBIT_LUNAR_BABY + * REGEX-TEST: PET_SKIN_RABBIT_PLUSHIE + * REGEX-TEST: PET_SKIN_RABBIT_ROSE + */ + private val petSkinNamePattern by CurrentPetAPI.patternGroup.pattern( + "neu.pet", + "PET_SKIN_(?[A-Z])_?(?[A-Z_]+)?" + ) // // @@ -88,10 +112,6 @@ object PetUtils { return null } - fun getFakePetLine(level: Int, rarity: LorenzRarity, petName: String, skin: String? = null): String { - return "§r§7[Lvl $level] §r${rarity.chatColorCode}$petName§r${skin.orEmpty()}" - } - fun rarityByColorGroup(color: String): LorenzRarity = LorenzRarity.getByColorCode(color[0]) ?: ErrorManager.skyHanniError( "Unknown rarity", @@ -116,7 +136,7 @@ object PetUtils { } val petName = input.slice(2..= xpReq) { + xp -= xpReq + level++ + } else { + break + } + } + + return level + } + private fun isValidLevel(level: Int, petName: String): Boolean { val petsData = customXpLevelReqs ?: run { ErrorManager.skyHanniError("NEUPetsData is null") @@ -174,10 +222,23 @@ object PetUtils { // @HandleEvent - fun onNEURepoReload(event: NeuRepositoryReloadEvent) { + fun onNeuRepoReload(event: NeuRepositoryReloadEvent) { val data = event.getConstant("pets") baseXpLevelReqs = data.petLevels customXpLevelReqs = data.customPetLeveling + + NEUItems.allNeuRepoItems().forEach { (rawInternalName, jsonObject) -> + petSkinNamePattern.matchMatcher(rawInternalName) { + val petName = group("pet") ?: return@matchMatcher + // Skin name can be empty, see PET_SKIN_ENDERMAN, PET_SKIN_RABBIT, etc. + val skinName = groupOrNull("skin").orEmpty() + + // Use GSON to reflect the JSON into a NeuPetSkinJson object + val petItemData = Gson().fromJson(jsonObject, NeuPetSkinJson::class.java) + + petSkins.getOrPut(petName) { mutableMapOf() }[skinName] = petItemData + } + } } @HandleEvent From 3b97537bd190e334383de727bc4f4376558d27cd Mon Sep 17 00:00:00 2001 From: David Cole <40234707+DavidArthurCole@users.noreply.github.com> Date: Tue, 10 Dec 2024 19:13:22 -0500 Subject: [PATCH 58/91] Detekt --- src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt b/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt index 149645291b62..5f51482ab2ed 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt @@ -268,7 +268,6 @@ object CurrentPetAPI { val level = group("level").toInt() val rarity = rarityByColorGroup(group("rarity")) val petName = group("pet") - val skin = groupOrNull("skin").takeIf { it != null } return PetData( petItem = petNameToInternalName(petName, rarity), From b969988df1d31bb50f8bf6f9f26d1641412ba506 Mon Sep 17 00:00:00 2001 From: Cal Date: Sat, 14 Dec 2024 12:00:54 +1100 Subject: [PATCH 59/91] fix merge --- src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt b/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt index 5f51482ab2ed..ce29f0ebcd7c 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt @@ -391,7 +391,7 @@ object CurrentPetAPI { updatePet(parsePetAsItem(event.item)) } - @SubscribeEvent + @HandleEvent fun onDebug(event: DebugDataCollectEvent) { event.title("PetAPI") if (currentPet?.isInitialized() == false) { From f98f2b51b5c3ca87f3111b3e2e78761b1238df4a Mon Sep 17 00:00:00 2001 From: David Cole <40234707+DavidArthurCole@users.noreply.github.com> Date: Fri, 13 Dec 2024 22:43:32 -0500 Subject: [PATCH 60/91] Rip out new display --- .../at/hannibal2/skyhanni/data/PetData.kt | 18 ++++++++++++++++-- .../features/misc/discordrpc/DiscordStatus.kt | 3 ++- .../features/misc/pets/CurrentPetDisplay.kt | 19 +++---------------- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetData.kt b/src/main/java/at/hannibal2/skyhanni/data/PetData.kt index f70138998277..2b9e28aca96f 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetData.kt @@ -15,20 +15,33 @@ import at.hannibal2.skyhanni.utils.StringUtils.removeColor import com.google.gson.Gson import net.minecraft.item.ItemStack +/** + * TODO: Skins still need to be loaded from the API. + * + */ data class PetData( val petItem: NEUInternalName? = null, // The internal name of the pet, e.g., `RABBIT;5` val skinItem: NEUInternalName? = null, // The skin of the pet, e.g., `PET_SKIN_WOLF_DOGE` val heldItem: NEUInternalName? = null, // The held item of the pet, e.g., `PET_ITEM_COMBAT_SKILL_BOOST_EPIC` val cleanName: String? = null, // The clean name of the pet, e.g., `Rabbit` + val skinSymbol: String? = null, // The symbol of the skin of the pet, e.g., §d ✦ val rarity: LorenzRarity? = null, // The rarity of the pet, e.g., `COMMON` val level: Int? = null, // The current level of the pet as an integer, e.g., `100` val xp: Double? = null, // The total XP of the pet as a double, e.g., `0.0` ) { val displayName = petItem?.itemName + val formattedName = "${rarity?.chatColorCode}$cleanName" + // private val skinName = skinItem?.itemName?.takeIf { it.isNotEmpty() }?.let { " §r$it" }.orEmpty() // Please god only use this for UI, not for comparisons - private val skinName = skinItem?.itemName?.takeIf { it.isNotEmpty() }?.let { " §r$it" }.orEmpty() - val userFriendlyName = if (this.isInitialized()) "§r§7[Lvl $level] §r${rarity?.chatColorCode}$cleanName$skinName" else "" + fun getUserFriendlyName( + includeLevel: Boolean = true, + includeSkin: Boolean = true, + ): String { + val levelString = if (includeLevel) "§7[Lvl $level] §r" else "" + val skinString = if (includeSkin) (skinSymbol.orEmpty()) else "" + return "§r$levelString$formattedName$cleanName$skinString" + } override fun equals(other: Any?): Boolean { if (other !is PetData) return false @@ -36,6 +49,7 @@ data class PetData( this.skinItem == other.skinItem && this.heldItem == other.heldItem && this.cleanName == other.cleanName && + this.skinSymbol == other.skinSymbol && this.rarity == other.rarity && this.level == other.level && this.xp == other.xp diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt index 61a00bb598e4..b898e01fac7f 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt @@ -71,7 +71,8 @@ private fun getCropMilestoneDisplay(): String { return "${crop.cropName}: $text" } -private fun getPetDisplay(): String = CurrentPetAPI.currentPet?.userFriendlyName ?: "No pet equipped" +private fun getPetDisplay(): String = CurrentPetAPI.currentPet?.getUserFriendlyName() + ?: "No pet equipped" enum class DiscordStatus(private val displayMessageSupplier: (() -> String?)) { diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt index bc12c4c5b6c1..e6b46df6f183 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt @@ -8,9 +8,7 @@ import at.hannibal2.skyhanni.events.GuiRenderEvent import at.hannibal2.skyhanni.features.rift.RiftAPI import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.LorenzUtils -import at.hannibal2.skyhanni.utils.NEUItems.getItemStack -import at.hannibal2.skyhanni.utils.RenderUtils.renderRenderable -import at.hannibal2.skyhanni.utils.renderables.Renderable +import at.hannibal2.skyhanni.utils.RenderUtils.renderString import net.minecraftforge.fml.common.eventhandler.SubscribeEvent @SkyHanniModule @@ -21,20 +19,9 @@ object CurrentPetDisplay { @SubscribeEvent fun onRenderOverlay(event: GuiRenderEvent.GuiOverlayRenderEvent) { if (!LorenzUtils.inSkyBlock || RiftAPI.inRift() || !config.display) return - val currentPet = CurrentPetAPI.currentPet ?: return - val petItemStack = currentPet.petItem?.getItemStack() ?: return - val skinItem = currentPet.skinItem?.getItemStack() - // When we have a skin item, we want to display that instead of the pet item - val displayStack = skinItem ?: petItemStack - - config.displayPos.renderRenderable( - Renderable.itemStack( - displayStack, - 1.0, - ), - posLabel = "Current Pet" - ) + val displayName = CurrentPetAPI.currentPet?.getUserFriendlyName(includeLevel = false) ?: return + config.displayPos.renderString(displayName, posLabel = "Current Pet") } @HandleEvent From 482a7ade0a3c71871a2a1ffa27b21d47fef51dd0 Mon Sep 17 00:00:00 2001 From: David Cole <40234707+DavidArthurCole@users.noreply.github.com> Date: Fri, 13 Dec 2024 23:49:27 -0500 Subject: [PATCH 61/91] Merge cleanup --- .../skyhanni/features/misc/discordrpc/DiscordStatus.kt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt index b7f390da1a8c..08e44dc5378e 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordStatus.kt @@ -17,6 +17,7 @@ import at.hannibal2.skyhanni.features.garden.GardenAPI.getCropType import at.hannibal2.skyhanni.features.misc.compacttablist.AdvancedPlayerList import at.hannibal2.skyhanni.features.rift.RiftAPI import at.hannibal2.skyhanni.utils.InventoryUtils +import at.hannibal2.skyhanni.utils.ItemUtils.extraAttributes import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators import at.hannibal2.skyhanni.utils.SimpleTimeMark @@ -26,8 +27,6 @@ import at.hannibal2.skyhanni.utils.StringUtils.removeColor import at.hannibal2.skyhanni.utils.TabListData import at.hannibal2.skyhanni.utils.TimeUtils.format import at.hannibal2.skyhanni.utils.TimeUtils.formatted -import net.minecraft.item.ItemStack -import net.minecraft.nbt.NBTTagCompound import java.util.regex.Pattern import kotlin.time.Duration.Companion.minutes @@ -188,7 +187,7 @@ enum class DiscordStatus(private val displayMessageSupplier: (() -> String?)) { if (fruit == "") profile = lastKnownDisplayStrings[PROFILE] ?: "SkyBlock Level: [$sbLevel]" // profile fruit hasn't loaded in yet else profile += fruit - + lastKnownDisplayStrings[PROFILE] = profile profile }, @@ -268,7 +267,7 @@ enum class DiscordStatus(private val displayMessageSupplier: (() -> String?)) { val itemInHand = InventoryUtils.getItemInHand() val itemName = itemInHand?.displayName?.removeColor().orEmpty() val extraAttributes = itemInHand?.extraAttributes - + fun getProgressPercent(amount: Int, levels: List): String { var percent = "MAXED" for (level in levels.indices) { From da7e2d119b01c91d7556b3e81aacfb2c590bd6ec Mon Sep 17 00:00:00 2001 From: David Cole <40234707+DavidArthurCole@users.noreply.github.com> Date: Sat, 14 Dec 2024 03:09:01 -0500 Subject: [PATCH 62/91] Done --- .live-plugins/event/plugin.kts | 9 +++- .../skyhannimodule/ModuleProcessor.kt | 9 +++- .../skyhanni/api/event/EventListeners.kt | 51 ++++++++++++++----- .../skyhanni/api/event/HandleEvent.kt | 6 +++ .../skyhanni/api/event/SkyHanniEvents.kt | 23 +++++++-- 5 files changed, 77 insertions(+), 21 deletions(-) diff --git a/.live-plugins/event/plugin.kts b/.live-plugins/event/plugin.kts index d012154b881f..4564c8384243 100644 --- a/.live-plugins/event/plugin.kts +++ b/.live-plugins/event/plugin.kts @@ -19,6 +19,7 @@ import org.jetbrains.kotlin.types.typeUtil.supertypes val skyhanniEvent = "at.hannibal2.skyhanni.api.event.SkyHanniEvent" val handleEvent = "HandleEvent" +val eventType = "eventType" registerInspection(HandleEventInspectionKotlin()) @@ -30,6 +31,12 @@ class HandleEventInspectionKotlin : AbstractKotlinInspection() { val hasEventAnnotation = function.annotationEntries.any { it.shortName!!.asString() == handleEvent } val isEvent = function.valueParameters.firstOrNull()?.type()?.supertypes() ?.any { it.fqName?.asString() == skyhanniEvent } ?: false + val hasEventType = function.annotationEntries + .find { it.shortName!!.asString() == handleEvent } + ?.valueArguments + ?.find { it.getArgumentName()?.asName?.asString() == eventType } + ?.getArgumentExpression() + ?.text != null if (isEvent && !hasEventAnnotation && function.valueParameters.size == 1 && function.isPublic) { holder.registerProblem( @@ -37,7 +44,7 @@ class HandleEventInspectionKotlin : AbstractKotlinInspection() { "Event handler function should be annotated with @HandleEvent", HandleEventQuickFix() ) - } else if (!isEvent && hasEventAnnotation) { + } else if (!isEvent && !hasEventType && hasEventAnnotation) { holder.registerProblem( function, "Function should not be annotated with @HandleEvent if it does not take a SkyHanniEvent", diff --git a/annotation-processors/src/main/kotlin/at/hannibal2/skyhanni/skyhannimodule/ModuleProcessor.kt b/annotation-processors/src/main/kotlin/at/hannibal2/skyhanni/skyhannimodule/ModuleProcessor.kt index 402bedef9183..87fbbe7bbf45 100644 --- a/annotation-processors/src/main/kotlin/at/hannibal2/skyhanni/skyhannimodule/ModuleProcessor.kt +++ b/annotation-processors/src/main/kotlin/at/hannibal2/skyhanni/skyhannimodule/ModuleProcessor.kt @@ -68,8 +68,13 @@ class ModuleProcessor(private val codeGenerator: CodeGenerator, private val logg } if (function.annotations.any { it.shortName.asString() == "HandleEvent" }) { - val firstParameter = function.parameters.firstOrNull()?.type?.resolve()!! - if (!skyHanniEvent!!.isAssignableFrom(firstParameter)) { + val firstParameter = function.parameters.firstOrNull()?.type?.resolve() + val handleEventAnnotation = function.annotations.find { it.shortName.asString() == "HandleEvent" } + val eventType = handleEventAnnotation?.arguments?.find { it.name?.asString() == "eventType" }?.value + val isFirstParameterProblem = firstParameter == null && eventType == null + val notAssignable = firstParameter != null && !skyHanniEvent!!.isAssignableFrom(firstParameter) + + if (isFirstParameterProblem || notAssignable) { warnings.add("Function in $className must have an event assignable from $skyHanniEvent because it is annotated with @HandleEvent") } } diff --git a/src/main/java/at/hannibal2/skyhanni/api/event/EventListeners.kt b/src/main/java/at/hannibal2/skyhanni/api/event/EventListeners.kt index 62a22a7d0d64..8f81aa29579a 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/event/EventListeners.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/event/EventListeners.kt @@ -18,18 +18,6 @@ class EventListeners private constructor(val name: String, private val isGeneric ) fun addListener(method: Method, instance: Any, options: HandleEvent) { - require(method.parameterCount == 1) - val generic: Class<*>? = if (isGeneric) { - ReflectionUtils.resolveUpperBoundSuperClassGenericParameter( - method.genericParameterTypes[0], - GenericSkyHanniEvent::class.java.typeParameters[0], - ) ?: error( - "Generic event handler type parameter is not present in " + - "event class hierarchy for type ${method.genericParameterTypes[0]}", - ) - } else { - null - } val name = "${method.declaringClass.name}.${method.name}${ method.parameterTypes.joinTo( StringBuilder(), @@ -39,7 +27,44 @@ class EventListeners private constructor(val name: String, private val isGeneric transform = Class<*>::getTypeName, ) }" - listeners.add(Listener(name, createEventConsumer(name, instance, method), options, generic)) + + val eventConsumer: (Any) -> Unit = when (method.parameterCount) { + 0 -> { + // Handle methods with no parameters + if (options.eventType == SkyHanniEvent::class) { + throw IllegalArgumentException("Method ${method.name} has no parameters but no eventType was provided in the annotation.") + } + // Verify the provided eventType + val eventType = options.eventType.java + if (!SkyHanniEvent::class.java.isAssignableFrom(eventType)) { + throw IllegalArgumentException("eventType in @HandleEvent must extend SkyHanniEvent. Provided: $eventType") + } + { method.invoke(instance) } + } + 1 -> { + // Handle methods with a single parameter (original behavior) + if (!SkyHanniEvent::class.java.isAssignableFrom(method.parameterTypes[0])) { + throw IllegalArgumentException("Method ${method.name} parameter must be a subclass of SkyHanniEvent.") + } + { event -> method.invoke(instance, event) } + } + else -> { + throw IllegalArgumentException("Method ${method.name} must have either 0 or 1 parameters.") + } + } + + val generic: Class<*>? = if (isGeneric) { + val genericType = method.genericParameterTypes.getOrNull(0) + ?: error("Method ${method.name} does not have a generic parameter type.") + ReflectionUtils.resolveUpperBoundSuperClassGenericParameter( + genericType, + GenericSkyHanniEvent::class.java.typeParameters[0], + ) ?: error( + "Generic event handler type parameter is not present in " + + "event class hierarchy for type $genericType", + ) + } else null + listeners.add(Listener(name, eventConsumer, options, generic)) } /** diff --git a/src/main/java/at/hannibal2/skyhanni/api/event/HandleEvent.kt b/src/main/java/at/hannibal2/skyhanni/api/event/HandleEvent.kt index a88f7f33724c..d6da04e1ceef 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/event/HandleEvent.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/event/HandleEvent.kt @@ -1,6 +1,7 @@ package at.hannibal2.skyhanni.api.event import at.hannibal2.skyhanni.data.IslandType +import kotlin.reflect.KClass @Retention(AnnotationRetention.RUNTIME) @Target(AnnotationTarget.FUNCTION) @@ -31,6 +32,11 @@ annotation class HandleEvent( * If the event is cancelled & receiveCancelled is true, then the method will still invoke. */ val receiveCancelled: Boolean = false, + + /** + * For cases where the event properties are themselves not needed, and solely a listener for an event fire suffices. + */ + val eventType: KClass = SkyHanniEvent::class ) { companion object { diff --git a/src/main/java/at/hannibal2/skyhanni/api/event/SkyHanniEvents.kt b/src/main/java/at/hannibal2/skyhanni/api/event/SkyHanniEvents.kt index dd7d60f3c9c1..8a69bb6ba8e2 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/event/SkyHanniEvents.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/event/SkyHanniEvents.kt @@ -38,12 +38,25 @@ object SkyHanniEvents { @Suppress("UNCHECKED_CAST") private fun registerMethod(method: Method, instance: Any) { - if (method.parameterCount != 1) return val options = method.getAnnotation(HandleEvent::class.java) ?: return - val event = method.parameterTypes[0] - if (!SkyHanniEvent::class.java.isAssignableFrom(event)) return - listeners.getOrPut(event as Class) { EventListeners(event) } - .addListener(method, instance, options) + val parameterTypes = method.parameterTypes + + // Check if the method has no parameters and an eventType is provided + if (parameterTypes.isEmpty()) { + val eventType = options.eventType.java + if (!SkyHanniEvent::class.java.isAssignableFrom(eventType)) return + listeners.getOrPut(eventType as Class) { EventListeners(eventType) } + .addListener(method, instance, options) + return + } + + // Handle methods with parameters (original behavior) + if (parameterTypes.size == 1) { + val eventType = parameterTypes[0] + if (!SkyHanniEvent::class.java.isAssignableFrom(eventType)) return + listeners.getOrPut(eventType as Class) { EventListeners(eventType) } + .addListener(method, instance, options) + } } @SubscribeEvent From f42004b8bbb927197f9713a0919c9840d9aa6a71 Mon Sep 17 00:00:00 2001 From: David Cole <40234707+DavidArthurCole@users.noreply.github.com> Date: Sat, 14 Dec 2024 03:32:08 -0500 Subject: [PATCH 63/91] Detekt :( --- .../skyhanni/api/event/EventListeners.kt | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/api/event/EventListeners.kt b/src/main/java/at/hannibal2/skyhanni/api/event/EventListeners.kt index 8f81aa29579a..c8e39b40d462 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/event/EventListeners.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/event/EventListeners.kt @@ -30,22 +30,21 @@ class EventListeners private constructor(val name: String, private val isGeneric val eventConsumer: (Any) -> Unit = when (method.parameterCount) { 0 -> { - // Handle methods with no parameters - if (options.eventType == SkyHanniEvent::class) { - throw IllegalArgumentException("Method ${method.name} has no parameters but no eventType was provided in the annotation.") + require(options.eventType != SkyHanniEvent::class) { + "Method ${method.name} has no parameters but no eventType was provided in the annotation." } - // Verify the provided eventType val eventType = options.eventType.java - if (!SkyHanniEvent::class.java.isAssignableFrom(eventType)) { - throw IllegalArgumentException("eventType in @HandleEvent must extend SkyHanniEvent. Provided: $eventType") + require(SkyHanniEvent::class.java.isAssignableFrom(eventType)) { + "eventType in @HandleEvent must extend SkyHanniEvent. Provided: $eventType" } - { method.invoke(instance) } + ; + { _: Any -> method.invoke(instance) } } 1 -> { - // Handle methods with a single parameter (original behavior) - if (!SkyHanniEvent::class.java.isAssignableFrom(method.parameterTypes[0])) { - throw IllegalArgumentException("Method ${method.name} parameter must be a subclass of SkyHanniEvent.") + require(SkyHanniEvent::class.java.isAssignableFrom(method.parameterTypes[0])) { + "Method ${method.name} parameter must be a subclass of SkyHanniEvent." } + ; { event -> method.invoke(instance, event) } } else -> { From ceb3e7b519902cf321e1aa3f8ec0bd43bfa31c78 Mon Sep 17 00:00:00 2001 From: David Cole <40234707+DavidArthurCole@users.noreply.github.com> Date: Sat, 14 Dec 2024 03:54:37 -0500 Subject: [PATCH 64/91] Remove strict reliance on eventType= --- .live-plugins/event/plugin.kts | 21 ++++++++++++++----- .../skyhanni/api/event/HandleEvent.kt | 11 +++++----- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/.live-plugins/event/plugin.kts b/.live-plugins/event/plugin.kts index 4564c8384243..9738809f572d 100644 --- a/.live-plugins/event/plugin.kts +++ b/.live-plugins/event/plugin.kts @@ -29,15 +29,26 @@ class HandleEventInspectionKotlin : AbstractKotlinInspection() { val visitor = object : KtVisitorVoid() { override fun visitNamedFunction(function: KtNamedFunction) { val hasEventAnnotation = function.annotationEntries.any { it.shortName!!.asString() == handleEvent } + + // Check if the function's parameter is a SkyHanniEvent or its subtype val isEvent = function.valueParameters.firstOrNull()?.type()?.supertypes() ?.any { it.fqName?.asString() == skyhanniEvent } ?: false - val hasEventType = function.annotationEntries + + // Find the annotation entry + val annotationEntry = function.annotationEntries .find { it.shortName!!.asString() == handleEvent } - ?.valueArguments - ?.find { it.getArgumentName()?.asName?.asString() == eventType } - ?.getArgumentExpression() - ?.text != null + // Check if the annotation specifies the eventType explicitly or as a positional parameter + val hasEventType = annotationEntry?.valueArguments + ?.any { argument -> + // Check if it is a named parameter for `eventType` + argument.getArgumentName()?.asName?.asString() == "eventType" || + // Check if it is a positional argument (first argument) + (annotationEntry.valueArguments.indexOf(argument) == 0 && + argument.getArgumentExpression()?.text != null) + } ?: false + + // Validate function annotation and parameters if (isEvent && !hasEventAnnotation && function.valueParameters.size == 1 && function.isPublic) { holder.registerProblem( function, diff --git a/src/main/java/at/hannibal2/skyhanni/api/event/HandleEvent.kt b/src/main/java/at/hannibal2/skyhanni/api/event/HandleEvent.kt index d6da04e1ceef..6f144add64aa 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/event/HandleEvent.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/event/HandleEvent.kt @@ -6,6 +6,11 @@ import kotlin.reflect.KClass @Retention(AnnotationRetention.RUNTIME) @Target(AnnotationTarget.FUNCTION) annotation class HandleEvent( + /** + * For cases where the event properties are themselves not needed, and solely a listener for an event fire suffices. + */ + val eventType: KClass = SkyHanniEvent::class, + /** * If the event should only be received while on SkyBlock. */ @@ -32,13 +37,7 @@ annotation class HandleEvent( * If the event is cancelled & receiveCancelled is true, then the method will still invoke. */ val receiveCancelled: Boolean = false, - - /** - * For cases where the event properties are themselves not needed, and solely a listener for an event fire suffices. - */ - val eventType: KClass = SkyHanniEvent::class ) { - companion object { const val HIGHEST = -2 const val HIGH = -1 From 18153c67788e018358b803508acd2bd821483e15 Mon Sep 17 00:00:00 2001 From: David Cole <40234707+DavidArthurCole@users.noreply.github.com> Date: Sat, 14 Dec 2024 04:15:01 -0500 Subject: [PATCH 65/91] Combine some dupe logic, split up monster function --- .../skyhanni/api/event/EventListeners.kt | 88 +++++++++++-------- .../skyhanni/api/event/SkyHanniEvents.kt | 22 +---- 2 files changed, 53 insertions(+), 57 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/api/event/EventListeners.kt b/src/main/java/at/hannibal2/skyhanni/api/event/EventListeners.kt index c8e39b40d462..6e3ed833638f 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/event/EventListeners.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/event/EventListeners.kt @@ -18,53 +18,63 @@ class EventListeners private constructor(val name: String, private val isGeneric ) fun addListener(method: Method, instance: Any, options: HandleEvent) { - val name = "${method.declaringClass.name}.${method.name}${ - method.parameterTypes.joinTo( - StringBuilder(), - prefix = "(", - postfix = ")", - separator = ", ", - transform = Class<*>::getTypeName, + val name = buildListenerName(method) + val eventConsumer = createEventConsumer(method, instance, options) + val generic = if (isGeneric) resolveGenericType(method) else null + + listeners.add(Listener(name, eventConsumer, options, generic)) + } + + private fun buildListenerName(method: Method): String { + val paramTypesString = method.parameterTypes.joinTo( + StringBuilder(), + prefix = "(", + postfix = ")", + separator = ", ", + transform = Class<*>::getTypeName + ).toString() + + return "${method.declaringClass.name}.${method.name}$paramTypesString" + } + + private fun createEventConsumer(method: Method, instance: Any, options: HandleEvent): (Any) -> Unit { + return when (method.parameterCount) { + 0 -> createZeroParameterConsumer(method, instance, options) + 1 -> createSingleParameterConsumer(method, instance) + else -> throw IllegalArgumentException( + "Method ${method.name} must have either 0 or 1 parameters." ) - }" - - val eventConsumer: (Any) -> Unit = when (method.parameterCount) { - 0 -> { - require(options.eventType != SkyHanniEvent::class) { - "Method ${method.name} has no parameters but no eventType was provided in the annotation." - } - val eventType = options.eventType.java - require(SkyHanniEvent::class.java.isAssignableFrom(eventType)) { - "eventType in @HandleEvent must extend SkyHanniEvent. Provided: $eventType" - } - ; - { _: Any -> method.invoke(instance) } - } - 1 -> { - require(SkyHanniEvent::class.java.isAssignableFrom(method.parameterTypes[0])) { - "Method ${method.name} parameter must be a subclass of SkyHanniEvent." - } - ; - { event -> method.invoke(instance, event) } - } - else -> { - throw IllegalArgumentException("Method ${method.name} must have either 0 or 1 parameters.") - } } + } - val generic: Class<*>? = if (isGeneric) { - val genericType = method.genericParameterTypes.getOrNull(0) - ?: error("Method ${method.name} does not have a generic parameter type.") + private fun createZeroParameterConsumer(method: Method, instance: Any, options: HandleEvent): (Any) -> Unit { + require(options.eventType != SkyHanniEvent::class) { + "Method ${method.name} has no parameters but no eventType was provided in the annotation." + } + val eventType = options.eventType.java + require(SkyHanniEvent::class.java.isAssignableFrom(eventType)) { + "eventType in @HandleEvent must extend SkyHanniEvent. Provided: $eventType" + } + return { _: Any -> method.invoke(instance) } + } + + private fun createSingleParameterConsumer(method: Method, instance: Any): (Any) -> Unit { + require(SkyHanniEvent::class.java.isAssignableFrom(method.parameterTypes[0])) { + "Method ${method.name} parameter must be a subclass of SkyHanniEvent." + } + return { event -> method.invoke(instance, event) } + } + + private fun resolveGenericType(method: Method): Class<*> = + method.genericParameterTypes.getOrNull(0)?.let { genericType -> ReflectionUtils.resolveUpperBoundSuperClassGenericParameter( genericType, - GenericSkyHanniEvent::class.java.typeParameters[0], + GenericSkyHanniEvent::class.java.typeParameters[0] ) ?: error( "Generic event handler type parameter is not present in " + - "event class hierarchy for type $genericType", + "event class hierarchy for type $genericType" ) - } else null - listeners.add(Listener(name, eventConsumer, options, generic)) - } + } ?: error("Method ${method.name} does not have a generic parameter type.") /** * Creates a consumer using LambdaMetafactory, this is the most efficient way to reflectively call diff --git a/src/main/java/at/hannibal2/skyhanni/api/event/SkyHanniEvents.kt b/src/main/java/at/hannibal2/skyhanni/api/event/SkyHanniEvents.kt index 8a69bb6ba8e2..e83d1876bd01 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/event/SkyHanniEvents.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/event/SkyHanniEvents.kt @@ -39,24 +39,10 @@ object SkyHanniEvents { @Suppress("UNCHECKED_CAST") private fun registerMethod(method: Method, instance: Any) { val options = method.getAnnotation(HandleEvent::class.java) ?: return - val parameterTypes = method.parameterTypes - - // Check if the method has no parameters and an eventType is provided - if (parameterTypes.isEmpty()) { - val eventType = options.eventType.java - if (!SkyHanniEvent::class.java.isAssignableFrom(eventType)) return - listeners.getOrPut(eventType as Class) { EventListeners(eventType) } - .addListener(method, instance, options) - return - } - - // Handle methods with parameters (original behavior) - if (parameterTypes.size == 1) { - val eventType = parameterTypes[0] - if (!SkyHanniEvent::class.java.isAssignableFrom(eventType)) return - listeners.getOrPut(eventType as Class) { EventListeners(eventType) } - .addListener(method, instance, options) - } + val eventType = method.parameterTypes.getOrNull(0) ?: options.eventType.java + if (!SkyHanniEvent::class.java.isAssignableFrom(eventType)) return + listeners.getOrPut(eventType as Class) { EventListeners(eventType) } + .addListener(method, instance, options) } @SubscribeEvent From cd5f57df474866297421dd9d1348eb55be72308d Mon Sep 17 00:00:00 2001 From: David Cole <40234707+DavidArthurCole@users.noreply.github.com> Date: Sat, 4 Jan 2025 16:42:49 -0500 Subject: [PATCH 66/91] Merge --- .../hannibal2/skyhanni/api/CurrentPetAPI.kt | 6 ++ .../features/misc/pets/CurrentPetDisplay.kt | 74 ------------------- 2 files changed, 6 insertions(+), 74 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt b/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt index ce29f0ebcd7c..1939a437a36d 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt @@ -72,6 +72,8 @@ object CurrentPetAPI { * REGEX-TEST: §cAutopet §eequipped your §7[Lvl 100] §6Scatha§e! §a§lVIEW RULE * REGEX-TEST: §cAutopet §eequipped your §7[Lvl 99] §6Flying Fish§e! §a§lVIEW RULE * REGEX-TEST: §cAutopet §eequipped your §7[Lvl 100] §dBlack Cat§d ✦§e! §a§lVIEW RULE + * REGEX-TEST: §cAutopet §eequipped your §7[Lvl 100] §6Griffin§4 ✦§e! §a§lVIEW RULE + * REGEX-TEST: §cAutopet §eequipped your §7[Lvl 100] §6Elephant§e! §a§lVIEW RULE */ private val autopetMessagePattern by patternGroup.pattern( "chat.autopet", @@ -88,6 +90,8 @@ object CurrentPetAPI { /** * REGEX-TEST: §7§7Selected pet: §6Hedgehog + * REGEX-TEST: §7§7Selected pet: §6Enderman + * REGEX-TEST: §7§7Selected pet: §cNone */ private val inventorySelectedPetPattern by patternGroup.pattern( "inventory.selected", @@ -159,6 +163,7 @@ object CurrentPetAPI { /** * REGEX-TEST: §aYou despawned your §r§6Golden Dragon§r§a! * REGEX-TEST: §aYou despawned your §r§6Silverfish§r§5 ✦§r§a! + * REGEX-TEST: §aYou despawned your §r§6Enderman§r§a! */ private val chatDespawnPattern by patternGroup.pattern( "chat.despawn", @@ -168,6 +173,7 @@ object CurrentPetAPI { /** * REGEX-TEST: §aYou summoned your §r§6Silverfish§r§5 ✦§r§a! * REGEX-TEST: §aYou summoned your §r§6Golden Dragon§r§a! + * REGEX-TEST: §aYou summoned your §r§6Enderman§r§a! */ private val chatSpawnPattern by patternGroup.pattern( "chat.spawn", diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt index b56c9648842c..e6b46df6f183 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt @@ -16,80 +16,6 @@ object CurrentPetDisplay { private val config get() = SkyHanniMod.feature.misc.pets -<<<<<<< HEAD -======= - private val patternGroup = RepoPattern.group("misc.currentpet") - - /** - * REGEX-TEST: §7§7Selected pet: §6Enderman - * REGEX-TEST: §7§7Selected pet: §cNone - */ - private val inventorySelectedPetPattern by patternGroup.pattern( - "inventory.selected", - "§7§7Selected pet: (?.*)", - ) - - /** - * REGEX-TEST: §aYou summoned your §r§6Enderman§r§a! - */ - private val chatSpawnPattern by patternGroup.pattern( - "chat.spawn", - "§aYou summoned your §r(?.*)§r§a!", - ) - - /** - * REGEX-TEST: §aYou despawned your §r§6Enderman§r§a! - */ - private val chatDespawnPattern by patternGroup.pattern( - "chat.despawn", - "§aYou despawned your §r.*§r§a!", - ) - - /** - * REGEX-TEST: §cAutopet §eequipped your §7[Lvl 100] §6Griffin§4 ✦§e! §a§lVIEW RULE - * REGEX-TEST: §cAutopet §eequipped your §7[Lvl 100] §6Elephant§e! §a§lVIEW RULE - */ - private val chatPetRulePattern by patternGroup.pattern( - "chat.rule", - "§cAutopet §eequipped your §7\\[Lvl .*] (?.*)§e! §a§lVIEW RULE", - ) - - @SubscribeEvent - fun onChat(event: LorenzChatEvent) { - findPetInChat(event.message)?.let { - PetAPI.currentPet = it - if (config.hideAutopet) { - event.blockedReason = "pets" - } - } - } - - private fun findPetInChat(message: String): String? { - chatSpawnPattern.matchMatcher(message) { - return group("pet") - } - if (chatDespawnPattern.matches(message)) { - return "" - } - chatPetRulePattern.matchMatcher(message) { - return group("pet") - } - - return null - } - - @SubscribeEvent - fun onInventoryOpen(event: InventoryFullyOpenedEvent) { - if (!PetAPI.isPetMenu(event.inventoryName)) return - - val lore = event.inventoryItems[4]?.getLore() ?: return - inventorySelectedPetPattern.firstMatcher(lore) { - val newPet = group("pet") - PetAPI.currentPet = if (newPet != "§cNone") newPet else "" - } - } - ->>>>>>> upstream/beta @SubscribeEvent fun onRenderOverlay(event: GuiRenderEvent.GuiOverlayRenderEvent) { if (!LorenzUtils.inSkyBlock || RiftAPI.inRift() || !config.display) return From c272cfbf611315e111e167462b5c5e333967a961 Mon Sep 17 00:00:00 2001 From: David Cole <40234707+DavidArthurCole@users.noreply.github.com> Date: Sat, 4 Jan 2025 16:43:51 -0500 Subject: [PATCH 67/91] Cleanup --- .../at/hannibal2/skyhanni/utils/SkyBlockItemModifierUtils.kt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/utils/SkyBlockItemModifierUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/SkyBlockItemModifierUtils.kt index 09ae53f576f7..3bedc838d394 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/SkyBlockItemModifierUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/SkyBlockItemModifierUtils.kt @@ -7,12 +7,9 @@ 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.NEUInternalName.Companion.toInternalName -<<<<<<< HEAD import at.hannibal2.skyhanni.utils.PetUtils.petItemNamePattern -import at.hannibal2.skyhanni.utils.RegexUtils.matchGroup -======= import at.hannibal2.skyhanni.utils.RegexUtils.anyMatches ->>>>>>> upstream/beta +import at.hannibal2.skyhanni.utils.RegexUtils.matchGroup import at.hannibal2.skyhanni.utils.StringUtils.removeColor import com.google.gson.JsonObject import net.minecraft.item.Item From 68f07590461b491178e62098a302d3f268516aff Mon Sep 17 00:00:00 2001 From: David Cole <40234707+DavidArthurCole@users.noreply.github.com> Date: Sat, 4 Jan 2025 16:48:04 -0500 Subject: [PATCH 68/91] More cleanup --- src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt | 2 +- .../hannibal2/skyhanni/config/storage/ProfileSpecificStorage.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt b/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt index 1939a437a36d..993a34bfe432 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt @@ -51,7 +51,7 @@ object CurrentPetAPI { var currentPet: PetData? get() = ProfileStorageData.profileSpecific?.currentPetData?.takeIf { it.isInitialized() } set(value) { - ProfileStorageData.profileSpecific?.currentPetData = value + ProfileStorageData.profileSpecific?.currentPetData = value ?: PetData() } fun isCurrentPet(petName: String): Boolean = currentPet?.cleanName?.contains(petName) ?: false diff --git a/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.kt b/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.kt index 1d43fed855e4..a68c88bb9754 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.kt +++ b/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.kt @@ -60,7 +60,7 @@ import kotlin.time.Duration class ProfileSpecificStorage { @Expose - var currentPetData: PetData = PetData(); + var currentPetData: PetData = PetData() @Expose var experimentation: ExperimentationStorage = ExperimentationStorage() From b6fcdffb36860bf70ecac1c000a73e764500578e Mon Sep 17 00:00:00 2001 From: calwolfson Date: Wed, 8 Jan 2025 10:18:38 +0100 Subject: [PATCH 69/91] regression --- src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt b/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt index 993a34bfe432..19211a5eeee5 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt @@ -367,7 +367,7 @@ object CurrentPetAPI { } } - @SubscribeEvent + @HandleEvent fun onInventoryOpen(event: InventoryFullyOpenedEvent) { inPetMenu = isPetMenu(event.inventoryName, event.inventoryItems) if (!inPetMenu) return @@ -382,7 +382,7 @@ object CurrentPetAPI { updatePet(petData.copy(xp = petData.xp?.plus(overflowXp))) } - @SubscribeEvent + @HandleEvent fun onInventoryClose(event: InventoryCloseEvent) { inPetMenu = false } From 2fdba87f910f6bfd6cd06a131dd0b02aad7ba104 Mon Sep 17 00:00:00 2001 From: David Cole <40234707+DavidArthurCole@users.noreply.github.com> Date: Tue, 14 Jan 2025 15:24:23 -0500 Subject: [PATCH 70/91] Fix regression --- src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt b/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt index cc2369a376c1..95db087a4f39 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt @@ -380,7 +380,7 @@ object CurrentPetAPI { @HandleEvent fun onSlotClick(event: GuiContainerEvent.SlotClickEvent) { if (!inPetMenu) return - if (event.clickTypeEnum != GuiContainerEvent.ClickType.NORMAL) return + if (event.clickType != GuiContainerEvent.ClickType.NORMAL) return val category = event.item?.getItemCategoryOrNull() ?: return if (category != ItemCategory.PET) return From c5d3194f2ac3b0b3cce7cc0d2bbf27c62fa98699 Mon Sep 17 00:00:00 2001 From: David Cole <40234707+DavidArthurCole@users.noreply.github.com> Date: Thu, 23 Jan 2025 20:43:48 -0500 Subject: [PATCH 71/91] Merge cleanup --- .../java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt b/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt index 95db087a4f39..b08917e639c8 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt @@ -13,8 +13,8 @@ import at.hannibal2.skyhanni.events.DebugDataCollectEvent import at.hannibal2.skyhanni.events.GuiContainerEvent import at.hannibal2.skyhanni.events.InventoryCloseEvent import at.hannibal2.skyhanni.events.InventoryFullyOpenedEvent -import at.hannibal2.skyhanni.events.LorenzChatEvent import at.hannibal2.skyhanni.events.WidgetUpdateEvent +import at.hannibal2.skyhanni.events.chat.SkyHanniChatEvent import at.hannibal2.skyhanni.events.skyblock.PetChangeEvent import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.test.command.ErrorManager @@ -201,7 +201,7 @@ object CurrentPetAPI { PetChangeEvent(oldPet, newPet).post() } - private fun handlePetMessageBlock(event: LorenzChatEvent) { + private fun handlePetMessageBlock(event: SkyHanniChatEvent) { if (!config.hideAutopet) return val spawnMatches = chatSpawnPattern.matches(event.message) val despawnMatches = chatDespawnPattern.matches(event.message) @@ -247,7 +247,7 @@ object CurrentPetAPI { // // - private fun onAutopetMessage(event: LorenzChatEvent) { + private fun onAutopetMessage(event: SkyHanniChatEvent) { val hoverMessage = event.chatComponent.hover?.siblings?.joinToString("")?.split("\n") ?: return val (petData, _) = parsePetData( @@ -339,8 +339,8 @@ object CurrentPetAPI { updatePet(petData.copy(xp = petData.xp?.plus(overflowXP))) } - @SubscribeEvent - fun onChat(event: LorenzChatEvent) { + @HandleEvent(onlyOnSkyblock = true) + fun onChat(event: SkyHanniChatEvent) { handlePetMessageBlock(event) if (autopetMessagePattern.matches(event.message)) { onAutopetMessage(event) From e1d9e8b12b48ac2a78246c770646644717807b84 Mon Sep 17 00:00:00 2001 From: David Cole <40234707+DavidArthurCole@users.noreply.github.com> Date: Thu, 23 Jan 2025 23:02:44 -0500 Subject: [PATCH 72/91] Detekt --- src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt b/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt index b08917e639c8..579337e2cc83 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/CurrentPetAPI.kt @@ -38,7 +38,6 @@ import at.hannibal2.skyhanni.utils.RegexUtils.matches import at.hannibal2.skyhanni.utils.StringUtils.convertToUnformatted import at.hannibal2.skyhanni.utils.chat.Text.hover import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent @SkyHanniModule object CurrentPetAPI { From 247659fd86ab75163d37d91e67cfa8cc5cba66b4 Mon Sep 17 00:00:00 2001 From: David Cole <40234707+DavidArthurCole@users.noreply.github.com> Date: Fri, 24 Jan 2025 21:39:29 -0500 Subject: [PATCH 73/91] Cleanup --- .../java/at/hannibal2/skyhanni/data/PetData.kt | 18 +++++++++--------- .../data/jsonobjects/repo/NEUPetsJson.kt | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetData.kt b/src/main/java/at/hannibal2/skyhanni/data/PetData.kt index 8b762c4c1053..b0991b052833 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetData.kt @@ -5,8 +5,8 @@ import at.hannibal2.skyhanni.test.command.ErrorManager import at.hannibal2.skyhanni.utils.ItemUtils.getLore import at.hannibal2.skyhanni.utils.ItemUtils.itemName import at.hannibal2.skyhanni.utils.LorenzRarity -import at.hannibal2.skyhanni.utils.NEUInternalName -import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.toInternalName +import at.hannibal2.skyhanni.utils.NeuInternalName +import at.hannibal2.skyhanni.utils.NeuInternalName.Companion.toInternalName import at.hannibal2.skyhanni.utils.PetUtils.xpToLevel import at.hannibal2.skyhanni.utils.RegexUtils.anyMatches import at.hannibal2.skyhanni.utils.SkyBlockItemModifierUtils.getExtraAttributes @@ -20,9 +20,9 @@ import net.minecraft.item.ItemStack * */ data class PetData( - val petItem: NEUInternalName? = null, // The internal name of the pet, e.g., `RABBIT;5` - val skinItem: NEUInternalName? = null, // The skin of the pet, e.g., `PET_SKIN_WOLF_DOGE` - val heldItem: NEUInternalName? = null, // The held item of the pet, e.g., `PET_ITEM_COMBAT_SKILL_BOOST_EPIC` + val petItem: NeuInternalName? = null, // The internal name of the pet, e.g., `RABBIT;5` + val skinItem: NeuInternalName? = null, // The skin of the pet, e.g., `PET_SKIN_WOLF_DOGE` + val heldItem: NeuInternalName? = null, // The held item of the pet, e.g., `PET_ITEM_COMBAT_SKILL_BOOST_EPIC` val cleanName: String? = null, // The clean name of the pet, e.g., `Rabbit` val skinSymbol: String? = null, // The symbol of the skin of the pet, e.g., §d ✦ val rarity: LorenzRarity? = null, // The rarity of the pet, e.g., `COMMON` @@ -71,7 +71,7 @@ data class PetData( // fun parsePetData( lines: List, - itemHandler: (String) -> NEUInternalName?, + itemHandler: (String) -> NeuInternalName?, xpHandler: (String) -> Double?, petHandler: (String) -> PetData? ): Pair? { @@ -85,7 +85,7 @@ data class PetData( fun parsePetDataLists( lines: List, - itemHandlerList: (List) -> NEUInternalName?, + itemHandlerList: (List) -> NeuInternalName?, xpHandlerList: (List) -> Double?, petHandlerList: (List) -> PetData? ): Pair? { @@ -127,10 +127,10 @@ data class PetData( ) } - fun petNameToInternalName(name: String, rarity: LorenzRarity): NEUInternalName = + fun petNameToInternalName(name: String, rarity: LorenzRarity): NeuInternalName = "${name.removeColor()};${rarity.id}".toInternalName() - fun internalNameToPetName(internalName: NEUInternalName): Pair? { + fun internalNameToPetName(internalName: NeuInternalName): Pair? { val (name, rarityStr) = internalName.asString().split(";") val rarity = LorenzRarity.getById(rarityStr.toInt()) ?: return null return Pair(name, rarity) diff --git a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt index 46c8b6fb6d25..288d662d3002 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt @@ -1,14 +1,14 @@ package at.hannibal2.skyhanni.data.jsonobjects.repo import at.hannibal2.skyhanni.utils.LorenzRarity -import at.hannibal2.skyhanni.utils.NEUInternalName +import at.hannibal2.skyhanni.utils.NeuInternalName import com.google.gson.annotations.Expose import com.google.gson.annotations.SerializedName data class NEUPetsJson( @Expose @SerializedName("pet_levels") val petLevels: List, @Expose @SerializedName("custom_pet_leveling") val customPetLeveling: Map, - @Expose @SerializedName("id_to_display_name") val internalToDisplayName: Map + @Expose @SerializedName("id_to_display_name") val internalToDisplayName: Map ) data class NEUPetData( From 3598abc4f7f9cb44b2dfc1f0f5d177cf4ccf2cec Mon Sep 17 00:00:00 2001 From: David Cole <40234707+DavidArthurCole@users.noreply.github.com> Date: Fri, 24 Jan 2025 23:18:39 -0500 Subject: [PATCH 74/91] Rename --- src/main/java/at/hannibal2/skyhanni/api/CurrentPetApi.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/at/hannibal2/skyhanni/api/CurrentPetApi.kt b/src/main/java/at/hannibal2/skyhanni/api/CurrentPetApi.kt index 4aecc1663844..88b0f464c54d 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/CurrentPetApi.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/CurrentPetApi.kt @@ -388,7 +388,7 @@ object CurrentPetApi { @HandleEvent fun onDebug(event: DebugDataCollectEvent) { - event.title("PetAPI") + event.title("CurrentPetApi") if (currentPet?.isInitialized() == false) { event.addIrrelevant("no pet equipped") return From c9ca4f0cb53510a5c822976f30f91f743e12f166 Mon Sep 17 00:00:00 2001 From: David Cole <40234707+DavidArthurCole@users.noreply.github.com> Date: Mon, 10 Feb 2025 17:22:23 -0500 Subject: [PATCH 75/91] Add multi --- .../hannibal2/skyhanni/api/event/HandleEvent.kt | 7 +++++++ .../skyhanni/api/event/SkyHanniEvents.kt | 17 ++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/main/java/at/hannibal2/skyhanni/api/event/HandleEvent.kt b/src/main/java/at/hannibal2/skyhanni/api/event/HandleEvent.kt index 6f144add64aa..119a4992a4fc 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/event/HandleEvent.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/event/HandleEvent.kt @@ -8,9 +8,16 @@ import kotlin.reflect.KClass annotation class HandleEvent( /** * For cases where the event properties are themselves not needed, and solely a listener for an event fire suffices. + * To specify multiple events, use [eventTypes] instead. */ val eventType: KClass = SkyHanniEvent::class, + /** + * For cases where multiple events are listened to, and properties are unnecessary. + * To specify only one event, use [eventType] instead. + */ + val eventTypes: Array> = [], + /** * If the event should only be received while on SkyBlock. */ diff --git a/src/main/java/at/hannibal2/skyhanni/api/event/SkyHanniEvents.kt b/src/main/java/at/hannibal2/skyhanni/api/event/SkyHanniEvents.kt index f2336d0eda5b..6b229f9a694e 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/event/SkyHanniEvents.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/event/SkyHanniEvents.kt @@ -35,15 +35,30 @@ object SkyHanniEvents { fun isDisabledHandler(handler: String): Boolean = handler in disabledHandlers fun isDisabledInvoker(invoker: String): Boolean = invoker in disabledHandlerInvokers - @Suppress("UNCHECKED_CAST") private fun registerMethod(method: Method, instance: Any) { val options = method.getAnnotation(HandleEvent::class.java) ?: return + registerSingleEventType(options, method, instance) + registerMultipleEventTypes(options, method, instance) + } + + @Suppress("UNCHECKED_CAST") + private fun registerSingleEventType(options: HandleEvent, method: Method, instance: Any) { val eventType = method.parameterTypes.getOrNull(0) ?: options.eventType.java if (!SkyHanniEvent::class.java.isAssignableFrom(eventType)) return listeners.getOrPut(eventType as Class) { EventListeners(eventType) } .addListener(method, instance, options) } + @Suppress("UNCHECKED_CAST") + private fun registerMultipleEventTypes(options: HandleEvent, method: Method, instance: Any) { + options.eventTypes.map { it.java }.forEach { eventType -> + if (!SkyHanniEvent::class.java.isAssignableFrom(eventType)) return + listeners.getOrPut(eventType as Class) { EventListeners(eventType) } + .addListener(method, instance, options) + } + } + + @HandleEvent fun onRepoReload(event: RepositoryReloadEvent) { val data = event.getConstant("DisabledEvents") From 1b4f559f9deb86f6813ac6dc93dbfc5228959b6d Mon Sep 17 00:00:00 2001 From: David Cole <40234707+DavidArthurCole@users.noreply.github.com> Date: Mon, 10 Feb 2025 18:25:10 -0500 Subject: [PATCH 76/91] Plugin config --- .live-plugins/event/plugin.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.live-plugins/event/plugin.kts b/.live-plugins/event/plugin.kts index 9738809f572d..ff289c705a28 100644 --- a/.live-plugins/event/plugin.kts +++ b/.live-plugins/event/plugin.kts @@ -41,8 +41,8 @@ class HandleEventInspectionKotlin : AbstractKotlinInspection() { // Check if the annotation specifies the eventType explicitly or as a positional parameter val hasEventType = annotationEntry?.valueArguments ?.any { argument -> - // Check if it is a named parameter for `eventType` - argument.getArgumentName()?.asName?.asString() == "eventType" || + val argName = argument.getArgumentName()?.asName?.asString() + argName == eventType || argName == "eventTypes" || // Check if it is a positional argument (first argument) (annotationEntry.valueArguments.indexOf(argument) == 0 && argument.getArgumentExpression()?.text != null) From 4f9dcfe6bb428f085c8aee6456200a252c80c720 Mon Sep 17 00:00:00 2001 From: David Cole <40234707+DavidArthurCole@users.noreply.github.com> Date: Mon, 10 Feb 2025 18:35:56 -0500 Subject: [PATCH 77/91] Oops. --- .../skyhanni/api/event/EventListeners.kt | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/api/event/EventListeners.kt b/src/main/java/at/hannibal2/skyhanni/api/event/EventListeners.kt index 6e3ed833638f..042613296d4f 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/event/EventListeners.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/event/EventListeners.kt @@ -48,13 +48,21 @@ class EventListeners private constructor(val name: String, private val isGeneric } private fun createZeroParameterConsumer(method: Method, instance: Any, options: HandleEvent): (Any) -> Unit { - require(options.eventType != SkyHanniEvent::class) { - "Method ${method.name} has no parameters but no eventType was provided in the annotation." - } - val eventType = options.eventType.java - require(SkyHanniEvent::class.java.isAssignableFrom(eventType)) { - "eventType in @HandleEvent must extend SkyHanniEvent. Provided: $eventType" + if (options.eventTypes.isNotEmpty()) { + options.eventTypes.onEach { kClass -> + require(SkyHanniEvent::class.java.isAssignableFrom(kClass.java)) { + "Each event in eventTypes in @HandleEvent must extend SkyHanniEvent. Provided: $kClass" + } + } + } else { + require(options.eventType != SkyHanniEvent::class) { + "Method ${method.name} has no parameters but no eventType was provided in the annotation." + } + require(SkyHanniEvent::class.java.isAssignableFrom(options.eventType.java)) { + "eventType in @HandleEvent must extend SkyHanniEvent. Provided: ${options.eventType.java}" + } } + return { _: Any -> method.invoke(instance) } } From d5624178a442d4f2d863e89317ff4214f60687d8 Mon Sep 17 00:00:00 2001 From: hannibal2 <24389977+hannibal00212@users.noreply.github.com> Date: Tue, 11 Feb 2025 11:45:35 +0100 Subject: [PATCH 78/91] merge conflict --- .../skyhanni/config/storage/ProfileSpecificStorage.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.kt b/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.kt index 557f84ac469d..80840e51ba40 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.kt +++ b/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.kt @@ -4,6 +4,7 @@ import at.hannibal2.skyhanni.api.HotmApi.PowderType import at.hannibal2.skyhanni.api.SkillApi import at.hannibal2.skyhanni.data.IslandType import at.hannibal2.skyhanni.data.MaxwellApi.ThaumaturgyPowerTuning +import at.hannibal2.skyhanni.data.PetData import at.hannibal2.skyhanni.data.jsonobjects.local.HotmTree import at.hannibal2.skyhanni.data.model.ComposterUpgrade import at.hannibal2.skyhanni.data.model.SkyblockStat @@ -750,7 +751,7 @@ class ProfileSpecificStorage { // data @Expose - var currentPet: String = "" + var currentPetData: PetData = PetData() @Expose var stats: MutableMap = enumMapOf() From 78a92216d438bdeb14edb002ecef92f6c4426d3e Mon Sep 17 00:00:00 2001 From: David Cole <40234707+DavidArthurCole@users.noreply.github.com> Date: Fri, 21 Feb 2025 20:02:27 -0500 Subject: [PATCH 79/91] Sto --- .../at/hannibal2/skyhanni/data/PetData.kt | 5 +- .../features/misc/pets/CurrentPetDisplay.kt | 26 ++++++- .../skyhanni/utils/renderables/Renderable.kt | 73 +++++++++++++++++++ 3 files changed, 100 insertions(+), 4 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetData.kt b/src/main/java/at/hannibal2/skyhanni/data/PetData.kt index b0991b052833..34a158ec1cfd 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetData.kt @@ -7,6 +7,7 @@ import at.hannibal2.skyhanni.utils.ItemUtils.itemName import at.hannibal2.skyhanni.utils.LorenzRarity import at.hannibal2.skyhanni.utils.NeuInternalName import at.hannibal2.skyhanni.utils.NeuInternalName.Companion.toInternalName +import at.hannibal2.skyhanni.utils.NeuItems.getItemStackOrNull import at.hannibal2.skyhanni.utils.PetUtils.xpToLevel import at.hannibal2.skyhanni.utils.RegexUtils.anyMatches import at.hannibal2.skyhanni.utils.SkyBlockItemModifierUtils.getExtraAttributes @@ -40,9 +41,11 @@ data class PetData( ): String { val levelString = if (includeLevel) "§7[Lvl $level] §r" else "" val skinString = if (includeSkin) (skinSymbol.orEmpty()) else "" - return "§r$levelString$formattedName$cleanName$skinString" + return "§r$levelString$formattedName$skinString" } + fun getItemStackOrNull(): ItemStack? = petItem?.getItemStackOrNull() + override fun equals(other: Any?): Boolean { if (other !is PetData) return false return this.petItem == other.petItem && diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt index 7f119ea020f6..6d224b3d3c20 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt @@ -7,7 +7,10 @@ import at.hannibal2.skyhanni.config.ConfigUpdaterMigrator import at.hannibal2.skyhanni.events.GuiRenderEvent import at.hannibal2.skyhanni.features.rift.RiftApi import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule -import at.hannibal2.skyhanni.utils.RenderUtils.renderString +import at.hannibal2.skyhanni.utils.RenderUtils +import at.hannibal2.skyhanni.utils.RenderUtils.renderRenderable +import at.hannibal2.skyhanni.utils.renderables.Renderable +import java.awt.Color @SkyHanniModule object CurrentPetDisplay { @@ -18,8 +21,25 @@ object CurrentPetDisplay { fun onRenderOverlay(event: GuiRenderEvent.GuiOverlayRenderEvent) { if (RiftApi.inRift() || !config.display) return - val displayName = CurrentPetApi.currentPet?.getUserFriendlyName(includeLevel = false) ?: return - config.displayPos.renderString(displayName, posLabel = "Current Pet") + val currentPet = CurrentPetApi.currentPet ?: return + val displayName = currentPet.getUserFriendlyName(includeLevel = false) + val itemStack = currentPet.getItemStackOrNull() ?: return + val rarityColor = currentPet.rarity?.color ?: return + + val nameRender = Renderable.string(displayName, color = rarityColor.toColor()) + val circle = Renderable.CircularRenderable( + rarityColor.toColor(), + 50, + itemStack = itemStack, + border = Renderable.CircularRenderable(Color.LIGHT_GRAY, 65) + ) + + val container = Renderable.verticalContainer( + listOf(nameRender, circle), + horizontalAlign = RenderUtils.HorizontalAlignment.CENTER, + ) + + config.displayPos.renderRenderable(container, posLabel = "Current Pet") } @HandleEvent 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 3a8bc7c48bc2..6c6dea574c38 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt @@ -46,7 +46,9 @@ import net.minecraft.util.ResourceLocation import org.lwjgl.opengl.GL11 import java.awt.Color import java.util.Collections +import kotlin.math.cos import kotlin.math.max +import kotlin.math.sin interface Renderable { @@ -1688,4 +1690,75 @@ interface Renderable { } } } + + class CircularRenderable( + private val backgroundColor: Color, + private val radius: Int, + private val border: CircularRenderable? = null, + private val itemStack: ItemStack? = null, + private val itemScale: Double = 1.0 + ) : Renderable { + + // The bounding box is a square with a diameter equal to 2*radius. + override val width: Int = radius * 2 + override val height: Int = radius * 2 + // We use top-left alignment here; positioning will be done via translation. + override val horizontalAlign = HorizontalAlignment.LEFT + override val verticalAlign = VerticalAlignment.TOP + + override fun render(posX: Int, posY: Int) { + // Render outer border rings first (if any) - we want to transpose each circle on top of the previous one, + // to give the illusion of a ring effect. + border?.render(posX, posY) + + val centerX = posX + radius + val centerY = posY + radius + drawFilledCircle(centerX, centerY, radius, backgroundColor) + + val itemStack = itemStack ?: return + // Render the ItemStack centered in this circle. + val itemRenderable = itemStack(itemStack, scale = itemScale) + // Calculate top-left position for centering the item. + val itemX = centerX - itemRenderable.width / 2 + val itemY = centerY - itemRenderable.height / 2 + itemRenderable.render(itemX, itemY) + } + + /** + * Draws a filled circle using OpenGL. + * + * @param cx The x-coordinate of the circle's center. + * @param cy The y-coordinate of the circle's center. + * @param radius The circle's radius. + * @param color The fill color. + */ + private fun drawFilledCircle(cx: Int, cy: Int, radius: Int, color: Color) { + GL11.glPushMatrix() + GL11.glEnable(GL11.GL_BLEND) + GL11.glDisable(GL11.GL_TEXTURE_2D) + // Set the circle's color. + GL11.glColor4f( + color.red / 255f, + color.green / 255f, + color.blue / 255f, + color.alpha / 255f + ) + // Begin drawing a triangle fan (a filled circle) + GL11.glBegin(GL11.GL_TRIANGLE_FAN) + // Center of the circle. + GL11.glVertex2f(cx.toFloat(), cy.toFloat()) + // Use enough segments for a smooth circle. + val segments = 100 + for (i in 0..segments) { + val angle = (2.0 * Math.PI * i / segments).toFloat() + val x = cx + (cos(angle.toDouble()) * radius).toInt() + val y = cy + (sin(angle.toDouble()) * radius).toInt() + GL11.glVertex2f(x.toFloat(), y.toFloat()) + } + GL11.glEnd() + GL11.glEnable(GL11.GL_TEXTURE_2D) + GL11.glDisable(GL11.GL_BLEND) + GL11.glPopMatrix() + } + } } From 6d597cf1763e7d842da6a4c040c3882b7ebed9ba Mon Sep 17 00:00:00 2001 From: David Cole <40234707+DavidArthurCole@users.noreply.github.com> Date: Fri, 21 Feb 2025 21:07:12 -0500 Subject: [PATCH 80/91] Sto --- .../at/hannibal2/skyhanni/data/PetData.kt | 35 ++++++------- .../jsonobjects/repo/neu/NeuPetSkinJson.kt | 49 +++++++++++++++---- .../at/hannibal2/skyhanni/utils/PetUtils.kt | 27 +++++++--- .../skyhanni/utils/renderables/Renderable.kt | 39 +++++++++------ 4 files changed, 101 insertions(+), 49 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetData.kt b/src/main/java/at/hannibal2/skyhanni/data/PetData.kt index 34a158ec1cfd..73cb5e733418 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetData.kt @@ -1,38 +1,40 @@ package at.hannibal2.skyhanni.data import at.hannibal2.skyhanni.api.CurrentPetApi.petDespawnMenuPattern +import at.hannibal2.skyhanni.data.jsonobjects.repo.neu.NeuPetSkinJson import at.hannibal2.skyhanni.test.command.ErrorManager import at.hannibal2.skyhanni.utils.ItemUtils.getLore import at.hannibal2.skyhanni.utils.ItemUtils.itemName +import at.hannibal2.skyhanni.utils.LorenzColor import at.hannibal2.skyhanni.utils.LorenzRarity import at.hannibal2.skyhanni.utils.NeuInternalName import at.hannibal2.skyhanni.utils.NeuInternalName.Companion.toInternalName import at.hannibal2.skyhanni.utils.NeuItems.getItemStackOrNull +import at.hannibal2.skyhanni.utils.PetUtils.getSkinOrNull import at.hannibal2.skyhanni.utils.PetUtils.xpToLevel import at.hannibal2.skyhanni.utils.RegexUtils.anyMatches import at.hannibal2.skyhanni.utils.SkyBlockItemModifierUtils.getExtraAttributes import at.hannibal2.skyhanni.utils.StringUtils.firstLetterUppercase import at.hannibal2.skyhanni.utils.StringUtils.removeColor import com.google.gson.Gson +import com.google.gson.annotations.Expose import net.minecraft.item.ItemStack -/** - * TODO: Skins still need to be loaded from the API. - * - */ data class PetData( - val petItem: NeuInternalName? = null, // The internal name of the pet, e.g., `RABBIT;5` - val skinItem: NeuInternalName? = null, // The skin of the pet, e.g., `PET_SKIN_WOLF_DOGE` - val heldItem: NeuInternalName? = null, // The held item of the pet, e.g., `PET_ITEM_COMBAT_SKILL_BOOST_EPIC` - val cleanName: String? = null, // The clean name of the pet, e.g., `Rabbit` - val skinSymbol: String? = null, // The symbol of the skin of the pet, e.g., §d ✦ - val rarity: LorenzRarity? = null, // The rarity of the pet, e.g., `COMMON` - val level: Int? = null, // The current level of the pet as an integer, e.g., `100` - val xp: Double? = null, // The total XP of the pet as a double, e.g., `0.0` + @Expose val petItem: NeuInternalName? = null, // The internal name of the pet, e.g., `RABBIT;5` + @Expose val heldItem: NeuInternalName? = null, // The held item of the pet, e.g., `PET_ITEM_COMBAT_SKILL_BOOST_EPIC` + @Expose val cleanName: String? = null, // The clean name of the pet, e.g., `Rabbit` + @Expose val skinSymbolColor: LorenzColor? = null, // The color symbol of the skin of the pet, e.g., §d ✦ -> `LorenzColor.Pink` + @Expose val rarity: LorenzRarity? = null, // The rarity of the pet, e.g., `COMMON` + @Expose val level: Int? = null, // The current level of the pet as an integer, e.g., `100` + @Expose val xp: Double? = null, // The total XP of the pet as a double, e.g., `0.0` + @Expose val skinInternalNameOverride: NeuInternalName? = null, // If the skin is known (i.e., from stored data or Inventory) ) { val displayName = petItem?.itemName val formattedName = "${rarity?.chatColorCode}$cleanName" - // private val skinName = skinItem?.itemName?.takeIf { it.isNotEmpty() }?.let { " §r$it" }.orEmpty() + val skin: NeuPetSkinJson? = getSkinOrNull() + + @Expose var skinInternalName: NeuInternalName? = skinInternalNameOverride ?: skin?.internalName // Please god only use this for UI, not for comparisons fun getUserFriendlyName( @@ -40,19 +42,18 @@ data class PetData( includeSkin: Boolean = true, ): String { val levelString = if (includeLevel) "§7[Lvl $level] §r" else "" - val skinString = if (includeSkin) (skinSymbol.orEmpty()) else "" + val skinString = if (includeSkin) skinSymbolColor?.let { "${it.getChatColor()}✦" }.orEmpty() else "" return "§r$levelString$formattedName$skinString" } - fun getItemStackOrNull(): ItemStack? = petItem?.getItemStackOrNull() + fun getItemStackOrNull(): ItemStack? = skin?.itemStack ?: petItem?.getItemStackOrNull() override fun equals(other: Any?): Boolean { if (other !is PetData) return false return this.petItem == other.petItem && - this.skinItem == other.skinItem && this.heldItem == other.heldItem && this.cleanName == other.cleanName && - this.skinSymbol == other.skinSymbol && + this.skinSymbolColor == other.skinSymbolColor && this.rarity == other.rarity && this.level == other.level && this.xp == other.xp diff --git a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/neu/NeuPetSkinJson.kt b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/neu/NeuPetSkinJson.kt index bc9d107c882a..ebad0256b9cf 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/neu/NeuPetSkinJson.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/neu/NeuPetSkinJson.kt @@ -1,5 +1,14 @@ package at.hannibal2.skyhanni.data.jsonobjects.repo.neu +import at.hannibal2.skyhanni.api.CurrentPetApi +import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule +import at.hannibal2.skyhanni.utils.ItemUtils +import at.hannibal2.skyhanni.utils.ItemUtils.getSkullTexture +import at.hannibal2.skyhanni.utils.LorenzRarity +import at.hannibal2.skyhanni.utils.NeuInternalName.Companion.toInternalName +import at.hannibal2.skyhanni.utils.RegexUtils.firstMatcher +import at.hannibal2.skyhanni.utils.RegexUtils.firstMatches +import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern.Companion.group import com.google.gson.annotations.Expose import com.google.gson.annotations.SerializedName import net.minecraft.nbt.CompressedStreamTools @@ -13,7 +22,7 @@ data class NeuPetSkinJson( @Expose @SerializedName("nbttag") val nbtTagString: String, @Expose val damage: Int, @Expose val lore: List, - @Expose @SerializedName("internalname") val internalName: String, + @Expose @SerializedName("internalname") val internalNameStr: String, @Expose @SerializedName("crafttext") val craftText: String, @Expose @SerializedName("clickcommand") val clickCommand: String, @Expose @SerializedName("modver") val modVersion: String, @@ -25,15 +34,37 @@ data class NeuPetSkinJson( * @return Parsed NBTTagCompound object. * @throws IllegalArgumentException if the NBT parsing fails. */ - private fun getParsedNBT(): NBTTagCompound { - return try { - val decodedBytes = Base64.getDecoder().decode(nbtTagString.toByteArray(Charsets.UTF_8)) - val inputStream = ByteArrayInputStream(decodedBytes) - CompressedStreamTools.readCompressed(inputStream) - } catch (e: Exception) { - throw IllegalArgumentException("Failed to parse NBT tag: $nbtTagString", e) + private val nbtTag: NBTTagCompound? get() = try { + val decodedBytes = Base64.getDecoder().decode(nbtTagString.toByteArray(Charsets.UTF_8)) + val inputStream = ByteArrayInputStream(decodedBytes) + CompressedStreamTools.readCompressed(inputStream) + } catch (e: Exception) { + throw IllegalArgumentException("Failed to parse NBT tag: $nbtTagString", e) + } + + @Suppress("SpreadOperator") + val itemStack by lazy { + nbtTag?.let { + ItemUtils.createSkull( + displayName, + it.getString("ID"), + it.getSkullTexture(), + *lore.toTypedArray() + ) } } + val rarity: LorenzRarity? = rarityPattern.firstMatcher(lore) { LorenzRarity.getByName(group("rarity")) } + val internalName = internalNameStr.toInternalName() - val nbtTag get() = getParsedNBT() + @SkyHanniModule + companion object { + /** + * REGEX-TEST: §9§lRARE COSMETIC + * REGEX-TEST: §d§lMYTHIC COSMETIC + */ + private val rarityPattern by CurrentPetApi.patternGroup.pattern( + "skin.rarity", + "(?:§.)+(?[A-Z]+) COSMETIC", + ) + } } diff --git a/src/main/java/at/hannibal2/skyhanni/utils/PetUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/PetUtils.kt index 424e880b3ec2..abba31e5d132 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/PetUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/PetUtils.kt @@ -4,6 +4,7 @@ import at.hannibal2.skyhanni.api.CurrentPetApi import at.hannibal2.skyhanni.api.event.HandleEvent import at.hannibal2.skyhanni.config.commands.CommandCategory import at.hannibal2.skyhanni.config.commands.CommandRegistrationEvent +import at.hannibal2.skyhanni.data.PetData import at.hannibal2.skyhanni.data.PetData.Companion.internalNameToPetName import at.hannibal2.skyhanni.data.jsonobjects.repo.NEUPetData import at.hannibal2.skyhanni.data.jsonobjects.repo.NEUPetsJson @@ -14,7 +15,6 @@ import at.hannibal2.skyhanni.test.command.ErrorManager import at.hannibal2.skyhanni.utils.ItemUtils.getLore import at.hannibal2.skyhanni.utils.NeuInternalName.Companion.toInternalName import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators -import at.hannibal2.skyhanni.utils.RegexUtils.groupOrNull import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.RegexUtils.matches import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern @@ -25,8 +25,8 @@ import net.minecraft.item.ItemStack object PetUtils { private val patternGroup = RepoPattern.group("misc.pet") private const val FORGE_BACK_SLOT = 48 - // Map of Pet Name to a Map of Skin Name to NeuPetSkinJson - val petSkins = mutableMapOf>() + // Map of Pet Name to a Map of InternalName to NeuPetSkinJson + private val petSkins = mutableMapOf>() private var baseXpLevelReqs: List = listOf() private var customXpLevelReqs: Map? = null @@ -230,13 +230,10 @@ object PetUtils { NeuItems.allNeuRepoItems().forEach { (rawInternalName, jsonObject) -> petSkinNamePattern.matchMatcher(rawInternalName) { val petName = group("pet") ?: return@matchMatcher - // Skin name can be empty, see PET_SKIN_ENDERMAN, PET_SKIN_RABBIT, etc. - val skinName = groupOrNull("skin").orEmpty() - // Use GSON to reflect the JSON into a NeuPetSkinJson object val petItemData = Gson().fromJson(jsonObject, NeuPetSkinJson::class.java) - petSkins.getOrPut(petName) { mutableMapOf() }[skinName] = petItemData + petSkins.getOrPut(petName) { mutableMapOf() }[rawInternalName] = petItemData } } } @@ -249,4 +246,20 @@ object PetUtils { callback { levelToXPCommand(it) } } } + + fun PetData.getSkinOrNull(): NeuPetSkinJson? { + if (skinSymbolColor == null && skinInternalName == null) return null + + val cleanPetName = cleanName ?: return null + val possiblePetSkins = petSkins[cleanPetName] ?: return null + if (possiblePetSkins.size == 1) return possiblePetSkins.values.first() + + skinInternalName?.let { return possiblePetSkins[it.asString()] } + + val possibleSymbolSkins = possiblePetSkins.filter { + val cosmeticRarity = it.value.rarity ?: return@filter false + cosmeticRarity.color == skinSymbolColor + }.takeIf { it.isNotEmpty() } ?: return null + if (possibleSymbolSkins.size == 1) return possibleSymbolSkins.values.first() + } } 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 6c6dea574c38..60f41a303957 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt @@ -1694,21 +1694,22 @@ interface Renderable { class CircularRenderable( private val backgroundColor: Color, private val radius: Int, + // Optional border; if provided, its render() is called first. private val border: CircularRenderable? = null, + // Optional ItemStack to render on top of the circle. private val itemStack: ItemStack? = null, + // Scale for the item rendering. private val itemScale: Double = 1.0 ) : Renderable { - // The bounding box is a square with a diameter equal to 2*radius. + // The bounding box is a square of side length 2 * radius. override val width: Int = radius * 2 override val height: Int = radius * 2 - // We use top-left alignment here; positioning will be done via translation. override val horizontalAlign = HorizontalAlignment.LEFT override val verticalAlign = VerticalAlignment.TOP override fun render(posX: Int, posY: Int) { - // Render outer border rings first (if any) - we want to transpose each circle on top of the previous one, - // to give the illusion of a ring effect. + // Render the border (if any) first. border?.render(posX, posY) val centerX = posX + radius @@ -1716,12 +1717,19 @@ interface Renderable { drawFilledCircle(centerX, centerY, radius, backgroundColor) val itemStack = itemStack ?: return - // Render the ItemStack centered in this circle. - val itemRenderable = itemStack(itemStack, scale = itemScale) - // Calculate top-left position for centering the item. - val itemX = centerX - itemRenderable.width / 2 - val itemY = centerY - itemRenderable.height / 2 - itemRenderable.render(itemX, itemY) + // Use an approximate size for the item icon (you can adjust these values). + val itemWidth = (15.5 * itemScale).toInt() + val itemHeight = (15.5 * itemScale).toInt() + // Compute the top-left coordinates to center the item. + val itemX = centerX - itemWidth / 2 + val itemY = centerY - itemHeight / 2 + + GL11.glPushMatrix() + // Translate so that (0,0) is where the item should be rendered. + GL11.glTranslatef(itemX.toFloat(), itemY.toFloat(), 0f) + // Render the item at (0,0) now. + itemStack.renderOnScreen(0f, 0f, scaleMultiplier = itemScale, rescaleSkulls = true) + GL11.glPopMatrix() } /** @@ -1736,23 +1744,22 @@ interface Renderable { GL11.glPushMatrix() GL11.glEnable(GL11.GL_BLEND) GL11.glDisable(GL11.GL_TEXTURE_2D) - // Set the circle's color. + // Set the desired color. GL11.glColor4f( color.red / 255f, color.green / 255f, color.blue / 255f, color.alpha / 255f ) - // Begin drawing a triangle fan (a filled circle) GL11.glBegin(GL11.GL_TRIANGLE_FAN) - // Center of the circle. + // Center vertex. GL11.glVertex2f(cx.toFloat(), cy.toFloat()) - // Use enough segments for a smooth circle. + // Draw circle segments. val segments = 100 for (i in 0..segments) { val angle = (2.0 * Math.PI * i / segments).toFloat() - val x = cx + (cos(angle.toDouble()) * radius).toInt() - val y = cy + (sin(angle.toDouble()) * radius).toInt() + val x = cx + (cos(angle) * radius).toInt() + val y = cy + (sin(angle) * radius).toInt() GL11.glVertex2f(x.toFloat(), y.toFloat()) } GL11.glEnd() From 4122beb63fc97621febcac5a9ec03f96b8beaed4 Mon Sep 17 00:00:00 2001 From: David Cole <40234707+DavidArthurCole@users.noreply.github.com> Date: Fri, 21 Feb 2025 21:15:40 -0500 Subject: [PATCH 81/91] Fix --- src/main/java/at/hannibal2/skyhanni/utils/PetUtils.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/utils/PetUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/PetUtils.kt index abba31e5d132..0d7be80668a2 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/PetUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/PetUtils.kt @@ -259,7 +259,8 @@ object PetUtils { val possibleSymbolSkins = possiblePetSkins.filter { val cosmeticRarity = it.value.rarity ?: return@filter false cosmeticRarity.color == skinSymbolColor - }.takeIf { it.isNotEmpty() } ?: return null - if (possibleSymbolSkins.size == 1) return possibleSymbolSkins.values.first() + } + + return possibleSymbolSkins.values.firstOrNull() } } From 37144648f0ccc8926f5d43379465965f0cfcfce9 Mon Sep 17 00:00:00 2001 From: David Cole <40234707+DavidArthurCole@users.noreply.github.com> Date: Fri, 21 Feb 2025 21:28:04 -0500 Subject: [PATCH 82/91] More fixes --- .../at/hannibal2/skyhanni/api/CurrentPetApi.kt | 16 +++++++++++++--- .../java/at/hannibal2/skyhanni/data/PetData.kt | 6 +++++- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/api/CurrentPetApi.kt b/src/main/java/at/hannibal2/skyhanni/api/CurrentPetApi.kt index 88b0f464c54d..4596aa3c25ab 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/CurrentPetApi.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/CurrentPetApi.kt @@ -22,6 +22,8 @@ import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.ItemCategory import at.hannibal2.skyhanni.utils.ItemUtils.getItemCategoryOrNull import at.hannibal2.skyhanni.utils.ItemUtils.getLore +import at.hannibal2.skyhanni.utils.LorenzColor +import at.hannibal2.skyhanni.utils.LorenzColor.Companion.toLorenzColor import at.hannibal2.skyhanni.utils.LorenzRarity import at.hannibal2.skyhanni.utils.NeuInternalName import at.hannibal2.skyhanni.utils.NumberUtil.formatDouble @@ -189,9 +191,16 @@ object CurrentPetApi { // // - private fun updatePet(newPet: PetData?) { - if (newPet == currentPet) return + private fun updatePet(eventNewPet: PetData?) { + val newPet = eventNewPet ?: return val oldPet = currentPet + if (newPet == oldPet) return + if (newPet.allButSkinEquivalent(oldPet)) { + // If the two pets are the same except for the skin, we want to take the one that has the skin. + // If they both have differing skins, we want to take the new one. + if (oldPet?.skinInternalName != null && newPet.skinInternalName == null) return + } + currentPet = newPet if (SkyHanniMod.feature.dev.debug.petEventMessages) { ChatUtils.debug("oldPet: " + oldPet.toString().convertToUnformatted()) @@ -217,15 +226,16 @@ object CurrentPetApi { val petName = groupOrNull("name").orEmpty() val level = groupOrNull("level")?.toInt() ?: 0 val xp = levelToXp(level, rarity, petName) ?: return null + val skinColor = groupOrNull("skin")?.substring(1, 2)?.get(0)?.toLorenzColor() return PetData( petItem = petNameToInternalName(petName, rarity), - skinItem = null, heldItem = null, cleanName = petName, rarity = rarity, level = level, xp = xp, + skinSymbolColor = skinColor, ) } diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetData.kt b/src/main/java/at/hannibal2/skyhanni/data/PetData.kt index 73cb5e733418..15f60d367d60 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetData.kt @@ -49,11 +49,15 @@ data class PetData( fun getItemStackOrNull(): ItemStack? = skin?.itemStack ?: petItem?.getItemStackOrNull() override fun equals(other: Any?): Boolean { + if (other !is PetData) return false + return allButSkinEquivalent(other) && this.skinInternalName == other.skinInternalName + } + + fun allButSkinEquivalent(other: Any?): Boolean { if (other !is PetData) return false return this.petItem == other.petItem && this.heldItem == other.heldItem && this.cleanName == other.cleanName && - this.skinSymbolColor == other.skinSymbolColor && this.rarity == other.rarity && this.level == other.level && this.xp == other.xp From 91282d4380431a1e201331b144c863892502498e Mon Sep 17 00:00:00 2001 From: David Cole <40234707+DavidArthurCole@users.noreply.github.com> Date: Fri, 21 Feb 2025 21:54:49 -0500 Subject: [PATCH 83/91] Improvements --- .../skyhanni/utils/renderables/Renderable.kt | 86 +++++++++++-------- 1 file changed, 50 insertions(+), 36 deletions(-) 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 60f41a303957..4b2ddf179baf 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt @@ -1694,41 +1694,45 @@ interface Renderable { class CircularRenderable( private val backgroundColor: Color, private val radius: Int, - // Optional border; if provided, its render() is called first. private val border: CircularRenderable? = null, - // Optional ItemStack to render on top of the circle. private val itemStack: ItemStack? = null, - // Scale for the item rendering. - private val itemScale: Double = 1.0 + private val itemScale: Double = 1.0, + private val filledPercentage: Int = 100, + private val unfilledColor: Color = Color.LIGHT_GRAY, ) : Renderable { - // The bounding box is a square of side length 2 * radius. + companion object { + // How many segments to use when drawing the circle. + private const val SEGMENT_COUNT: Int = 400 + } + override val width: Int = radius * 2 override val height: Int = radius * 2 override val horizontalAlign = HorizontalAlignment.LEFT override val verticalAlign = VerticalAlignment.TOP override fun render(posX: Int, posY: Int) { - // Render the border (if any) first. border?.render(posX, posY) - val centerX = posX + radius - val centerY = posY + radius - drawFilledCircle(centerX, centerY, radius, backgroundColor) - - val itemStack = itemStack ?: return - // Use an approximate size for the item icon (you can adjust these values). - val itemWidth = (15.5 * itemScale).toInt() - val itemHeight = (15.5 * itemScale).toInt() - // Compute the top-left coordinates to center the item. - val itemX = centerX - itemWidth / 2 - val itemY = centerY - itemHeight / 2 - - GL11.glPushMatrix() - // Translate so that (0,0) is where the item should be rendered. - GL11.glTranslatef(itemX.toFloat(), itemY.toFloat(), 0f) - // Render the item at (0,0) now. - itemStack.renderOnScreen(0f, 0f, scaleMultiplier = itemScale, rescaleSkulls = true) + GlStateManager.pushMatrix() + GlStateManager.translate(posX.toFloat(), posY.toFloat(), 0f) + GlStateManager.translate(0f, 0f, 100f) + + drawFilledCircle(radius, radius, radius, backgroundColor) + + itemStack?.let { stack -> + val itemWidth = (15.5 * itemScale).toInt() + val itemHeight = (15.5 * itemScale).toInt() + val itemX = radius - itemWidth / 2 + val itemY = radius - itemHeight / 2 + + GL11.glPushMatrix() + // Translate so that (0,0) is where the item should be rendered. + GL11.glTranslatef(itemX.toFloat(), itemY.toFloat(), 0f) + stack.renderOnScreen(0f, 0f, scaleMultiplier = itemScale, rescaleSkulls = true) + GL11.glPopMatrix() + } + GL11.glPopMatrix() } @@ -1741,31 +1745,41 @@ interface Renderable { * @param color The fill color. */ private fun drawFilledCircle(cx: Int, cy: Int, radius: Int, color: Color) { - GL11.glPushMatrix() - GL11.glEnable(GL11.GL_BLEND) - GL11.glDisable(GL11.GL_TEXTURE_2D) - // Set the desired color. - GL11.glColor4f( + GlStateManager.pushMatrix() + GlStateManager.disableTexture2D() + GlStateManager.enableBlend() + GlStateManager.tryBlendFuncSeparate( + GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO + ) + GlStateManager.color( color.red / 255f, color.green / 255f, color.blue / 255f, color.alpha / 255f ) + var doneFilling = false + val fillSegmentCount = (filledPercentage / 100.0 * SEGMENT_COUNT).toInt() GL11.glBegin(GL11.GL_TRIANGLE_FAN) - // Center vertex. GL11.glVertex2f(cx.toFloat(), cy.toFloat()) - // Draw circle segments. - val segments = 100 - for (i in 0..segments) { - val angle = (2.0 * Math.PI * i / segments).toFloat() + for (i in 0..SEGMENT_COUNT) { + val angle = (2.0 * Math.PI * i / SEGMENT_COUNT).toFloat() val x = cx + (cos(angle) * radius).toInt() val y = cy + (sin(angle) * radius).toInt() GL11.glVertex2f(x.toFloat(), y.toFloat()) + if (i == fillSegmentCount && !doneFilling) { + doneFilling = true + GlStateManager.color( + unfilledColor.red / 255f, + unfilledColor.green / 255f, + unfilledColor.blue / 255f, + unfilledColor.alpha / 255f + ) + } } GL11.glEnd() - GL11.glEnable(GL11.GL_TEXTURE_2D) - GL11.glDisable(GL11.GL_BLEND) - GL11.glPopMatrix() + GlStateManager.disableBlend() + GlStateManager.enableTexture2D() + GlStateManager.popMatrix() } } } From b8999bd70544ff845e2b19fab75fb7c7756e10aa Mon Sep 17 00:00:00 2001 From: David Cole <40234707+DavidArthurCole@users.noreply.github.com> Date: Fri, 21 Feb 2025 22:00:59 -0500 Subject: [PATCH 84/91] :( --- .../java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt | 1 - 1 file changed, 1 deletion(-) 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 4b2ddf179baf..0c2da4c7e615 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt @@ -1716,7 +1716,6 @@ interface Renderable { GlStateManager.pushMatrix() GlStateManager.translate(posX.toFloat(), posY.toFloat(), 0f) - GlStateManager.translate(0f, 0f, 100f) drawFilledCircle(radius, radius, radius, backgroundColor) From ec7cb596f1a2ca014b53bbe506335a5f8c3b5c55 Mon Sep 17 00:00:00 2001 From: David Cole <40234707+DavidArthurCole@users.noreply.github.com> Date: Fri, 21 Feb 2025 23:15:49 -0500 Subject: [PATCH 85/91] More progress --- .../hannibal2/skyhanni/api/CurrentPetApi.kt | 34 ++++++---- .../skyhanni/config/ConfigUpdaterMigrator.kt | 2 +- .../config/features/misc/pets/PetConfig.java | 16 +---- .../features/misc/pets/PetDisplayConfig.kt | 25 +++++++ .../at/hannibal2/skyhanni/data/PetData.kt | 16 +++++ .../features/misc/pets/CurrentPetDisplay.kt | 20 ++++-- .../at/hannibal2/skyhanni/utils/PetUtils.kt | 68 ++++++++----------- .../skyhanni/utils/renderables/Renderable.kt | 21 +++--- 8 files changed, 121 insertions(+), 81 deletions(-) create mode 100644 src/main/java/at/hannibal2/skyhanni/config/features/misc/pets/PetDisplayConfig.kt diff --git a/src/main/java/at/hannibal2/skyhanni/api/CurrentPetApi.kt b/src/main/java/at/hannibal2/skyhanni/api/CurrentPetApi.kt index 4596aa3c25ab..1e682775f23e 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/CurrentPetApi.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/CurrentPetApi.kt @@ -224,12 +224,13 @@ object CurrentPetApi { private fun handleWidgetPetLine(line: String): PetData? = petWidgetPattern.matchMatcher(line) { val rarity = rarityByColorGroup(group("rarity")) val petName = groupOrNull("name").orEmpty() + val petInternalName = petNameToInternalName(petName, rarity) val level = groupOrNull("level")?.toInt() ?: 0 - val xp = levelToXp(level, rarity, petName) ?: return null + val xp = levelToXp(level, petInternalName) ?: return null val skinColor = groupOrNull("skin")?.substring(1, 2)?.get(0)?.toLorenzColor() return PetData( - petItem = petNameToInternalName(petName, rarity), + petItem = petInternalName, heldItem = null, cleanName = petName, rarity = rarity, @@ -273,13 +274,14 @@ object CurrentPetApi { val level = group("level").toInt() val rarity = rarityByColorGroup(group("rarity")) val petName = group("pet") + val petInternalName = petNameToInternalName(petName, rarity) return PetData( - petItem = petNameToInternalName(petName, rarity), + petItem = petInternalName, cleanName = petName, rarity = rarity, level = level, - xp = levelToXp(level, rarity, petName) ?: 0.0, + xp = levelToXp(level, petInternalName) ?: 0.0, ) } @@ -289,38 +291,40 @@ object CurrentPetApi { // // - private fun extractSelectedPetData(lore: List): Triple? { + private fun extractSelectedPetData(lore: List): Triple? { val level = inventorySelectedProgressPattern.firstMatchGroup(lore, "level")?.toInt() val rarity = inventorySelectedPetPattern.firstMatchGroup(lore, "rarity")?.let { rarityByColorGroup(it) } val petName = inventorySelectedPetPattern.firstMatchGroup(lore, "pet") + val petInternalName = petName?.let { + petNameToInternalName(it, rarity ?: return null) + } - return if (level != null && rarity != null && petName != null) { - Triple(level, rarity, petName) + return if (level != null && rarity != null && petInternalName != null) { + Triple(level, rarity, petInternalName) } else null } private fun handleSelectedPetName(lore: List): NeuInternalName? = inventorySelectedPetPattern.firstMatcher(lore) { - val (_, rarity, petName) = extractSelectedPetData(lore) ?: return null - petNameToInternalName(petName, rarity) + val (_, _, petInternalName) = extractSelectedPetData(lore) ?: return null + petInternalName } private fun handleSelectedPetOverflowXp(lore: List): Double? { // Only have overflow if `next` group is absent if (inventorySelectedXpPattern.firstMatchGroup(lore, "next") != null) return 0.0 - val (level, rarity, petName) = extractSelectedPetData(lore) ?: return null - val maxXpNeeded = levelToXp(level, rarity, petName) + val (level, _, petInternalName) = extractSelectedPetData(lore) ?: return null + val maxXpNeeded = levelToXp(level, petInternalName) val currentXp = inventorySelectedXpPattern.firstMatchGroup(lore, "current")?.formatDouble() ?: 0.0 return maxXpNeeded?.minus(currentXp) ?: 0.0 } private fun handleSelectedPetData(lore: List): PetData? { - val (level, rarity, petName) = extractSelectedPetData(lore) ?: return null + val (level, rarity, petInternalName) = extractSelectedPetData(lore) ?: return null val partialXp = inventorySelectedXpPattern.firstMatchGroup(lore, "current")?.formatDouble() ?: 0.0 val nextExists = inventorySelectedXpPattern.firstMatchGroup(lore, "next") != null - val totalXp = partialXp + if (nextExists) (levelToXp(level, rarity, petName) ?: return null) else 0.0 + val totalXp = partialXp + if (nextExists) (levelToXp(level, petInternalName) ?: return null) else 0.0 return PetData( - petItem = petNameToInternalName(petName, rarity), - cleanName = petName, + petItem = petInternalName, rarity = rarity, heldItem = null, level = level, diff --git a/src/main/java/at/hannibal2/skyhanni/config/ConfigUpdaterMigrator.kt b/src/main/java/at/hannibal2/skyhanni/config/ConfigUpdaterMigrator.kt index e4b38806a695..29a1b768861d 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/ConfigUpdaterMigrator.kt +++ b/src/main/java/at/hannibal2/skyhanni/config/ConfigUpdaterMigrator.kt @@ -12,7 +12,7 @@ import com.google.gson.JsonPrimitive object ConfigUpdaterMigrator { val logger = LorenzLogger("ConfigMigration") - const val CONFIG_VERSION = 74 + const val CONFIG_VERSION = 75 fun JsonElement.at(chain: List, init: Boolean): JsonElement? { if (chain.isEmpty()) return this if (this !is JsonObject) return null diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/misc/pets/PetConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/misc/pets/PetConfig.java index 5314956cde25..d2a5236dfd24 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/misc/pets/PetConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/misc/pets/PetConfig.java @@ -16,19 +16,9 @@ public class PetConfig { @Expose - @ConfigOption(name = "Pet Display", desc = "Show the currently active pet.") - @ConfigEditorBoolean - @FeatureToggle - public boolean display = false; - - @Expose - @ConfigOption(name = "Rarity Circle", desc = "Display a circle around the pet icon based on rarity.") - @ConfigEditorBoolean - public boolean rarityCircle = true; - - @Expose - @ConfigLink(owner = PetConfig.class, field = "display") - public Position displayPos = new Position(-330, -15, false, true); + @ConfigOption(name = "Pet Display", desc = "") + @Accordion + public PetDisplayConfig display = new PetDisplayConfig(); @Expose @ConfigOption(name = "Pet Experience Tooltip", desc = "") diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/misc/pets/PetDisplayConfig.kt b/src/main/java/at/hannibal2/skyhanni/config/features/misc/pets/PetDisplayConfig.kt new file mode 100644 index 000000000000..e11aace129bf --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/misc/pets/PetDisplayConfig.kt @@ -0,0 +1,25 @@ +package at.hannibal2.skyhanni.config.features.misc.pets + +import at.hannibal2.skyhanni.config.FeatureToggle +import at.hannibal2.skyhanni.config.core.config.Position +import com.google.gson.annotations.Expose +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean +import io.github.notenoughupdates.moulconfig.annotations.ConfigLink +import io.github.notenoughupdates.moulconfig.annotations.ConfigOption + +class PetDisplayConfig { + @Expose + @ConfigOption(name = "Enabled", desc = "Show the currently active pet.") + @ConfigEditorBoolean + @FeatureToggle + var enabled: Boolean = false + + @Expose + @ConfigLink(owner = PetDisplayConfig::class, field = "enabled") + var position: Position = Position(-330, -15, false, true) + + @Expose + @ConfigOption(name = "Level Ring", desc = "Show a ring to indicate level progression.") + @ConfigEditorBoolean + var levelRing: Boolean = true +} diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetData.kt b/src/main/java/at/hannibal2/skyhanni/data/PetData.kt index 15f60d367d60..adf86ded9edb 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetData.kt @@ -10,7 +10,9 @@ import at.hannibal2.skyhanni.utils.LorenzRarity import at.hannibal2.skyhanni.utils.NeuInternalName import at.hannibal2.skyhanni.utils.NeuInternalName.Companion.toInternalName import at.hannibal2.skyhanni.utils.NeuItems.getItemStackOrNull +import at.hannibal2.skyhanni.utils.PetUtils import at.hannibal2.skyhanni.utils.PetUtils.getSkinOrNull +import at.hannibal2.skyhanni.utils.PetUtils.levelToXp import at.hannibal2.skyhanni.utils.PetUtils.xpToLevel import at.hannibal2.skyhanni.utils.RegexUtils.anyMatches import at.hannibal2.skyhanni.utils.SkyBlockItemModifierUtils.getExtraAttributes @@ -34,6 +36,20 @@ data class PetData( val formattedName = "${rarity?.chatColorCode}$cleanName" val skin: NeuPetSkinJson? = getSkinOrNull() + val levelProgressionPercentage: Double? = when { + xp == null -> null + level == null -> null + petItem == null -> null + PetUtils.isValidLevel(level + 1, petItem) -> { + val currentLevelXp = levelToXp(level, petItem) ?: 0.0 + val nextLevelXp = levelToXp(level + 1, petItem) ?: 0.0 + val xpDifference = nextLevelXp - currentLevelXp + val xpProgress = xp - currentLevelXp + xpProgress / xpDifference * 100 + } + else -> 100.0 + } + @Expose var skinInternalName: NeuInternalName? = skinInternalNameOverride ?: skin?.internalName // Please god only use this for UI, not for comparisons diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt index 6d224b3d3c20..00495bcdefb1 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt @@ -15,11 +15,11 @@ import java.awt.Color @SkyHanniModule object CurrentPetDisplay { - private val config get() = SkyHanniMod.feature.misc.pets + private val config get() = SkyHanniMod.feature.misc.pets.display @HandleEvent(onlyOnSkyblock = true) fun onRenderOverlay(event: GuiRenderEvent.GuiOverlayRenderEvent) { - if (RiftApi.inRift() || !config.display) return + if (RiftApi.inRift() || !config.enabled) return val currentPet = CurrentPetApi.currentPet ?: return val displayName = currentPet.getUserFriendlyName(includeLevel = false) @@ -29,9 +29,17 @@ object CurrentPetDisplay { val nameRender = Renderable.string(displayName, color = rarityColor.toColor()) val circle = Renderable.CircularRenderable( rarityColor.toColor(), - 50, + 25, itemStack = itemStack, - border = Renderable.CircularRenderable(Color.LIGHT_GRAY, 65) + border = Renderable.CircularRenderable( + Color.LIGHT_GRAY, + 30, + border = if (config.levelRing) Renderable.CircularRenderable( + backgroundColor = Color.BLUE, + radius = 32, + filledPercentage = currentPet.levelProgressionPercentage ?: 0.0 + ) else null + ) ) val container = Renderable.verticalContainer( @@ -39,12 +47,14 @@ object CurrentPetDisplay { horizontalAlign = RenderUtils.HorizontalAlignment.CENTER, ) - config.displayPos.renderRenderable(container, posLabel = "Current Pet") + config.position.renderRenderable(container, posLabel = "Current Pet") } @HandleEvent fun onConfigFix(event: ConfigUpdaterMigrator.ConfigFixEvent) { event.move(3, "misc.petDisplay", "misc.pets.display") event.move(9, "misc.petDisplayPos", "misc.pets.displayPos") + event.move(75, "misc.pets.display", "misc.pets.display.enabled") + event.move(75, "misc.pets.displayPos", "misc.pets.display.pos") } } diff --git a/src/main/java/at/hannibal2/skyhanni/utils/PetUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/PetUtils.kt index 0d7be80668a2..237bbd02c3d9 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/PetUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/PetUtils.kt @@ -6,6 +6,7 @@ import at.hannibal2.skyhanni.config.commands.CommandCategory import at.hannibal2.skyhanni.config.commands.CommandRegistrationEvent import at.hannibal2.skyhanni.data.PetData import at.hannibal2.skyhanni.data.PetData.Companion.internalNameToPetName +import at.hannibal2.skyhanni.data.PetData.Companion.petNameToInternalName import at.hannibal2.skyhanni.data.jsonobjects.repo.NEUPetData import at.hannibal2.skyhanni.data.jsonobjects.repo.NEUPetsJson import at.hannibal2.skyhanni.data.jsonobjects.repo.neu.NeuPetSkinJson @@ -29,7 +30,7 @@ object PetUtils { private val petSkins = mutableMapOf>() private var baseXpLevelReqs: List = listOf() - private var customXpLevelReqs: Map? = null + private var customXpLevelReqs: Map? = null // /** @@ -136,7 +137,9 @@ object PetUtils { } val petName = input.slice(2..= level } - private fun getCustomLeveling(petName: String): List { - return customXpLevelReqs?.get(petName)?.petLevels.orEmpty() + private fun getCustomLeveling(petInternalName: NeuInternalName): List { + return customXpLevelReqs?.get(petInternalName)?.petLevels.orEmpty() } - private fun getRarityOffset(rarity: LorenzRarity, petName: String): Int? { + private fun getRarityOffset(petInternalName: NeuInternalName): Int { val petsData = customXpLevelReqs ?: run { ErrorManager.skyHanniError("NEUPetsData is null") } - return if (petName in petsData.keys) { - val petData = petsData[petName] - petData?.rarityOffset?.get(rarity) - } else { - when (rarity) { - LorenzRarity.COMMON -> 0 - LorenzRarity.UNCOMMON -> 6 - LorenzRarity.RARE -> 11 - LorenzRarity.EPIC -> 16 - LorenzRarity.LEGENDARY -> 20 - LorenzRarity.MYTHIC -> 20 - else -> { - ChatUtils.userError("Invalid Rarity \"${rarity.name}\"") - null - } + val (_, rarity) = internalNameToPetName(petInternalName) ?: run { + ErrorManager.skyHanniError("Invalid Pet Internal Name \"$petInternalName\"") + } + + return petsData[petInternalName]?.rarityOffset?.get(rarity) ?: when (rarity) { + LorenzRarity.COMMON -> 0 + LorenzRarity.UNCOMMON -> 6 + LorenzRarity.RARE -> 11 + LorenzRarity.EPIC -> 16 + LorenzRarity.LEGENDARY -> 20 + LorenzRarity.MYTHIC -> 20 + else -> { + ErrorManager.skyHanniError("Invalid Rarity \"${rarity.name}\"") } } } @@ -225,7 +217,7 @@ object PetUtils { fun onNeuRepoReload(event: NeuRepositoryReloadEvent) { val data = event.getConstant("pets") baseXpLevelReqs = data.petLevels - customXpLevelReqs = data.customPetLeveling + customXpLevelReqs = data.customPetLeveling.mapKeys { it.key.toInternalName() } NeuItems.allNeuRepoItems().forEach { (rawInternalName, jsonObject) -> petSkinNamePattern.matchMatcher(rawInternalName) { 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 0c2da4c7e615..bf3eab57c94e 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt @@ -1696,18 +1696,19 @@ interface Renderable { private val radius: Int, private val border: CircularRenderable? = null, private val itemStack: ItemStack? = null, - private val itemScale: Double = 1.0, - private val filledPercentage: Int = 100, + private val itemScale: Double = 2.0, + private val filledPercentage: Double = 100.0, private val unfilledColor: Color = Color.LIGHT_GRAY, ) : Renderable { + private val totalRadius: Int = max(radius, border?.totalRadius ?: 0) companion object { // How many segments to use when drawing the circle. - private const val SEGMENT_COUNT: Int = 400 + private const val SEGMENT_COUNT: Int = 1000 } - override val width: Int = radius * 2 - override val height: Int = radius * 2 + override val width: Int = totalRadius * 2 + override val height: Int = totalRadius * 2 override val horizontalAlign = HorizontalAlignment.LEFT override val verticalAlign = VerticalAlignment.TOP @@ -1717,13 +1718,13 @@ interface Renderable { GlStateManager.pushMatrix() GlStateManager.translate(posX.toFloat(), posY.toFloat(), 0f) - drawFilledCircle(radius, radius, radius, backgroundColor) + drawFilledCircle(totalRadius, totalRadius, radius, backgroundColor) itemStack?.let { stack -> val itemWidth = (15.5 * itemScale).toInt() val itemHeight = (15.5 * itemScale).toInt() - val itemX = radius - itemWidth / 2 - val itemY = radius - itemHeight / 2 + val itemX = totalRadius - itemWidth / 2 + val itemY = totalRadius - itemHeight / 2 GL11.glPushMatrix() // Translate so that (0,0) is where the item should be rendered. @@ -1744,6 +1745,7 @@ interface Renderable { * @param color The fill color. */ private fun drawFilledCircle(cx: Int, cy: Int, radius: Int, color: Color) { + GlStateManager.disableCull() GlStateManager.pushMatrix() GlStateManager.disableTexture2D() GlStateManager.enableBlend() @@ -1765,7 +1767,7 @@ interface Renderable { val x = cx + (cos(angle) * radius).toInt() val y = cy + (sin(angle) * radius).toInt() GL11.glVertex2f(x.toFloat(), y.toFloat()) - if (i == fillSegmentCount && !doneFilling) { + if (i != SEGMENT_COUNT && i == fillSegmentCount && !doneFilling) { doneFilling = true GlStateManager.color( unfilledColor.red / 255f, @@ -1779,6 +1781,7 @@ interface Renderable { GlStateManager.disableBlend() GlStateManager.enableTexture2D() GlStateManager.popMatrix() + GlStateManager.enableCull() } } } From f4bb6ddf7d042ed2fc88942104935934af7358aa Mon Sep 17 00:00:00 2001 From: David Cole <40234707+DavidArthurCole@users.noreply.github.com> Date: Sat, 22 Feb 2025 00:56:37 -0500 Subject: [PATCH 86/91] Fixes --- .../hannibal2/skyhanni/api/CurrentPetApi.kt | 25 +++++----- .../config/storage/ProfileSpecificStorage.kt | 4 +- .../at/hannibal2/skyhanni/data/PetData.kt | 49 ++++++++++++++++--- .../features/misc/pets/CurrentPetDisplay.kt | 4 +- 4 files changed, 57 insertions(+), 25 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/api/CurrentPetApi.kt b/src/main/java/at/hannibal2/skyhanni/api/CurrentPetApi.kt index 1e682775f23e..77dcd4cf6578 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/CurrentPetApi.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/CurrentPetApi.kt @@ -7,6 +7,7 @@ import at.hannibal2.skyhanni.data.PetData.Companion.parsePetAsItem import at.hannibal2.skyhanni.data.PetData.Companion.parsePetData import at.hannibal2.skyhanni.data.PetData.Companion.parsePetDataLists import at.hannibal2.skyhanni.data.PetData.Companion.petNameToInternalName +import at.hannibal2.skyhanni.data.PetDataStorage import at.hannibal2.skyhanni.data.ProfileStorageData import at.hannibal2.skyhanni.data.model.TabWidget import at.hannibal2.skyhanni.events.DebugDataCollectEvent @@ -22,7 +23,6 @@ import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.ItemCategory import at.hannibal2.skyhanni.utils.ItemUtils.getItemCategoryOrNull import at.hannibal2.skyhanni.utils.ItemUtils.getLore -import at.hannibal2.skyhanni.utils.LorenzColor import at.hannibal2.skyhanni.utils.LorenzColor.Companion.toLorenzColor import at.hannibal2.skyhanni.utils.LorenzRarity import at.hannibal2.skyhanni.utils.NeuInternalName @@ -30,6 +30,7 @@ import at.hannibal2.skyhanni.utils.NumberUtil.formatDouble import at.hannibal2.skyhanni.utils.PetUtils.isPetMenu import at.hannibal2.skyhanni.utils.PetUtils.levelToXp import at.hannibal2.skyhanni.utils.PetUtils.rarityByColorGroup +import at.hannibal2.skyhanni.utils.Quad import at.hannibal2.skyhanni.utils.RegexUtils.firstMatchGroup import at.hannibal2.skyhanni.utils.RegexUtils.firstMatcher import at.hannibal2.skyhanni.utils.RegexUtils.firstMatches @@ -50,9 +51,9 @@ object CurrentPetApi { private var lastPetLine: String? = null var currentPet: PetData? - get() = ProfileStorageData.profileSpecific?.currentPetData?.takeIf { it.isInitialized() } + get() = ProfileStorageData.profileSpecific?.currentPetData?.toPetData()?.takeIf { it.isInitialized() } set(value) { - ProfileStorageData.profileSpecific?.currentPetData = value ?: PetData() + ProfileStorageData.profileSpecific?.currentPetData = value?.asStorage() ?: PetDataStorage() } fun isCurrentPet(petName: String): Boolean = currentPet?.cleanName?.contains(petName) ?: false @@ -291,7 +292,7 @@ object CurrentPetApi { // // - private fun extractSelectedPetData(lore: List): Triple? { + private fun extractSelectedPetData(lore: List): Quad? { val level = inventorySelectedProgressPattern.firstMatchGroup(lore, "level")?.toInt() val rarity = inventorySelectedPetPattern.firstMatchGroup(lore, "rarity")?.let { rarityByColorGroup(it) } val petName = inventorySelectedPetPattern.firstMatchGroup(lore, "pet") @@ -300,31 +301,31 @@ object CurrentPetApi { } return if (level != null && rarity != null && petInternalName != null) { - Triple(level, rarity, petInternalName) + Quad(level, rarity, petInternalName, petName) } else null } private fun handleSelectedPetName(lore: List): NeuInternalName? = inventorySelectedPetPattern.firstMatcher(lore) { - val (_, _, petInternalName) = extractSelectedPetData(lore) ?: return null - petInternalName + extractSelectedPetData(lore)?.third ?: return null } private fun handleSelectedPetOverflowXp(lore: List): Double? { // Only have overflow if `next` group is absent if (inventorySelectedXpPattern.firstMatchGroup(lore, "next") != null) return 0.0 - val (level, _, petInternalName) = extractSelectedPetData(lore) ?: return null + val (level, _, petInternalName, _) = extractSelectedPetData(lore) ?: return null val maxXpNeeded = levelToXp(level, petInternalName) val currentXp = inventorySelectedXpPattern.firstMatchGroup(lore, "current")?.formatDouble() ?: 0.0 return maxXpNeeded?.minus(currentXp) ?: 0.0 } private fun handleSelectedPetData(lore: List): PetData? { - val (level, rarity, petInternalName) = extractSelectedPetData(lore) ?: return null + val (level, rarity, petInternalName, petName) = extractSelectedPetData(lore) ?: return null val partialXp = inventorySelectedXpPattern.firstMatchGroup(lore, "current")?.formatDouble() ?: 0.0 val nextExists = inventorySelectedXpPattern.firstMatchGroup(lore, "next") != null val totalXp = partialXp + if (nextExists) (levelToXp(level, petInternalName) ?: return null) else 0.0 return PetData( petItem = petInternalName, + cleanName = petName, rarity = rarity, heldItem = null, level = level, @@ -385,10 +386,8 @@ object CurrentPetApi { updatePet(petData.copy(xp = petData.xp?.plus(overflowXp))) } - @HandleEvent - fun onInventoryClose(event: InventoryCloseEvent) { - inPetMenu = false - } + @HandleEvent(InventoryCloseEvent::class) + fun onInventoryClose() { inPetMenu = false } @HandleEvent fun onSlotClick(event: GuiContainerEvent.SlotClickEvent) { diff --git a/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.kt b/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.kt index baf0eafcfabd..7ae6eda9cb05 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.kt +++ b/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.kt @@ -4,7 +4,7 @@ import at.hannibal2.skyhanni.api.HotmApi.PowderType import at.hannibal2.skyhanni.api.SkillApi import at.hannibal2.skyhanni.data.IslandType import at.hannibal2.skyhanni.data.MaxwellApi.ThaumaturgyPowerTuning -import at.hannibal2.skyhanni.data.PetData +import at.hannibal2.skyhanni.data.PetDataStorage import at.hannibal2.skyhanni.data.jsonobjects.local.HotmTree import at.hannibal2.skyhanni.data.model.ComposterUpgrade import at.hannibal2.skyhanni.data.model.SkyblockStat @@ -755,7 +755,7 @@ class ProfileSpecificStorage { // data @Expose - var currentPetData: PetData = PetData() + var currentPetData: PetDataStorage = PetDataStorage() @Expose var stats: MutableMap = enumMapOf() diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetData.kt b/src/main/java/at/hannibal2/skyhanni/data/PetData.kt index adf86ded9edb..6ecbfe41a631 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetData.kt @@ -22,15 +22,37 @@ import com.google.gson.Gson import com.google.gson.annotations.Expose import net.minecraft.item.ItemStack +data class PetDataStorage( + @Expose var petItem: NeuInternalName? = null, // The internal name of the pet, e.g., `RABBIT;5` + @Expose var heldItem: NeuInternalName? = null, // The held item of the pet, e.g., `PET_ITEM_COMBAT_SKILL_BOOST_EPIC` + @Expose var cleanName: String? = null, // The clean name of the pet, e.g., `Rabbit` + @Expose var skinSymbolColor: LorenzColor? = null, // The color symbol of the skin of the pet, e.g., §d ✦ -> `LorenzColor.Pink` + @Expose var rarity: LorenzRarity? = null, // The rarity of the pet, e.g., `COMMON` + @Expose var level: Int? = null, // The current level of the pet as an integer, e.g., `100` + @Expose var xp: Double? = null, // The total XP of the pet as a double, e.g., `0.0` + @Expose var skinInternalNameOverride: NeuInternalName? = null, // If the skin is known (i.e., from stored data or Inventory) +) { + fun toPetData(): PetData = PetData( + petItem = petItem, + heldItem = heldItem, + cleanName = cleanName, + skinSymbolColor = skinSymbolColor, + rarity = rarity, + level = level, + xp = xp, + skinInternalNameOverride = skinInternalNameOverride, + ) +} + data class PetData( - @Expose val petItem: NeuInternalName? = null, // The internal name of the pet, e.g., `RABBIT;5` - @Expose val heldItem: NeuInternalName? = null, // The held item of the pet, e.g., `PET_ITEM_COMBAT_SKILL_BOOST_EPIC` - @Expose val cleanName: String? = null, // The clean name of the pet, e.g., `Rabbit` - @Expose val skinSymbolColor: LorenzColor? = null, // The color symbol of the skin of the pet, e.g., §d ✦ -> `LorenzColor.Pink` - @Expose val rarity: LorenzRarity? = null, // The rarity of the pet, e.g., `COMMON` - @Expose val level: Int? = null, // The current level of the pet as an integer, e.g., `100` - @Expose val xp: Double? = null, // The total XP of the pet as a double, e.g., `0.0` - @Expose val skinInternalNameOverride: NeuInternalName? = null, // If the skin is known (i.e., from stored data or Inventory) + val petItem: NeuInternalName? = null, + val heldItem: NeuInternalName? = null, + val cleanName: String? = null, + val skinSymbolColor: LorenzColor? = null, + val rarity: LorenzRarity? = null, + val level: Int? = null, + val xp: Double? = null, + val skinInternalNameOverride: NeuInternalName? = null, ) { val displayName = petItem?.itemName val formattedName = "${rarity?.chatColorCode}$cleanName" @@ -91,6 +113,17 @@ data class PetData( return petItem != null && cleanName != null && rarity != null && level != null && xp != null } + fun asStorage(): PetDataStorage = PetDataStorage( + petItem = petItem, + heldItem = heldItem, + cleanName = cleanName, + skinSymbolColor = skinSymbolColor, + rarity = rarity, + level = level, + xp = xp, + skinInternalNameOverride = skinInternalNameOverride, + ) + companion object { // fun parsePetData( diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt index 00495bcdefb1..a861eea57885 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt @@ -17,8 +17,8 @@ object CurrentPetDisplay { private val config get() = SkyHanniMod.feature.misc.pets.display - @HandleEvent(onlyOnSkyblock = true) - fun onRenderOverlay(event: GuiRenderEvent.GuiOverlayRenderEvent) { + @HandleEvent(GuiRenderEvent.GuiOverlayRenderEvent::class, onlyOnSkyblock = true) + fun onRenderOverlay() { if (RiftApi.inRift() || !config.enabled) return val currentPet = CurrentPetApi.currentPet ?: return From 66197d5cfdf2fbac7dc28ace5d98992b11dc6b39 Mon Sep 17 00:00:00 2001 From: David Cole <40234707+DavidArthurCole@users.noreply.github.com> Date: Sat, 22 Feb 2025 01:00:34 -0500 Subject: [PATCH 87/91] Fixes --- src/main/java/at/hannibal2/skyhanni/api/CurrentPetApi.kt | 7 +++---- .../skyhanni/data/jsonobjects/repo/neu/NeuPetSkinJson.kt | 2 -- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/api/CurrentPetApi.kt b/src/main/java/at/hannibal2/skyhanni/api/CurrentPetApi.kt index 77dcd4cf6578..94a12e7855b9 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/CurrentPetApi.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/CurrentPetApi.kt @@ -192,11 +192,10 @@ object CurrentPetApi { // // - private fun updatePet(eventNewPet: PetData?) { - val newPet = eventNewPet ?: return + private fun updatePet(newPet: PetData?) { val oldPet = currentPet if (newPet == oldPet) return - if (newPet.allButSkinEquivalent(oldPet)) { + if (newPet?.allButSkinEquivalent(oldPet) == true) { // If the two pets are the same except for the skin, we want to take the one that has the skin. // If they both have differing skins, we want to take the new one. if (oldPet?.skinInternalName != null && newPet.skinInternalName == null) return @@ -205,7 +204,7 @@ object CurrentPetApi { currentPet = newPet if (SkyHanniMod.feature.dev.debug.petEventMessages) { ChatUtils.debug("oldPet: " + oldPet.toString().convertToUnformatted()) - ChatUtils.debug("newPet: " + newPet?.toString()?.convertToUnformatted()) + ChatUtils.debug("newPet: " + newPet.toString().convertToUnformatted()) } PetChangeEvent(oldPet, newPet).post() } diff --git a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/neu/NeuPetSkinJson.kt b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/neu/NeuPetSkinJson.kt index ebad0256b9cf..cd83241875d9 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/neu/NeuPetSkinJson.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/neu/NeuPetSkinJson.kt @@ -7,8 +7,6 @@ import at.hannibal2.skyhanni.utils.ItemUtils.getSkullTexture import at.hannibal2.skyhanni.utils.LorenzRarity import at.hannibal2.skyhanni.utils.NeuInternalName.Companion.toInternalName import at.hannibal2.skyhanni.utils.RegexUtils.firstMatcher -import at.hannibal2.skyhanni.utils.RegexUtils.firstMatches -import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern.Companion.group import com.google.gson.annotations.Expose import com.google.gson.annotations.SerializedName import net.minecraft.nbt.CompressedStreamTools From ee76a0d952dd1fe15be56ec9a42f9ea92abe2c82 Mon Sep 17 00:00:00 2001 From: David Cole <40234707+DavidArthurCole@users.noreply.github.com> Date: Sat, 22 Feb 2025 01:04:56 -0500 Subject: [PATCH 88/91] Add smoothing --- .../at/hannibal2/skyhanni/utils/renderables/Renderable.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) 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 bf3eab57c94e..a0e81803228d 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt @@ -1760,12 +1760,14 @@ interface Renderable { ) var doneFilling = false val fillSegmentCount = (filledPercentage / 100.0 * SEGMENT_COUNT).toInt() + GL11.glEnable(GL11.GL_POLYGON_SMOOTH) + GL11.glHint(GL11.GL_POLYGON_SMOOTH_HINT, GL11.GL_NICEST) GL11.glBegin(GL11.GL_TRIANGLE_FAN) GL11.glVertex2f(cx.toFloat(), cy.toFloat()) for (i in 0..SEGMENT_COUNT) { val angle = (2.0 * Math.PI * i / SEGMENT_COUNT).toFloat() - val x = cx + (cos(angle) * radius).toInt() - val y = cy + (sin(angle) * radius).toInt() + val x = cx + cos(angle) * radius + val y = cy + sin(angle) * radius GL11.glVertex2f(x.toFloat(), y.toFloat()) if (i != SEGMENT_COUNT && i == fillSegmentCount && !doneFilling) { doneFilling = true @@ -1777,6 +1779,7 @@ interface Renderable { ) } } + GL11.glDisable(GL11.GL_POLYGON_SMOOTH) GL11.glEnd() GlStateManager.disableBlend() GlStateManager.enableTexture2D() From aad249361076c1f2af95943c457a61958dded43d Mon Sep 17 00:00:00 2001 From: Thunderblade73 <85900443+Thunderblade73@users.noreply.github.com> Date: Sat, 22 Feb 2025 07:13:21 +0100 Subject: [PATCH 89/91] better way --- .../hannibal2/skyhanni/shader/CircleShader.kt | 25 +++++++ .../hannibal2/skyhanni/utils/RenderUtils.kt | 38 +++++++++++ .../skyhanni/utils/renderables/Renderable.kt | 65 ++----------------- .../skyhanni/utils/shader/ShaderManager.kt | 4 +- .../assets/skyhanni/shaders/circle.fsh | 26 ++++++++ .../assets/skyhanni/shaders/circle.vsh | 8 +++ 6 files changed, 104 insertions(+), 62 deletions(-) create mode 100644 src/main/java/at/hannibal2/skyhanni/shader/CircleShader.kt create mode 100644 src/main/resources/assets/skyhanni/shaders/circle.fsh create mode 100644 src/main/resources/assets/skyhanni/shaders/circle.vsh diff --git a/src/main/java/at/hannibal2/skyhanni/shader/CircleShader.kt b/src/main/java/at/hannibal2/skyhanni/shader/CircleShader.kt new file mode 100644 index 000000000000..4056d3fb1f15 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/shader/CircleShader.kt @@ -0,0 +1,25 @@ +package at.hannibal2.skyhanni.shader + +import at.hannibal2.skyhanni.utils.shader.Shader +import at.hannibal2.skyhanni.utils.shader.Uniform +import net.minecraft.client.Minecraft + +object CircleShader : Shader("circle", "circle") { + + val INSTANCE get() = this + + var scaleFactor: Float = 0f + var radius: Float = 0f + var smoothness: Float = 0f + var centerPos: FloatArray = floatArrayOf(0f, 0f) + set(value) { + field = floatArrayOf(value[0], Minecraft.getMinecraft().displayHeight - value[1]) + } + + override fun registerUniforms() { + registerUniform(Uniform.UniformType.FLOAT, "scaleFactor") { scaleFactor } + registerUniform(Uniform.UniformType.FLOAT, "radius") { radius } + registerUniform(Uniform.UniformType.FLOAT, "smoothness") { smoothness } + registerUniform(Uniform.UniformType.VEC2, "centerPos") { centerPos } + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/utils/RenderUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/RenderUtils.kt index b389e6c80500..243d241d68ca 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/RenderUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/RenderUtils.kt @@ -13,11 +13,14 @@ import at.hannibal2.skyhanni.features.misc.PatcherFixes import at.hannibal2.skyhanni.features.misc.RoundedRectangleOutlineShader import at.hannibal2.skyhanni.features.misc.RoundedRectangleShader import at.hannibal2.skyhanni.features.misc.RoundedTextureShader +import at.hannibal2.skyhanni.shader.CircleShader import at.hannibal2.skyhanni.utils.CollectionUtils.zipWithNext3 +import at.hannibal2.skyhanni.utils.ColorUtils.addAlpha import at.hannibal2.skyhanni.utils.ColorUtils.getFirstColorCode import at.hannibal2.skyhanni.utils.LocationUtils.calculateEdges import at.hannibal2.skyhanni.utils.LorenzColor.Companion.toLorenzColor import at.hannibal2.skyhanni.utils.LorenzUtils.getCorners +import at.hannibal2.skyhanni.utils.RenderUtils.drawRoundRect import at.hannibal2.skyhanni.utils.compat.GuiScreenUtils import at.hannibal2.skyhanni.utils.renderables.Renderable import at.hannibal2.skyhanni.utils.renderables.RenderableUtils.renderXAligned @@ -1934,6 +1937,41 @@ object RenderUtils { GlStateManager.popMatrix() } + /** + * Method to draw a circle. + * + * **NOTE:** If you are using [GlStateManager.translate] or [GlStateManager.scale] + * with this method, ensure they are invoked in the correct order if you use both. That is, [GlStateManager.translate] + * is called **BEFORE** [GlStateManager.scale], otherwise the rectangle will not be rendered correctly + * + * @param x The x-coordinate of the circle's center. + * @param y The y-coordinate of the circle's center. + * @param radius The circle's radius. + * @param color The fill color. + * @param smoothness how smooth the corners will appear (default 1). NOTE: This does very + * little to the smoothness of the corners in reality due to how the final pixel color is calculated. + * It is best kept at its default. + */ + fun drawFilledCircle(x: Int, y: Int, radius: Int, color: Color, smoothness: Float = 0f) { + val scaleFactor = ScaledResolution(Minecraft.getMinecraft()).scaleFactor + val radiusIn = radius * scaleFactor + val xIn = x * scaleFactor + val yIn = y * scaleFactor + + CircleShader.scaleFactor = scaleFactor.toFloat() + CircleShader.radius = radiusIn.toFloat() + CircleShader.smoothness = smoothness.toFloat() + CircleShader.centerPos = floatArrayOf((xIn + radiusIn).toFloat(), (yIn + radiusIn).toFloat()) + + GlStateManager.pushMatrix() + ShaderManager.enableShader(ShaderManager.Shaders.CIRCLE) + + Gui.drawRect(x - 5, y - 5, x + radius * 2 + 5, y + radius * 2 + 5, color.addAlpha(100).rgb) + + ShaderManager.disableShader() + GlStateManager.popMatrix() + } + fun getAlpha(): Float { colorBuffer.clear() GlStateManager.getFloat(GL11.GL_CURRENT_COLOR, colorBuffer) 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 a0e81803228d..3322dbefc95c 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt @@ -26,6 +26,7 @@ import at.hannibal2.skyhanni.utils.NeuItems.renderOnScreen import at.hannibal2.skyhanni.utils.RenderUtils import at.hannibal2.skyhanni.utils.RenderUtils.HorizontalAlignment import at.hannibal2.skyhanni.utils.RenderUtils.VerticalAlignment +import at.hannibal2.skyhanni.utils.RenderUtils.drawFilledCircle import at.hannibal2.skyhanni.utils.compat.getTooltipCompat import at.hannibal2.skyhanni.utils.guide.GuideGUI import at.hannibal2.skyhanni.utils.renderables.Renderable.Companion.shouldAllowLink @@ -46,9 +47,7 @@ import net.minecraft.util.ResourceLocation import org.lwjgl.opengl.GL11 import java.awt.Color import java.util.Collections -import kotlin.math.cos import kotlin.math.max -import kotlin.math.sin interface Renderable { @@ -1702,13 +1701,8 @@ interface Renderable { ) : Renderable { private val totalRadius: Int = max(radius, border?.totalRadius ?: 0) - companion object { - // How many segments to use when drawing the circle. - private const val SEGMENT_COUNT: Int = 1000 - } - - override val width: Int = totalRadius * 2 - override val height: Int = totalRadius * 2 + override val width: Int = radius * 2 + override val height: Int = radius * 2 override val horizontalAlign = HorizontalAlignment.LEFT override val verticalAlign = VerticalAlignment.TOP @@ -1716,9 +1710,8 @@ interface Renderable { border?.render(posX, posY) GlStateManager.pushMatrix() - GlStateManager.translate(posX.toFloat(), posY.toFloat(), 0f) - drawFilledCircle(totalRadius, totalRadius, radius, backgroundColor) + drawFilledCircle(0, 0, radius, backgroundColor) itemStack?.let { stack -> val itemWidth = (15.5 * itemScale).toInt() @@ -1736,55 +1729,5 @@ interface Renderable { GL11.glPopMatrix() } - /** - * Draws a filled circle using OpenGL. - * - * @param cx The x-coordinate of the circle's center. - * @param cy The y-coordinate of the circle's center. - * @param radius The circle's radius. - * @param color The fill color. - */ - private fun drawFilledCircle(cx: Int, cy: Int, radius: Int, color: Color) { - GlStateManager.disableCull() - GlStateManager.pushMatrix() - GlStateManager.disableTexture2D() - GlStateManager.enableBlend() - GlStateManager.tryBlendFuncSeparate( - GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO - ) - GlStateManager.color( - color.red / 255f, - color.green / 255f, - color.blue / 255f, - color.alpha / 255f - ) - var doneFilling = false - val fillSegmentCount = (filledPercentage / 100.0 * SEGMENT_COUNT).toInt() - GL11.glEnable(GL11.GL_POLYGON_SMOOTH) - GL11.glHint(GL11.GL_POLYGON_SMOOTH_HINT, GL11.GL_NICEST) - GL11.glBegin(GL11.GL_TRIANGLE_FAN) - GL11.glVertex2f(cx.toFloat(), cy.toFloat()) - for (i in 0..SEGMENT_COUNT) { - val angle = (2.0 * Math.PI * i / SEGMENT_COUNT).toFloat() - val x = cx + cos(angle) * radius - val y = cy + sin(angle) * radius - GL11.glVertex2f(x.toFloat(), y.toFloat()) - if (i != SEGMENT_COUNT && i == fillSegmentCount && !doneFilling) { - doneFilling = true - GlStateManager.color( - unfilledColor.red / 255f, - unfilledColor.green / 255f, - unfilledColor.blue / 255f, - unfilledColor.alpha / 255f - ) - } - } - GL11.glDisable(GL11.GL_POLYGON_SMOOTH) - GL11.glEnd() - GlStateManager.disableBlend() - GlStateManager.enableTexture2D() - GlStateManager.popMatrix() - GlStateManager.enableCull() - } } } diff --git a/src/main/java/at/hannibal2/skyhanni/utils/shader/ShaderManager.kt b/src/main/java/at/hannibal2/skyhanni/utils/shader/ShaderManager.kt index ed4dbabdfe6c..b9a897b8ed64 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/shader/ShaderManager.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/shader/ShaderManager.kt @@ -6,6 +6,7 @@ import at.hannibal2.skyhanni.features.misc.DarkenShader import at.hannibal2.skyhanni.features.misc.RoundedRectangleOutlineShader import at.hannibal2.skyhanni.features.misc.RoundedRectangleShader import at.hannibal2.skyhanni.features.misc.RoundedTextureShader +import at.hannibal2.skyhanni.shader.CircleShader import at.hannibal2.skyhanni.test.command.ErrorManager import at.hannibal2.skyhanni.utils.LorenzUtils import net.minecraft.client.Minecraft @@ -30,7 +31,8 @@ object ShaderManager { ROUNDED_RECTANGLE(RoundedRectangleShader.INSTANCE), ROUNDED_RECT_OUTLINE(RoundedRectangleOutlineShader.INSTANCE), ROUNDED_TEXTURE(RoundedTextureShader.INSTANCE), - DARKEN(DarkenShader.INSTANCE) + DARKEN(DarkenShader.INSTANCE), + CIRCLE(CircleShader.INSTANCE), ; fun enableShader() = enableShader(this) diff --git a/src/main/resources/assets/skyhanni/shaders/circle.fsh b/src/main/resources/assets/skyhanni/shaders/circle.fsh new file mode 100644 index 000000000000..391ce6d2914d --- /dev/null +++ b/src/main/resources/assets/skyhanni/shaders/circle.fsh @@ -0,0 +1,26 @@ +#version 120 + +uniform float scaleFactor; +uniform float radius; +uniform float smoothness; +uniform vec2 centerPos; + +varying vec4 color; + +void main() { + float xScale = gl_ModelViewMatrix[0][0]; + float yScale = gl_ModelViewMatrix[1][1]; + float xTranslation = gl_ModelViewMatrix[3][0]; + float yTranslation = gl_ModelViewMatrix[3][1]; + + vec2 cords = vec2(gl_FragCoord.x, gl_FragCoord.y); + + vec2 newCenterPos = vec2((centerPos.x + (radius * (xScale - 1.0))) + (xTranslation * scaleFactor), (centerPos.y - (radius * (yScale - 1.0))) - (yTranslation * scaleFactor)); + + float newRadius = pow(radius * min(xScale,yScale),2.0); + + vec2 adjusted = cords - newCenterPos; + + float smoothed = 1.0 - smoothstep(newRadius - smoothness, newRadius, pow(adjusted.x, 2.0) + pow(adjusted.y, 2.0)); + gl_FragColor = color * vec4(1.0, 1.0, 1.0, smoothed); +} diff --git a/src/main/resources/assets/skyhanni/shaders/circle.vsh b/src/main/resources/assets/skyhanni/shaders/circle.vsh new file mode 100644 index 000000000000..acfb526629fd --- /dev/null +++ b/src/main/resources/assets/skyhanni/shaders/circle.vsh @@ -0,0 +1,8 @@ +#version 120 + +varying vec4 color; + +void main() { + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; + color = gl_Color; +} From 9abd715f38e2e0687809755fa078fc4f2fda8452 Mon Sep 17 00:00:00 2001 From: Thunderblade73 <85900443+Thunderblade73@users.noreply.github.com> Date: Sat, 22 Feb 2025 09:29:32 +0100 Subject: [PATCH 90/91] semicircle --- .../hannibal2/skyhanni/shader/CircleShader.kt | 4 ++++ .../hannibal2/skyhanni/utils/RenderUtils.kt | 13 ++++++----- .../skyhanni/utils/renderables/Renderable.kt | 19 +++++++-------- .../assets/skyhanni/shaders/circle.fsh | 23 ++++++++++++++++--- 4 files changed, 41 insertions(+), 18 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/shader/CircleShader.kt b/src/main/java/at/hannibal2/skyhanni/shader/CircleShader.kt index 4056d3fb1f15..b2721e82d932 100644 --- a/src/main/java/at/hannibal2/skyhanni/shader/CircleShader.kt +++ b/src/main/java/at/hannibal2/skyhanni/shader/CircleShader.kt @@ -15,11 +15,15 @@ object CircleShader : Shader("circle", "circle") { set(value) { field = floatArrayOf(value[0], Minecraft.getMinecraft().displayHeight - value[1]) } + var angle1: Float = 0f + var angle2: Float = 0f override fun registerUniforms() { registerUniform(Uniform.UniformType.FLOAT, "scaleFactor") { scaleFactor } registerUniform(Uniform.UniformType.FLOAT, "radius") { radius } registerUniform(Uniform.UniformType.FLOAT, "smoothness") { smoothness } + registerUniform(Uniform.UniformType.FLOAT, "angle1") { angle1 } + registerUniform(Uniform.UniformType.FLOAT, "angle2") { angle2 } registerUniform(Uniform.UniformType.VEC2, "centerPos") { centerPos } } } diff --git a/src/main/java/at/hannibal2/skyhanni/utils/RenderUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/RenderUtils.kt index 243d241d68ca..c5365a0dfccf 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/RenderUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/RenderUtils.kt @@ -15,7 +15,6 @@ import at.hannibal2.skyhanni.features.misc.RoundedRectangleShader import at.hannibal2.skyhanni.features.misc.RoundedTextureShader import at.hannibal2.skyhanni.shader.CircleShader import at.hannibal2.skyhanni.utils.CollectionUtils.zipWithNext3 -import at.hannibal2.skyhanni.utils.ColorUtils.addAlpha import at.hannibal2.skyhanni.utils.ColorUtils.getFirstColorCode import at.hannibal2.skyhanni.utils.LocationUtils.calculateEdges import at.hannibal2.skyhanni.utils.LorenzColor.Companion.toLorenzColor @@ -1948,11 +1947,11 @@ object RenderUtils { * @param y The y-coordinate of the circle's center. * @param radius The circle's radius. * @param color The fill color. - * @param smoothness how smooth the corners will appear (default 1). NOTE: This does very - * little to the smoothness of the corners in reality due to how the final pixel color is calculated. - * It is best kept at its default. + * @param angle1 defines the start of the semicircle (Default value makes it a full circle). Must be in range [0,2*pi] (0 is on the left and increases counterclockwise) + * @param angle2 defines the end of the semicircle (Default value makes it a full circle). Must be in range [0,2*pi] (0 is on the left and increases counterclockwise) + * @param smoothness smooths out the edge. (In amount of blurred pixels) */ - fun drawFilledCircle(x: Int, y: Int, radius: Int, color: Color, smoothness: Float = 0f) { + fun drawFilledCircle(x: Int, y: Int, radius: Int, color: Color, smoothness: Float = 2.5f, angle1: Float = 7.0f, angle2: Float = 7.0f) { val scaleFactor = ScaledResolution(Minecraft.getMinecraft()).scaleFactor val radiusIn = radius * scaleFactor val xIn = x * scaleFactor @@ -1962,11 +1961,13 @@ object RenderUtils { CircleShader.radius = radiusIn.toFloat() CircleShader.smoothness = smoothness.toFloat() CircleShader.centerPos = floatArrayOf((xIn + radiusIn).toFloat(), (yIn + radiusIn).toFloat()) + CircleShader.angle1 = angle1 - Math.PI.toFloat() + CircleShader.angle2 = angle2 - Math.PI.toFloat() GlStateManager.pushMatrix() ShaderManager.enableShader(ShaderManager.Shaders.CIRCLE) - Gui.drawRect(x - 5, y - 5, x + radius * 2 + 5, y + radius * 2 + 5, color.addAlpha(100).rgb) + Gui.drawRect(x - 5, y - 5, x + radius * 2 + 5, y + radius * 2 + 5, color.rgb) ShaderManager.disableShader() GlStateManager.popMatrix() 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 3322dbefc95c..b235a889799a 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt @@ -1700,6 +1700,7 @@ interface Renderable { private val unfilledColor: Color = Color.LIGHT_GRAY, ) : Renderable { private val totalRadius: Int = max(radius, border?.totalRadius ?: 0) + private val diffRadius: Int = totalRadius - radius override val width: Int = radius * 2 override val height: Int = radius * 2 @@ -1709,9 +1710,15 @@ interface Renderable { override fun render(posX: Int, posY: Int) { border?.render(posX, posY) - GlStateManager.pushMatrix() + if (filledPercentage < 100.0) { + val baseAngle = Math.PI.toFloat() * 3f / 2f + val endAngle = (baseAngle + ((100.0 - filledPercentage) / 50.0 * Math.PI).toFloat()).mod(2f * Math.PI.toFloat()) + drawFilledCircle(diffRadius, diffRadius, radius, backgroundColor, angle1 = baseAngle, angle2 = endAngle) + drawFilledCircle(diffRadius, diffRadius, radius, unfilledColor, angle1 = endAngle, angle2 = baseAngle) + } else { + drawFilledCircle(diffRadius, diffRadius, radius, backgroundColor) + } - drawFilledCircle(0, 0, radius, backgroundColor) itemStack?.let { stack -> val itemWidth = (15.5 * itemScale).toInt() @@ -1719,14 +1726,8 @@ interface Renderable { val itemX = totalRadius - itemWidth / 2 val itemY = totalRadius - itemHeight / 2 - GL11.glPushMatrix() - // Translate so that (0,0) is where the item should be rendered. - GL11.glTranslatef(itemX.toFloat(), itemY.toFloat(), 0f) - stack.renderOnScreen(0f, 0f, scaleMultiplier = itemScale, rescaleSkulls = true) - GL11.glPopMatrix() + stack.renderOnScreen(itemX.toFloat(), itemY.toFloat(), scaleMultiplier = itemScale, rescaleSkulls = true) } - - GL11.glPopMatrix() } } diff --git a/src/main/resources/assets/skyhanni/shaders/circle.fsh b/src/main/resources/assets/skyhanni/shaders/circle.fsh index 391ce6d2914d..64f9029a679f 100644 --- a/src/main/resources/assets/skyhanni/shaders/circle.fsh +++ b/src/main/resources/assets/skyhanni/shaders/circle.fsh @@ -1,9 +1,13 @@ #version 120 +const float pi = 3.1415926535897932384626433832795028841971693993751058209749445923078164062f; + uniform float scaleFactor; uniform float radius; uniform float smoothness; uniform vec2 centerPos; +uniform float angle1; +uniform float angle2; varying vec4 color; @@ -17,10 +21,23 @@ void main() { vec2 newCenterPos = vec2((centerPos.x + (radius * (xScale - 1.0))) + (xTranslation * scaleFactor), (centerPos.y - (radius * (yScale - 1.0))) - (yTranslation * scaleFactor)); - float newRadius = pow(radius * min(xScale,yScale),2.0); + float newRadius = radius * min(xScale,yScale); vec2 adjusted = cords - newCenterPos; - float smoothed = 1.0 - smoothstep(newRadius - smoothness, newRadius, pow(adjusted.x, 2.0) + pow(adjusted.y, 2.0)); - gl_FragColor = color * vec4(1.0, 1.0, 1.0, smoothed); + float smoothed = 1.0 - smoothstep(pow(newRadius - smoothness,2.0), pow(newRadius,2.0), pow(adjusted.x, 2.0) + pow(adjusted.y, 2.0)); + + float current = atan(adjusted.y,adjusted.x); + + float sanity = step(angle1,angle2); + + float lim1 = step(current,angle1); + float lim2 = step(angle2,current); + + float lim3 = step(angle1,current); + float lim4 = step(current,angle2); + + float lim = max(lim1,lim2)*sanity+(1.0-sanity)*(1.0-max(lim3,lim4)); + + gl_FragColor = color * vec4(1.0, 1.0, 1.0, smoothed*lim); } From 500793a3650f420fecb1879297d85469efc04146 Mon Sep 17 00:00:00 2001 From: David Cole <40234707+DavidArthurCole@users.noreply.github.com> Date: Sat, 22 Feb 2025 04:44:44 -0500 Subject: [PATCH 91/91] More progress --- .../hannibal2/skyhanni/api/CurrentPetApi.kt | 10 ++-- .../at/hannibal2/skyhanni/data/PetData.kt | 6 +- .../data/jsonobjects/repo/NEUPetsJson.kt | 1 + .../event/hoppity/MythicRabbitPetWarning.kt | 5 +- .../features/misc/pets/CurrentPetDisplay.kt | 12 ++-- .../at/hannibal2/skyhanni/utils/PetUtils.kt | 55 +++++-------------- .../skyhanni/utils/renderables/Renderable.kt | 10 ++-- 7 files changed, 36 insertions(+), 63 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/api/CurrentPetApi.kt b/src/main/java/at/hannibal2/skyhanni/api/CurrentPetApi.kt index 94a12e7855b9..df252dc3e001 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/CurrentPetApi.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/CurrentPetApi.kt @@ -56,6 +56,7 @@ object CurrentPetApi { ProfileStorageData.profileSpecific?.currentPetData = value?.asStorage() ?: PetDataStorage() } + fun isCurrentPet(petInternalName: NeuInternalName): Boolean = currentPet?.petItem == petInternalName fun isCurrentPet(petName: String): Boolean = currentPet?.cleanName?.contains(petName) ?: false // @@ -227,7 +228,7 @@ object CurrentPetApi { val petInternalName = petNameToInternalName(petName, rarity) val level = groupOrNull("level")?.toInt() ?: 0 val xp = levelToXp(level, petInternalName) ?: return null - val skinColor = groupOrNull("skin")?.substring(1, 2)?.get(0)?.toLorenzColor() + val skinColor = groupOrNull("skin")?.substring(1)?.get(0)?.toLorenzColor() return PetData( petItem = petInternalName, @@ -334,7 +335,7 @@ object CurrentPetApi { // // - @HandleEvent + @HandleEvent(onlyOnSkyblock = true) fun onWidgetUpdate(event: WidgetUpdateEvent) { if (!event.isWidget(TabWidget.PET)) return @@ -392,10 +393,9 @@ object CurrentPetApi { fun onSlotClick(event: GuiContainerEvent.SlotClickEvent) { if (!inPetMenu) return if (event.clickType != GuiContainerEvent.ClickType.NORMAL) return - val category = event.item?.getItemCategoryOrNull() ?: return - if (category != ItemCategory.PET) return + val item = event.item.takeIf { it?.getItemCategoryOrNull() == ItemCategory.PET } ?: return - updatePet(parsePetAsItem(event.item)) + updatePet(parsePetAsItem(item)) } @HandleEvent diff --git a/src/main/java/at/hannibal2/skyhanni/data/PetData.kt b/src/main/java/at/hannibal2/skyhanni/data/PetData.kt index 6ecbfe41a631..aeef00974fff 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PetData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PetData.kt @@ -4,7 +4,6 @@ import at.hannibal2.skyhanni.api.CurrentPetApi.petDespawnMenuPattern import at.hannibal2.skyhanni.data.jsonobjects.repo.neu.NeuPetSkinJson import at.hannibal2.skyhanni.test.command.ErrorManager import at.hannibal2.skyhanni.utils.ItemUtils.getLore -import at.hannibal2.skyhanni.utils.ItemUtils.itemName import at.hannibal2.skyhanni.utils.LorenzColor import at.hannibal2.skyhanni.utils.LorenzRarity import at.hannibal2.skyhanni.utils.NeuInternalName @@ -54,8 +53,7 @@ data class PetData( val xp: Double? = null, val skinInternalNameOverride: NeuInternalName? = null, ) { - val displayName = petItem?.itemName - val formattedName = "${rarity?.chatColorCode}$cleanName" + val displayName = "${rarity?.chatColorCode}$cleanName" val skin: NeuPetSkinJson? = getSkinOrNull() val levelProgressionPercentage: Double? = when { @@ -81,7 +79,7 @@ data class PetData( ): String { val levelString = if (includeLevel) "§7[Lvl $level] §r" else "" val skinString = if (includeSkin) skinSymbolColor?.let { "${it.getChatColor()}✦" }.orEmpty() else "" - return "§r$levelString$formattedName$skinString" + return "§r$levelString$displayName$skinString" } fun getItemStackOrNull(): ItemStack? = skin?.itemStack ?: petItem?.getItemStackOrNull() diff --git a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt index 288d662d3002..a15a2a664a27 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/NEUPetsJson.kt @@ -6,6 +6,7 @@ import com.google.gson.annotations.Expose import com.google.gson.annotations.SerializedName data class NEUPetsJson( + @Expose @SerializedName("pet_rarity_offset") val petRarityOffset: Map, @Expose @SerializedName("pet_levels") val petLevels: List, @Expose @SerializedName("custom_pet_leveling") val customPetLeveling: Map, @Expose @SerializedName("id_to_display_name") val internalToDisplayName: Map diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/MythicRabbitPetWarning.kt b/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/MythicRabbitPetWarning.kt index 23b251051c4f..c60d9ec218a9 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/MythicRabbitPetWarning.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/MythicRabbitPetWarning.kt @@ -3,11 +3,12 @@ package at.hannibal2.skyhanni.features.event.hoppity import at.hannibal2.skyhanni.api.CurrentPetApi import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.NeuInternalName.Companion.toInternalName import at.hannibal2.skyhanni.utils.SimpleTimeMark import kotlin.time.Duration.Companion.seconds object MythicRabbitPetWarning { - private const val MYTHIC_RABBIT_DISPLAY_NAME = "§dRabbit" + private val MYTHIC_RABBIT = "RABBIT;5".toInternalName() private var lastCheck = SimpleTimeMark.farPast() fun check() { @@ -21,7 +22,7 @@ object MythicRabbitPetWarning { } } - fun correctPet() = CurrentPetApi.isCurrentPet(MYTHIC_RABBIT_DISPLAY_NAME) + fun correctPet() = CurrentPetApi.isCurrentPet(MYTHIC_RABBIT) private fun warn() { ChatUtils.chat("Use a §dMythic Rabbit Pet §efor more chocolate!") diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt index a861eea57885..5e533a4bb33f 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/pets/CurrentPetDisplay.kt @@ -22,21 +22,21 @@ object CurrentPetDisplay { if (RiftApi.inRift() || !config.enabled) return val currentPet = CurrentPetApi.currentPet ?: return - val displayName = currentPet.getUserFriendlyName(includeLevel = false) + val displayName = currentPet.getUserFriendlyName(includeLevel = true) val itemStack = currentPet.getItemStackOrNull() ?: return val rarityColor = currentPet.rarity?.color ?: return val nameRender = Renderable.string(displayName, color = rarityColor.toColor()) val circle = Renderable.CircularRenderable( rarityColor.toColor(), - 25, + 20, itemStack = itemStack, border = Renderable.CircularRenderable( - Color.LIGHT_GRAY, - 30, + Color.GRAY, + 26, border = if (config.levelRing) Renderable.CircularRenderable( - backgroundColor = Color.BLUE, - radius = 32, + backgroundColor = Color.cyan, + radius = 29, filledPercentage = currentPet.levelProgressionPercentage ?: 0.0 ) else null ) diff --git a/src/main/java/at/hannibal2/skyhanni/utils/PetUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/PetUtils.kt index 237bbd02c3d9..c63f682c15e1 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/PetUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/PetUtils.kt @@ -30,7 +30,10 @@ object PetUtils { private val petSkins = mutableMapOf>() private var baseXpLevelReqs: List = listOf() + private var baseRarityOffsets: Map = mapOf() private var customXpLevelReqs: Map? = null + private fun getXpList(petInternalName: NeuInternalName): List = + baseXpLevelReqs + customXpLevelReqs?.get(petInternalName)?.petLevels.orEmpty() // /** @@ -150,66 +153,35 @@ object PetUtils { fun levelToXp(level: Int, petInternalName: NeuInternalName): Double? { val rarityOffset = getRarityOffset(petInternalName) if (!isValidLevel(level, petInternalName)) return null + val sliceIndices = rarityOffset until level + rarityOffset - 1 - val xpList = baseXpLevelReqs + getCustomLeveling(petInternalName) - - return xpList.slice(0 + rarityOffset.. 0 } ?: return null var level = 0 for (i in 0 + rarityOffset until xpList.size) { val xpReq = xpList[i] if (xp >= xpReq) { xp -= xpReq level++ - } else { - break - } + } else break } return level } - fun isValidLevel(level: Int, petInternalName: NeuInternalName): Boolean { - val petsData = customXpLevelReqs ?: run { - ErrorManager.skyHanniError("NEUPetsData is null") - } - - val maxLevel = petsData[petInternalName]?.maxLevel ?: return false - return maxLevel >= level - } - - private fun getCustomLeveling(petInternalName: NeuInternalName): List { - return customXpLevelReqs?.get(petInternalName)?.petLevels.orEmpty() - } + fun isValidLevel(level: Int, petInternalName: NeuInternalName): Boolean = + level <= (customXpLevelReqs?.get(petInternalName)?.maxLevel ?: 100) private fun getRarityOffset(petInternalName: NeuInternalName): Int { - val petsData = customXpLevelReqs ?: run { - ErrorManager.skyHanniError("NEUPetsData is null") - } - - val (_, rarity) = internalNameToPetName(petInternalName) ?: run { - ErrorManager.skyHanniError("Invalid Pet Internal Name \"$petInternalName\"") - } - - return petsData[petInternalName]?.rarityOffset?.get(rarity) ?: when (rarity) { - LorenzRarity.COMMON -> 0 - LorenzRarity.UNCOMMON -> 6 - LorenzRarity.RARE -> 11 - LorenzRarity.EPIC -> 16 - LorenzRarity.LEGENDARY -> 20 - LorenzRarity.MYTHIC -> 20 - else -> { - ErrorManager.skyHanniError("Invalid Rarity \"${rarity.name}\"") - } - } + val rarityOffset = customXpLevelReqs?.get(petInternalName)?.rarityOffset ?: baseRarityOffsets + val (_, rarity) = internalNameToPetName(petInternalName) ?: return 0 + return rarityOffset[rarity] ?: 0 } // @@ -218,6 +190,7 @@ object PetUtils { val data = event.getConstant("pets") baseXpLevelReqs = data.petLevels customXpLevelReqs = data.customPetLeveling.mapKeys { it.key.toInternalName() } + baseRarityOffsets = data.petRarityOffset NeuItems.allNeuRepoItems().forEach { (rawInternalName, jsonObject) -> petSkinNamePattern.matchMatcher(rawInternalName) { 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 b235a889799a..e8ce91670059 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt @@ -1695,15 +1695,15 @@ interface Renderable { private val radius: Int, private val border: CircularRenderable? = null, private val itemStack: ItemStack? = null, - private val itemScale: Double = 2.0, + private val itemScale: Double = 1.9, private val filledPercentage: Double = 100.0, private val unfilledColor: Color = Color.LIGHT_GRAY, ) : Renderable { private val totalRadius: Int = max(radius, border?.totalRadius ?: 0) private val diffRadius: Int = totalRadius - radius - override val width: Int = radius * 2 - override val height: Int = radius * 2 + override val width: Int = totalRadius * 2 + override val height: Int = totalRadius * 2 override val horizontalAlign = HorizontalAlignment.LEFT override val verticalAlign = VerticalAlignment.TOP @@ -1721,8 +1721,8 @@ interface Renderable { itemStack?.let { stack -> - val itemWidth = (15.5 * itemScale).toInt() - val itemHeight = (15.5 * itemScale).toInt() + val itemWidth = (16 * itemScale).toInt() + val itemHeight = (16 * itemScale).toInt() val itemX = totalRadius - itemWidth / 2 val itemY = totalRadius - itemHeight / 2