aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/at/hannibal2/skyhanni
diff options
context:
space:
mode:
authorLinnea Gräf <nea@nea.moe>2024-06-08 20:37:18 +0200
committerGitHub <noreply@github.com>2024-06-08 20:37:18 +0200
commit853464d885b9dad1948fe2098ef0f93106f43028 (patch)
treeeb2064e2ff6fe4367d8e6fbd801da23b56314eaf /src/main/java/at/hannibal2/skyhanni
parent5bb98aed61e4dadba12d203aad770d0408171ef3 (diff)
downloadskyhanni-853464d885b9dad1948fe2098ef0f93106f43028.tar.gz
skyhanni-853464d885b9dad1948fe2098ef0f93106f43028.tar.bz2
skyhanni-853464d885b9dad1948fe2098ef0f93106f43028.zip
Feature: Add location rabbit requirement tracker (#1997)
Co-authored-by: Cal <cwolfson58@gmail.com>
Diffstat (limited to 'src/main/java/at/hannibal2/skyhanni')
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/features/inventory/chocolatefactory/ChocolateFactoryConfig.java9
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java8
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityCollectionStats.kt98
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggLocations.kt4
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/CollectionUtils.kt24
5 files changed, 140 insertions, 3 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/chocolatefactory/ChocolateFactoryConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/chocolatefactory/ChocolateFactoryConfig.java
index 50230a6ae..cbd43b214 100644
--- a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/chocolatefactory/ChocolateFactoryConfig.java
+++ b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/chocolatefactory/ChocolateFactoryConfig.java
@@ -175,6 +175,15 @@ public class ChocolateFactoryConfig {
public boolean highlightRabbitsWithRequirement = false;
@Expose
+ @ConfigOption(
+ name = "Show Missing Location Rabbits",
+ desc = "Shows which in which locations you have not yet found enough egg locations to unlock the rabbit for that location."
+ )
+ @ConfigEditorBoolean
+ @FeatureToggle
+ public boolean showLocationRequirementsRabbitsInHoppityStats = false;
+
+ @Expose
@ConfigOption(name = "Only Requirement Not Met", desc = "Only highlight the rabbits you don't have the requirement for.")
@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 074d4cc19..00ce6c39c 100644
--- a/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java
+++ b/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java
@@ -12,6 +12,7 @@ import at.hannibal2.skyhanni.features.dungeon.CroesusChestTracker;
import at.hannibal2.skyhanni.features.dungeon.DungeonFloor;
import at.hannibal2.skyhanni.features.event.diana.DianaProfitTracker;
import at.hannibal2.skyhanni.features.event.diana.MythologicalCreatureTracker;
+import at.hannibal2.skyhanni.features.event.hoppity.HoppityCollectionStats;
import at.hannibal2.skyhanni.features.event.jerry.frozentreasure.FrozenTreasureTracker;
import at.hannibal2.skyhanni.features.fame.UpgradeReminder;
import at.hannibal2.skyhanni.features.fishing.tracker.FishingProfitTracker;
@@ -130,10 +131,13 @@ public class ProfileSpecificStorage {
public String targetName = null;
@Expose
- public Map<String, Integer> rabbitCounts = new HashMap();
+ public Map<String, Integer> rabbitCounts = new HashMap<>();
@Expose
- public Map<IslandType, Set<LorenzVec>> collectedEggLocations = new HashMap();
+ public Map<String, HoppityCollectionStats.LocationRabbit> locationRabbitRequirements = new HashMap<>();
+
+ @Expose
+ public Map<IslandType, Set<LorenzVec>> collectedEggLocations = new HashMap<>();
@Expose
public Integer hoppityShopYearOpened = null;
diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityCollectionStats.kt b/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityCollectionStats.kt
index c198495e5..e4a7578c5 100644
--- a/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityCollectionStats.kt
+++ b/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityCollectionStats.kt
@@ -1,5 +1,6 @@
package at.hannibal2.skyhanni.features.event.hoppity
+import at.hannibal2.skyhanni.data.IslandType
import at.hannibal2.skyhanni.data.ProfileStorageData
import at.hannibal2.skyhanni.events.GuiContainerEvent
import at.hannibal2.skyhanni.events.GuiRenderEvent
@@ -8,9 +9,12 @@ import at.hannibal2.skyhanni.events.InventoryFullyOpenedEvent
import at.hannibal2.skyhanni.features.inventory.chocolatefactory.ChocolateFactoryAPI
import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule
import at.hannibal2.skyhanni.utils.ChatUtils
+import at.hannibal2.skyhanni.utils.CollectionUtils.collectWhile
+import at.hannibal2.skyhanni.utils.CollectionUtils.consumeWhile
import at.hannibal2.skyhanni.utils.DisplayTableEntry
import at.hannibal2.skyhanni.utils.InventoryUtils
import at.hannibal2.skyhanni.utils.ItemUtils.getLore
+import at.hannibal2.skyhanni.utils.KSerializable
import at.hannibal2.skyhanni.utils.LorenzColor
import at.hannibal2.skyhanni.utils.LorenzUtils
import at.hannibal2.skyhanni.utils.LorenzUtils.round
@@ -20,6 +24,7 @@ import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators
import at.hannibal2.skyhanni.utils.NumberUtil.formatInt
import at.hannibal2.skyhanni.utils.RegexUtils.anyMatches
import at.hannibal2.skyhanni.utils.RegexUtils.find
+import at.hannibal2.skyhanni.utils.RegexUtils.findMatcher
import at.hannibal2.skyhanni.utils.RegexUtils.matchFirst
import at.hannibal2.skyhanni.utils.RegexUtils.matches
import at.hannibal2.skyhanni.utils.RenderUtils.highlight
@@ -56,6 +61,7 @@ object HoppityCollectionStats {
"rabbits.found",
"§.§l§m[ §a-z]+§r §.(?<current>[0-9]+)§./§.(?<total>[0-9]+)"
)
+
/**
* REGEX-TEST: §a✔ §7Requirement
*/
@@ -63,6 +69,7 @@ object HoppityCollectionStats {
"rabbit.requirement.met",
"§a✔ §7Requirement"
)
+
/**
* REGEX-TEST: §c✖ §7Requirement §e0§7/§a15
* REGEX-TEST: §c✖ §7Requirement §e6§7/§a20
@@ -73,10 +80,50 @@ object HoppityCollectionStats {
"§c✖ §7Requirement.*",
)
+ /**
+ * REGEX-TEST: §c✖ §7Requirement §e0§7/§a15
+ * REGEX-TEST: §c✖ §7Requirement §e6§7/§a20
+ * REGEX-TEST: §c✖ §7Requirement §e651§7/§a1,000
+ */
+ private val requirementAmountNotMet by patternGroup.pattern(
+ "rabbit.requirement.notmet.amount",
+ "§c✖ §7Requirement §e(?<acquired>[\\d,]+)§7/§a(?<required>[\\d,]+)",
+ )
+
+ /**
+ * REGEX-TEST: Find 15 unique egg locations in the Deep Caverns.
+ */
+ private val locationRequirementDescription by patternGroup.pattern(
+ "rabbit.requirement.location",
+ "Find 15 unique egg locations in (the )?(?<location>.*)\\..*"
+ )
+
private var display = emptyList<Renderable>()
private val loggedRabbits
get() = ProfileStorageData.profileSpecific?.chocolateFactory?.rabbitCounts ?: mutableMapOf()
+ @KSerializable
+ data class LocationRabbit(
+ val locationName: String,
+ val loreFoundCount: Int,
+ val requiredCount: Int,
+ ) {
+ private fun getSkyhanniFoundCount(): Int {
+ val islandType = IslandType.getByNameOrNull(locationName) ?: return 0
+ val foundLocations = HoppityEggLocations.getEggsIn(islandType)
+ return foundLocations.size
+ }
+
+ val foundCount get() = maxOf(getSkyhanniFoundCount(), loreFoundCount)
+
+ fun hasMetRequirements(): Boolean {
+ return foundCount >= requiredCount
+ }
+ }
+
+ private val locationRabbitRequirements: MutableMap<String, LocationRabbit>
+ get() = ProfileStorageData.profileSpecific?.chocolateFactory?.locationRabbitRequirements ?: mutableMapOf()
+
var inInventory = false
@SubscribeEvent
@@ -120,6 +167,28 @@ object HoppityCollectionStats {
}
}
+ private fun addLocationRequirementRabbitsToHud(newList: MutableList<Renderable>) {
+ if (!config.showLocationRequirementsRabbitsInHoppityStats) return
+ val missingLocationRabbits = locationRabbitRequirements.values.filter { !it.hasMetRequirements() }
+
+ val tips = locationRabbitRequirements.map {
+ it.key + " §7(§e" + it.value.locationName + "§7): " + (if (it.value.hasMetRequirements()) "§a" else "§c") +
+ it.value.foundCount + "§7/§a" + it.value.requiredCount
+ }
+
+ newList.add(Renderable.hoverTips(
+ if (missingLocationRabbits.isEmpty())
+ Renderable.wrappedString("§aFound enough eggs in all locations", width = 200)
+ else
+ Renderable.wrappedString(
+ "§cMissing Locations§7:§c " +
+ missingLocationRabbits.joinToString("§7, §c") {
+ it.locationName
+ }, width = 200),
+ tips
+ ))
+ }
+
private fun buildDisplay(event: InventoryFullyOpenedEvent): MutableList<Renderable> {
logRabbits(event)
@@ -127,6 +196,8 @@ object HoppityCollectionStats {
newList.add(Renderable.string("§eHoppity Rabbit Collection§f:"))
newList.add(LorenzUtils.fillTable(getRabbitStats(), padding = 5))
+ addLocationRequirementRabbitsToHud(newList)
+
val loggedRabbitCount = loggedRabbits.size
val foundRabbitCount = getFoundRabbitsFromHypixel(event)
@@ -228,14 +299,39 @@ object HoppityCollectionStats {
}
}
+ private fun saveLocationRabbit(rabbitName: String, lore: List<String>) {
+ val iterator = lore.iterator()
+
+ val requirement = iterator.consumeWhile { line ->
+ val requirementMet = requirementMet.matches(line)
+ if (requirementMet) Pair(15, 15) // This is kind of hardcoded?
+ else requirementAmountNotMet.findMatcher(line) {
+ group("acquired").formatInt() to group("required").formatInt()
+ }
+ } ?: return
+
+ val requirementDescriptionCollate = iterator.collectWhile { line ->
+ line.isNotEmpty()
+ }.joinToString(" ") { it.removeColor() }
+
+ val location = locationRequirementDescription.findMatcher(requirementDescriptionCollate) {
+ group("location")
+ } ?: return
+
+ locationRabbitRequirements[rabbitName] = LocationRabbit(location, requirement.first, requirement.second)
+ }
+
private fun logRabbits(event: InventoryFullyOpenedEvent) {
- for ((_, item) in event.inventoryItems) {
+ for (item in event.inventoryItems.values) {
val itemName = item.displayName?.removeColor() ?: continue
val isRabbit = HoppityCollectionData.isKnownRabbit(itemName)
if (!isRabbit) continue
val itemLore = item.getLore()
+
+ saveLocationRabbit(itemName, itemLore)
+
val found = !rabbitNotFoundPattern.anyMatches(itemLore)
if (!found) continue
diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggLocations.kt b/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggLocations.kt
index 00f59cdb8..cce0aef79 100644
--- a/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggLocations.kt
+++ b/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggLocations.kt
@@ -38,6 +38,10 @@ object HoppityEggLocations {
val islandCollectedLocations
get() = collectedEggStorage[LorenzUtils.skyBlockIsland]?.toSet() ?: emptySet()
+ fun getEggsIn(islandType: IslandType): Set<LorenzVec> {
+ return collectedEggStorage[islandType] ?: emptySet()
+ }
+
fun hasCollectedEgg(location: LorenzVec): Boolean = islandCollectedLocations.contains(location)
@SubscribeEvent
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/CollectionUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/CollectionUtils.kt
index 48cf1ccb2..6b4d70046 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/CollectionUtils.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/CollectionUtils.kt
@@ -184,6 +184,30 @@ object CollectionUtils {
}
}
+ inline fun <T, R> Iterator<T>.consumeWhile(block: (T) -> R): R? {
+ while (hasNext()) {
+ return block(next()) ?: continue
+ }
+ return null
+ }
+
+ inline fun <T> Iterator<T>.collectWhile(block: (T) -> Boolean): List<T> {
+ return collectWhileTo(mutableListOf(), block)
+ }
+
+ inline fun <T, C : MutableCollection<T>> Iterator<T>.collectWhileTo(collection: C, block: (T) -> Boolean): C {
+ while (hasNext()) {
+ val element = next()
+ if (block(element)) {
+ collection.add(element)
+ } else {
+ break
+ }
+ }
+ return collection
+ }
+
+
/** Updates a value if it is present in the set (equals), useful if the newValue is not reference equal with the value in the set */
inline fun <reified T> MutableSet<T>.refreshReference(newValue: T) = if (this.contains(newValue)) {
this.remove(newValue)