aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/features/combat/FerocityDisplayConfig.java2
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java4
-rw-r--r--src/main/java/at/hannibal2/skyhanni/data/model/SkyblockStat.kt208
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/combat/FerocityDisplay.kt33
4 files changed, 165 insertions, 82 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/combat/FerocityDisplayConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/combat/FerocityDisplayConfig.java
index d212a4a07..605a31a2b 100644
--- a/src/main/java/at/hannibal2/skyhanni/config/features/combat/FerocityDisplayConfig.java
+++ b/src/main/java/at/hannibal2/skyhanni/config/features/combat/FerocityDisplayConfig.java
@@ -13,7 +13,7 @@ public class FerocityDisplayConfig {
@ConfigOption(
name = "Enabled",
desc = "Show ferocity stat as single GUI element.\n" +
- "§eRequires tab list widget enabled and ferocity selected to work."
+ "§eRequires tab list widget enabled and ferocity selected to update live."
)
@ConfigEditorBoolean
@FeatureToggle
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 4ccb0823d..4ad2c8eb3 100644
--- a/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java
+++ b/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java
@@ -6,6 +6,7 @@ import at.hannibal2.skyhanni.data.IslandType;
import at.hannibal2.skyhanni.data.MaxwellAPI;
import at.hannibal2.skyhanni.data.jsonobjects.local.HotmTree;
import at.hannibal2.skyhanni.data.model.ComposterUpgrade;
+import at.hannibal2.skyhanni.data.model.SkyblockStat;
import at.hannibal2.skyhanni.features.combat.endernodetracker.EnderNodeTracker;
import at.hannibal2.skyhanni.features.combat.ghostcounter.GhostData;
import at.hannibal2.skyhanni.features.dungeon.CroesusChestTracker;
@@ -204,6 +205,9 @@ public class ProfileSpecificStorage {
}
@Expose
+ public Map<SkyblockStat,Double> stats = new HashMap<>(SkyblockStat.getEntries().size());
+
+ @Expose
public MaxwellPowerStorage maxwell = new MaxwellPowerStorage();
public static class MaxwellPowerStorage {
diff --git a/src/main/java/at/hannibal2/skyhanni/data/model/SkyblockStat.kt b/src/main/java/at/hannibal2/skyhanni/data/model/SkyblockStat.kt
index f31c95958..d1c6dede0 100644
--- a/src/main/java/at/hannibal2/skyhanni/data/model/SkyblockStat.kt
+++ b/src/main/java/at/hannibal2/skyhanni/data/model/SkyblockStat.kt
@@ -1,69 +1,115 @@
package at.hannibal2.skyhanni.data.model
+import at.hannibal2.skyhanni.data.ProfileStorageData
+import at.hannibal2.skyhanni.events.InventoryFullyOpenedEvent
+import at.hannibal2.skyhanni.events.WidgetUpdateEvent
+import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule
+import at.hannibal2.skyhanni.utils.DelayedRun
+import at.hannibal2.skyhanni.utils.ItemUtils.getLore
+import at.hannibal2.skyhanni.utils.LorenzUtils
+import at.hannibal2.skyhanni.utils.RegexUtils.groupOrNull
+import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher
import at.hannibal2.skyhanni.utils.StringUtils.allLettersFirstUppercase
+import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern
import net.minecraft.client.Minecraft
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+import org.intellij.lang.annotations.Language
import java.util.EnumMap
+import java.util.regex.Pattern
+import kotlin.math.roundToInt
-enum class SkyblockStat(val icon: String) {
- DAMAGE("§c❁"),
- HEALTH("§c❤"),
- DEFENSE("§a❈"),
- STRENGTH("§c❁"),
- INTELLIGENCE("§b✎"),
-
- CRIT_DAMAGE("§9☠"),
- CRIT_CHANCE("§9☣"),
- FEROCITY("§c⫽"),
- BONUS_ATTACK_SPEED("§e⚔"),
- ABILITY_DAMAGE("§c๑"),
- HEALTH_REGEN("§c❣"),
- VITALITY("§4♨"),
- MENDING("§a☄"),
- TRUE_DEFENCE("§7❂"),
- SWING_RANGE("§eⓈ"),
- SPEED("§f✦"),
- SEA_CREATURE_CHANCE("§3α"),
- MAGIC_FIND("§b✯"),
- PET_LUCK("§d♣"),
- FISHING_SPEED("§b☂"),
- BONUS_PEST_CHANCE("§2ൠ"),
- COMBAT_WISDOM("§3☯"),
- MINING_WISDOM("§3☯"),
- FARMING_WISDOM("§3☯"),
- FORAGING_WISDOM("§3☯"),
- FISHING_WISDOM("§3☯"),
- ENCHANTING_WISDOM("§3☯"),
- ALCHEMY_WISDOM("§3☯"),
- CARPENTRY_WISDOM("§3☯"),
- RUNECRAFTING_WISDOM("§3☯"),
- SOCIAL_WISDOM("§3☯"),
- TAMING_WISDOM("§3☯"),
- MINING_SPEED("§6⸕"),
- BREAKING_POWER("§2Ⓟ"),
- PRISTINE("§5✧"),
- FORAGING_FORTUNE("§☘"),
- FARMING_FORTUNE("§6☘"),
-
- MINING_SPREAD("§e▚"),
- MINING_FORTUNE("§6☘"),
- ORE_FORTUNE("§6☘"),
- DWARVEN_METAL_FORTUNE("§6☘"),
- BLOCK_FORTUNE("§6☘"),
- GEMSTONE_FORTUNE("§6☘"),
-
- FEAR("§a☠"),
- HEAT_RESISTANCE("§c♨"),
-
- UNKNOWN("§c?")
+enum class SkyblockStat(
+ val icon: String,
+ @Language("RegExp") tabListPatternS: String,
+ @Language("RegExp") menuPatternS: String,
+) {
+ DAMAGE("§c❁", "", ""), // Weapon only
+ HEALTH("§c❤", " Health: §r§c❤(?<value>.*)", " §c❤ Health §f(?<value>.*)"), // TODO get from action bar
+ DEFENSE("§a❈", " Defense: §r§a❈(?<value>.*)", " §a❈ Defense §f(?<value>.*)"), // TODO get from action bar
+ STRENGTH("§c❁", " Strength: §r§c❁(?<value>.*)", " §c❁ Strength §f(?<value>.*)"),
+ INTELLIGENCE("§b✎", " Intelligence: §r§b✎(?<value>.*)", " §b✎ Intelligence §f(?<value>.*)"), // TODO get from action bar
+ CRIT_DAMAGE("§9☠", " Crit Damage: §r§9☠(?<value>.*)", " §9☠ Crit Damage §f(?<value>.*)"),
+ CRIT_CHANCE("§9☣", " Crit Chance: §r§9☣(?<value>.*)", " §9☣ Crit Chance §f(?<value>.*)"),
+ FEROCITY("§c⫽", " Ferocity: §r§c⫽(?<value>.*)", " §c⫽ Ferocity §f(?<value>.*)"),
+ BONUS_ATTACK_SPEED("§e⚔", " Attack Speed: §r§e⚔(?<value>.*)", " §e⚔ Bonus Attack Speed §f(?<value>.*)"),
+ ABILITY_DAMAGE("§c๑", " Ability Damage: §r§c๑(?<value>.*)", " §c๑ Ability Damage §f(?<value>.*)"),
+ HEALTH_REGEN("§c❣", " Health Regen: §r§c❣(?<value>.*)", " §c❣ Health Regen §f(?<value>.*)"),
+ VITALITY("§4♨", " Vitality: §r§4♨(?<value>.*)", " §4♨ Vitality §f(?<value>.*)"),
+ MENDING("§a☄", " Mending: §r§a☄(?<value>.*)", " §a☄ Mending §f(?<value>.*)"),
+ TRUE_DEFENCE("§7❂", " True Defense: §r§f❂(?<value>.*)", " §f❂ True Defense §f(?<value>.*)"),
+ SWING_RANGE("§eⓈ", " Swing Range: §r§eⓈ(?<value>.*)", " §eⓈ Swing Range §f(?<value>.*)"),
+ SPEED("§f✦", " Speed: §r§f✦(?<value>.*)", " §f✦ Speed §f(?<value>.*)"), // TODO add the way sba did get it (be careful with 500+ Speed)
+ SEA_CREATURE_CHANCE("§3α", " Sea Creature Chance: §r§3α(?<value>.*)", " §3α Sea Creature Chance §f(?<value>.*)"),
+ MAGIC_FIND("§b✯", " Magic Find: §r§b✯(?<value>.*)", " §b✯ Magic Find §f(?<value>.*)"),
+ PET_LUCK("§d♣", " Pet Luck: §r§d♣(?<value>.*)", " §d♣ Pet Luck §f(?<value>.*)"),
+ FISHING_SPEED("§b☂", " Fishing Speed: §r§b☂(?<value>.*)", " §b☂ Fishing Speed §f(?<value>.*)"),
+ DOUBLE_HOOK_CHANCE("§9⚓", " Double Hook Chance: §r§9⚓(?<value>.*)", ""),
+ BONUS_PEST_CHANCE("§2ൠ", " (?:§r§7§m)?Bonus Pest Chance: (?:§r§2)?ൠ(?<value>.*)", " (?:§7§m|§2)ൠ Bonus Pest Chance (?:§f)?(?<value>.*)"),
+ COMBAT_WISDOM("§3☯", " Combat Wisdom: §r§3☯(?<value>.*)", " §3☯ Combat Wisdom §f(?<value>.*)"),
+ MINING_WISDOM("§3☯", " Mining Wisdom: §r§3☯(?<value>.*)", " §3☯ Mining Wisdom §f(?<value>.*)"),
+ FARMING_WISDOM("§3☯", " Farming Wisdom: §r§3☯(?<value>.*)", " §3☯ Farming Wisdom §f(?<value>.*)"),
+ FORAGING_WISDOM("§3☯", " Foraging Wisdom: §r§3☯(?<value>.*)", " §3☯ Foraging Wisdom §f(?<value>.*)"),
+ FISHING_WISDOM("§3☯", " Fishing Wisdom: §r§3☯(?<value>.*)", " §3☯ Fishing Wisdom §f(?<value>.*)"),
+ ENCHANTING_WISDOM("§3☯", " Enchanting Wisdom: §r§3☯(?<value>.*)", " §3☯ Enchanting Wisdom §f(?<value>.*)"),
+ ALCHEMY_WISDOM("§3☯", " Alchemy Wisdom: §r§3☯(?<value>.*)", " §3☯ Alchemy Wisdom §f(?<value>.*)"),
+ CARPENTRY_WISDOM("§3☯", " Carpentry Wisdom: §r§3☯(?<value>.*)", " §3☯ Carpentry Wisdom §f(?<value>.*)"),
+ RUNECRAFTING_WISDOM("§3☯", " Runecrafting Wisdom: §r§3☯(?<value>.*)", " §3☯ Runecrafting Wisdom §f(?<value>.*)"),
+ SOCIAL_WISDOM("§3☯", " Social Wisdom: §r§3☯(?<value>.*)", " §3☯ Social Wisdom §f(?<value>.*)"),
+ TAMING_WISDOM("§3☯", " Taming Wisdom: §r§3☯(?<value>.*)", " §3☯ Taming Wisdom §f(?<value>.*)"),
+ MINING_SPEED("§6⸕", " Mining Speed: §r§6⸕(?<value>.*)", " §6⸕ Mining Speed §f(?<value>.*)"),
+ BREAKING_POWER("§2Ⓟ", "", " §2Ⓟ Breaking Power §f(?<value>.*)"),
+ PRISTINE("§5✧", " Pristine: §r§5✧(?<value>.*)", " §5✧ Pristine §f(?<value>.*)"),
+ FORAGING_FORTUNE("§☘", " Foraging Fortune: §r§6☘(?<value>.*)", " §6☘ Foraging Fortune §f(?<value>.*)"),
+ FARMING_FORTUNE("§6☘", " (?:§r§7§m)?Farming Fortune: (?:§r§6)?☘(?<value>.*)", " (?:§7§m|§6)☘ Farming Fortune (?:§f)?(?<value>.*)"),
+ MINING_FORTUNE("§6☘", " Mining Fortune: §r§6☘(?<value>.*)", " §6☘ Mining Fortune §f(?<value>.*)"),
+ FEAR("§a☠", "", ""), // Skyblock does not like fear. It only shows during Great Spook, therefore no Data.
+ COLD_RESISTANCE("§b❄", " Cold Resistance: §r§b❄(?<value>.*)", ""),
+ WHEAT_FORTUNE("§7☘", "", " §7(?:§m)☘ Wheat Fortune (?<value>.*)"),
+ CARROT_FORTUNE("§7☘", "", " §7(?:§m)☘ Carrot Fortune (?<value>.*)"),
+ POTATO_FORTUNE("§7☘", "", " §7(?:§m)☘ Potato Fortune (?<value>.*)"),
+ PUMPKIN_FORTUNE("§7☘", "", " §7(?:§m)☘ Pumpkin Fortune (?<value>.*)"),
+ MELON_FORTUNE("§7☘", "", " §7(?:§m)☘ Melon Fortune (?<value>.*)"),
+ MUSHROOM_FORTUNE("§7☘", "", " §7(?:§m)☘ Mushroom Fortune (?<value>.*)"),
+ CACTUS_FORTUNE("§7☘", "", " §7(?:§m)☘ Cactus Fortune (?<value>.*)"),
+ NETHER_WART_FORTUNE("§7☘", "", " §7(?:§m)☘ Nether Wart Fortune (?<value>.*)"),
+ COCOA_BEANS_FORTUNE("§7☘", "", " §7(?:§m)☘ Cocoa Beans Fortune (?<value>.*)"),
+ SUGAR_CANE_FORTUNE("§7☘", "", " §7(?:§m)☘ Sugar Cane Fortune (?<value>.*)"),
+
+ MINING_SPREAD("§e▚", " (§r§7§m)?Mining Spread: (§r§e)?▚(?<value>.*)", " (§7§m|§e)▚ Mining Spread (§f)?(?<value>.*)"),
+ GEMSTONE_SPREAD("§e▚", " (§r§7§m)?Mining Spread: (§r§e)?▚(?<value>.*)", " (§7§m|§e)▚ Gemstone Spread (§f)?(?<value>.*)"),
+ ORE_FORTUNE("§6☘", " Ore Fortune: §r§6☘(?<value>.*)", " §6☘ Ore Fortune §f103"),
+ DWARVEN_METAL_FORTUNE("§6☘", " Dwarven Metal Fortune: §r§6☘(?<value>.*)", " §6☘ Dwarven Metal Fortune §f(?<value>.*)"),
+ BLOCK_FORTUNE("§6☘", " Block Fortune: §r§6☘(?<value>.*)", " §6☘ Block Fortune §f(?<value>.*)"),
+ GEMSTONE_FORTUNE("§6☘", " Gemstone Fortune: §r§6☘(?<value>.*)", " §6☘ Gemstone Fortune §f(?<value>.*)"),
+ HEAT_RESISTANCE("§c♨", " Heat Resistance: §r§c♨(?<value>.*)", " §c♨ Heat Resistance §f(?<value>.*)"),
+
+ UNKNOWN("§c?", "", "")
;
+ var lastKnownValue: Double
+ get() = ProfileStorageData.profileSpecific?.stats?.get(this) ?: 0.0
+ set(value) {
+ ProfileStorageData.profileSpecific?.stats?.set(this, value)
+ }
+
+ var lastSource: StatSourceType = StatSourceType.UNKNOWN
+
val capitalizedName = name.lowercase().allLettersFirstUppercase()
val iconWithName = "$icon $capitalizedName"
+ val keyName = name.lowercase().replace('_', '.')
+
+ val displayValue get() = icon + lastKnownValue.roundToInt()
+
+ val tablistPattern by RepoPattern.pattern("stats.tablist.$keyName", tabListPatternS)
+ val menuPattern by RepoPattern.pattern("stats.menu.$keyName", menuPatternS)
+
fun asString(value: Int) = (if (value > 0) "+" else "") + value.toString() + " " + this.icon
+ @SkyHanniModule
companion object {
+
val fontSizeOfLargestIcon by lazy {
entries.maxOf { Minecraft.getMinecraft().fontRendererObj.getStringWidth(it.icon) } + 1
}
@@ -71,6 +117,59 @@ enum class SkyblockStat(val icon: String) {
fun getValueOrNull(string: String): SkyblockStat? = entries.firstOrNull { it.name == string }
fun getValue(string: String): SkyblockStat = getValueOrNull(string) ?: UNKNOWN
+
+ init {
+ entries.forEach {
+ it.tablistPattern
+ it.menuPattern
+ }
+ }
+
+ @SubscribeEvent
+ fun onInventory(event: InventoryFullyOpenedEvent) {
+ if (!LorenzUtils.inSkyBlock) return
+ onSkyblockMenu(event)
+ onStatsMenu(event)
+ }
+
+ private const val PLAYER_STATS_SLOT_INDEX = 13
+
+ private fun onSkyblockMenu(event: InventoryFullyOpenedEvent) {
+ if (event.inventoryName != "SkyBlock Menu") return
+ val list = event.inventoryItems[PLAYER_STATS_SLOT_INDEX]?.getLore() ?: return
+ DelayedRun.runNextTick { // Delayed to not impact opening time
+ assignEntry(list, StatSourceType.SKYBLOCK_MENU) { it.menuPattern }
+ }
+ }
+
+ private val statsMenuRelevantSlotIndexes = listOf(15, 16, 24, 25)
+
+ private fun onStatsMenu(event: InventoryFullyOpenedEvent) {
+ if (event.inventoryName != "Your Equipment and Stats") return
+ val list = statsMenuRelevantSlotIndexes.mapNotNull { event.inventoryItems[it]?.getLore() }.flatten()
+ if (list.isEmpty()) return
+ DelayedRun.runNextTick { // Delayed to not impact opening time
+ assignEntry(list, StatSourceType.STATS_MENU) { it.menuPattern }
+ }
+ }
+
+ @SubscribeEvent
+ fun onTabList(event: WidgetUpdateEvent) {
+ if (!event.isWidget(TabWidget.STATS, TabWidget.DUNGEON_SKILLS_AND_STATS)) return
+ val type = if (event.isWidget(TabWidget.DUNGEON_SKILLS_AND_STATS)) StatSourceType.TABLIST_DUNGEON else StatSourceType.TABLIST
+ assignEntry(event.lines, type) { it.tablistPattern }
+ }
+
+ private fun assignEntry(lines: List<String>, type: StatSourceType, pattern: (SkyblockStat) -> Pattern) {
+ for (line in lines) for (entry in entries) {
+ val matchResult = pattern(entry).matchMatcher(line) {
+ groupOrNull("value")?.replace("[,%]".toRegex(), "")?.toDouble()
+ } ?: continue
+ entry.lastKnownValue = matchResult
+ entry.lastSource = type
+ break // Exit the inner loop once a match is found
+ }
+ }
}
}
@@ -93,3 +192,10 @@ class SkyblockStatList : EnumMap<SkyblockStat, Double>(SkyblockStat::class.java)
}
}
+enum class StatSourceType {
+ UNKNOWN,
+ SKYBLOCK_MENU,
+ STATS_MENU,
+ TABLIST,
+ TABLIST_DUNGEON,
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/features/combat/FerocityDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/combat/FerocityDisplay.kt
index c30299e4f..8ea8449f4 100644
--- a/src/main/java/at/hannibal2/skyhanni/features/combat/FerocityDisplay.kt
+++ b/src/main/java/at/hannibal2/skyhanni/features/combat/FerocityDisplay.kt
@@ -1,14 +1,11 @@
package at.hannibal2.skyhanni.features.combat
import at.hannibal2.skyhanni.SkyHanniMod
-import at.hannibal2.skyhanni.data.model.TabWidget
+import at.hannibal2.skyhanni.data.model.SkyblockStat
import at.hannibal2.skyhanni.events.GuiRenderEvent
-import at.hannibal2.skyhanni.events.WidgetUpdateEvent
import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule
import at.hannibal2.skyhanni.utils.LorenzUtils
-import at.hannibal2.skyhanni.utils.RegexUtils.matchFirst
import at.hannibal2.skyhanni.utils.RenderUtils.renderString
-import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
@SkyHanniModule
@@ -16,35 +13,11 @@ object FerocityDisplay {
private val config get() = SkyHanniMod.feature.combat.ferocityDisplay
- /**
- * REGEX-TEST: Ferocity: §r§c⫽14
- */
- private val ferocityPattern by RepoPattern.pattern(
- "combat.ferocity.tab",
- " Ferocity: §r§c⫽(?<stat>.*)",
- )
-
- private var display = ""
-
- @SubscribeEvent
- fun onTabListUpdate(event: WidgetUpdateEvent) {
- if (!isEnabled()) return
- if (!event.isWidget(TabWidget.STATS, TabWidget.DUNGEON_SKILLS_AND_STATS)) return
- display = ""
- if (event.isClear()) return
- val stat = event.lines.matchFirst(ferocityPattern) {
- group("stat")
- } ?: return
-
- display = "§c⫽$stat"
-
- }
-
@SubscribeEvent
fun onRenderOverlay(event: GuiRenderEvent) {
if (!isEnabled()) return
-
- config.position.renderString(display, posLabel = "Ferocity Display")
+ if (SkyblockStat.FEROCITY.lastKnownValue == 0.0) return
+ config.position.renderString(SkyblockStat.FEROCITY.displayValue, posLabel = "Ferocity Display")
}
fun isEnabled() = LorenzUtils.inSkyBlock && config.enabled