diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/CakeTrackerConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/CakeTrackerConfig.java new file mode 100644 index 000000000000..67bd1d7d2b58 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/CakeTrackerConfig.java @@ -0,0 +1,81 @@ +package at.hannibal2.skyhanni.config.features.inventory; + +import at.hannibal2.skyhanni.config.FeatureToggle; +import at.hannibal2.skyhanni.config.core.config.Position; +import at.hannibal2.skyhanni.utils.LorenzColor; +import com.google.gson.annotations.Expose; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorColour; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorInfoText; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorSlider; +import io.github.notenoughupdates.moulconfig.annotations.ConfigLink; +import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; +import io.github.notenoughupdates.moulconfig.observer.Property; + +public class CakeTrackerConfig { + + @Expose + @ConfigOption(name = "Enabled", desc = "Tracks which Cakes you have/need.") + @ConfigEditorBoolean + @FeatureToggle + public boolean enabled = false; + + @Expose + @ConfigOption( + name = "Note", + desc = "§cNote7:" + + "\nThis feature is not compatible with the NEU Storage Overlay." + + "\nBackpacks/Ender Chest will not be scanned correctly with it enabled." + ) + @ConfigEditorInfoText + public boolean incompatibleNote = false; + + @Expose + @ConfigLink(owner = CakeTrackerConfig.class, field = "enabled") + public Position cakeTrackerPosition = new Position(300, 300, false, true); + + @Expose + public CakeTrackerDisplayType displayType = CakeTrackerDisplayType.MISSING_CAKES; + + public enum CakeTrackerDisplayType { + MISSING_CAKES, + OWNED_CAKES, + } + + @Expose + public CakeTrackerDisplayOrderType displayOrderType = CakeTrackerDisplayOrderType.OLDEST_FIRST; + + public enum CakeTrackerDisplayOrderType { + OLDEST_FIRST, + NEWEST_FIRST, + } + + @Expose + @ConfigOption(name = "Price on Hover", desc = "Show the prices of cakes when hovering over them in the tracker.") + @ConfigEditorBoolean + public boolean priceOnHover = true; + + @Expose + @ConfigOption( + name = "Missing Color", + desc = "The color that should be used to highlight unobtained cakes in the Auction House." + ) + @ConfigEditorColour + public String unobtainedAuctionHighlightColor = LorenzColor.RED.toConfigColor(); + + @Expose + @ConfigOption( + name = "Owned Color", + desc = "The color that should be used to highlight obtained cakes in the Auction House." + ) + @ConfigEditorColour + public String obtainedAuctionHighlightColor = LorenzColor.GREEN.toConfigColor(); + + @Expose + @ConfigOption( + name = "Maximum Rows", + desc = "The maximum number of rows to display in the tracker, before a cutoff is imposed." + ) + @ConfigEditorSlider(minValue = 5, maxValue = 40, minStep = 1) + public Property maxDisplayRows = Property.of(20); +} diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/InventoryConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/InventoryConfig.java index 8ff178fc050d..7a0aa9c7a36f 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/InventoryConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/InventoryConfig.java @@ -134,6 +134,11 @@ public class InventoryConfig { @Accordion public PageScrollingConfig pageScrolling = new PageScrollingConfig(); + @Expose + @ConfigOption(name = "New Year Cake Tracker", desc = "") + @Accordion + public CakeTrackerConfig cakeTracker = new CakeTrackerConfig(); + @Expose @ConfigOption(name = "Magical Power Display", desc = "") @Accordion 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 83334b404410..5c2669081412 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java +++ b/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java @@ -57,6 +57,7 @@ import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; @@ -528,6 +529,26 @@ public static class GhostCounter { } + public static class CakeData { + @Expose + public Set ownedCakes = new HashSet<>(); + + @Expose + public Set missingCakes = new HashSet<>(); + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ownedCakes.hashCode(); + result = prime * result + missingCakes.hashCode(); + return result; + } + } + + @Expose + public CakeData cakeData = new CakeData(); + @Expose public PowderTracker.Data powderTracker = new PowderTracker.Data(); diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/caketracker/CakeTracker.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/caketracker/CakeTracker.kt new file mode 100644 index 000000000000..df530118b92a --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/caketracker/CakeTracker.kt @@ -0,0 +1,475 @@ +package at.hannibal2.skyhanni.features.inventory.caketracker + +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.config.features.inventory.CakeTrackerConfig.CakeTrackerDisplayOrderType +import at.hannibal2.skyhanni.config.features.inventory.CakeTrackerConfig.CakeTrackerDisplayType +import at.hannibal2.skyhanni.config.storage.ProfileSpecificStorage.CakeData +import at.hannibal2.skyhanni.data.ProfileStorageData +import at.hannibal2.skyhanni.events.ConfigLoadEvent +import at.hannibal2.skyhanni.events.GuiContainerEvent +import at.hannibal2.skyhanni.events.GuiRenderEvent +import at.hannibal2.skyhanni.events.InventoryCloseEvent +import at.hannibal2.skyhanni.events.InventoryFullyOpenedEvent +import at.hannibal2.skyhanni.events.LorenzChatEvent +import at.hannibal2.skyhanni.events.SecondPassedEvent +import at.hannibal2.skyhanni.features.inventory.patternGroup +import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule +import at.hannibal2.skyhanni.utils.ChatUtils +import at.hannibal2.skyhanni.utils.ColorUtils.toChromaColor +import at.hannibal2.skyhanni.utils.ConditionalUtils +import at.hannibal2.skyhanni.utils.ConfigUtils.jumpToEditor +import at.hannibal2.skyhanni.utils.HypixelCommands +import at.hannibal2.skyhanni.utils.InventoryUtils +import at.hannibal2.skyhanni.utils.InventoryUtils.getUpperItems +import at.hannibal2.skyhanni.utils.ItemPriceUtils.getPrice +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.toInternalName +import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators +import at.hannibal2.skyhanni.utils.NumberUtil.formatInt +import at.hannibal2.skyhanni.utils.RegexUtils.matchGroup +import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher +import at.hannibal2.skyhanni.utils.RegexUtils.matches +import at.hannibal2.skyhanni.utils.RenderUtils.highlight +import at.hannibal2.skyhanni.utils.RenderUtils.renderRenderables +import at.hannibal2.skyhanni.utils.SimpleTimeMark +import at.hannibal2.skyhanni.utils.SkyBlockTime +import at.hannibal2.skyhanni.utils.TimeLimitedCache +import at.hannibal2.skyhanni.utils.renderables.Renderable +import net.minecraft.inventory.ContainerChest +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import java.awt.Color +import kotlin.math.abs +import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.minutes + +private typealias DisplayOrder = CakeTrackerDisplayOrderType +private typealias DisplayType = CakeTrackerDisplayType + +@SkyHanniModule +object CakeTracker { + + private val storage get() = ProfileStorageData.profileSpecific?.cakeData + private val config get() = SkyHanniMod.feature.inventory.cakeTracker + + private var currentYear = 0 + private var inCakeInventory = false + private var timeOpenedCakeInventory = SimpleTimeMark.farPast() + private var inAuctionHouse = false + private var slotHighlightCache = mapOf() + private var searchingForCakes = false + private var knownCakesInCurrentInventory = listOf() + private val cakePriceCache: TimeLimitedCache = TimeLimitedCache(5.minutes) + + private var cakeRenderables = listOf() + private var lastKnownCakeDataHash = 0 + + private val unobtainedHighlightColor: Color get() = config.unobtainedAuctionHighlightColor.toChromaColor() + private val obtainedHighlightColor: Color get() = config.obtainedAuctionHighlightColor.toChromaColor() + + /** + * REGEX-TEST: §cNew Year Cake (Year 360) + * REGEX-TEST: §cNew Year Cake (Year 1,000) + * REGEX-TEST: §f§f§cNew Year Cake (Year 330) + * REGEX-TEST: §f§f§cNew Year Cake (Year 49) + */ + private val cakeNamePattern by patternGroup.pattern( + "cake.name", + "(?:§f§f)?§cNew Year Cake \\(Year (?[\\d,]+)\\)", + ) + + /** + * REGEX-TEST: §eYou purchased §r§f§r§f§r§cNew Year Cake (Year 143) §r§efor §r§62,000,000 coins§r§e! + */ + private val cakePurchasedPattern by patternGroup.pattern( + "cake.purchased", + "§eYou purchased (?:§.)*New Year Cake \\(Year (?[\\d,]+)\\) (?:§.)*for (?:§.)+(?[\\d,]+) coins(?:§.)+!", + ) + + /** + * REGEX-TEST: Ender Chest (2/9) + * REGEX-TEST: Jumbo Backpack (Slot #6) + * REGEX-TEST: New Year Cake Bag + * REGEX-TEST: Large Chest + * REGEX-TEST: Chest + */ + private val cakeContainerPattern by patternGroup.pattern( + "cake.container", + "Ender Chest \\(\\d{1,2}/\\d{1,2}\\)|.*Backpack(?:§r)? \\(Slot #\\d{1,2}\\)|New Year Cake Bag|(Large )?Chest", + ) + + /** + * REGEX-TEST: Auctions Browser + * REGEX-TEST: Auctions: "Test" + * REGEX-TEST: Auctions: "New Year Cake (Year + */ + private val auctionBrowserPattern by patternGroup.pattern( + "auction.search", + "Auctions Browser|Auctions: \".*", + ) + + /** + * REGEX-TEST: Auctions: "New Year C + */ + private val auctionCakeSearchPattern by patternGroup.pattern( + "auction.cakesearch", + "Auctions: \"New Year C.*", + ) + + private fun addCake(cakeYear: Int) { + val storage = storage ?: return + val changed = storage.ownedCakes.add(cakeYear) + if (changed) recalculateMissingCakes() + } + + private fun removeCake(cakeYear: Int) { + val storage = storage ?: return + val changed = storage.ownedCakes.remove(cakeYear) + if (changed) recalculateMissingCakes() + } + + private fun isEnabled() = LorenzUtils.inSkyBlock && config.enabled + + @HandleEvent + fun onCommandRegistration(event: CommandRegistrationEvent) { + event.register("shresetcaketracker") { + description = "Resets the New Year Cake Tracker" + category = CommandCategory.USERS_RESET + callback { + val storage = storage ?: return@callback + storage.ownedCakes.clear() + recalculateMissingCakes() + ChatUtils.chat("New Year Cake tracker data reset") + } + } + } + + @SubscribeEvent + fun onChat(event: LorenzChatEvent) { + if (!isEnabled()) return + cakePurchasedPattern.matchMatcher(event.message) { + val year = group("year").formatInt() + addCake(year) + } + } + + @SubscribeEvent + fun onConfigLoad(event: ConfigLoadEvent) { + ConditionalUtils.onToggle(config.maxDisplayRows) { + lastKnownCakeDataHash = 0 + } + } + + @SubscribeEvent + fun onBackgroundDraw(event: GuiRenderEvent.ChestGuiOverlayRenderEvent) { + if (!isEnabled()) return + val inInvWithCakes = inCakeInventory && knownCakesInCurrentInventory.any() + val inAuctionWithCakes = inAuctionHouse && (slotHighlightCache.isNotEmpty() || searchingForCakes) + if (inInvWithCakes || inAuctionWithCakes) { + reRenderDisplay() + } + } + + @SubscribeEvent + fun onBackgroundDraw(event: GuiContainerEvent.BackgroundDrawnEvent) { + if (!isEnabled()) return + if (inCakeInventory) checkInventoryCakes() + if (!inAuctionHouse) return + + (event.gui.inventorySlots as ContainerChest).getUpperItems().forEach { (slot, _) -> + slotHighlightCache[slot.slotIndex]?.let { color -> + slot highlight color + } + } + } + + @SubscribeEvent + fun onInventoryOpen(event: InventoryFullyOpenedEvent) { + if (!isEnabled()) return + knownCakesInCurrentInventory = listOf() + checkCakeContainer(event) + inAuctionHouse = checkAuctionCakes(event) + } + + private fun reRenderDisplay() { + config.cakeTrackerPosition.renderRenderables( + drawDisplay(storage ?: return), + posLabel = "New Year Cake Tracker", + ) + } + + private fun checkCakeContainer(event: InventoryFullyOpenedEvent) { + if (!cakeContainerPattern.matches(event.inventoryName)) return + knownCakesInCurrentInventory = event.inventoryItems.values.mapNotNull { item -> + cakeNamePattern.matchMatcher(item.displayName) { + val year = group("year").formatInt() + addCake(year) + year + } + }.toMutableList() + inCakeInventory = true + timeOpenedCakeInventory = SimpleTimeMark.now() + } + + private fun checkAuctionCakes(event: InventoryFullyOpenedEvent): Boolean { + if (!auctionBrowserPattern.matches(event.inventoryName)) return false + searchingForCakes = auctionCakeSearchPattern.matches(event.inventoryName) + slotHighlightCache = event.inventoryItems.filter { + cakeNamePattern.matches(it.value.displayName) + }.mapValues { (_, item) -> + val year = cakeNamePattern.matchGroup(item.displayName, "year")?.toInt() ?: -1 + val owned = storage?.ownedCakes?.contains(year) ?: false + if (owned) obtainedHighlightColor else unobtainedHighlightColor + } + return true + } + + @SubscribeEvent + fun onInventoryClose(event: InventoryCloseEvent) { + inCakeInventory = false + knownCakesInCurrentInventory = listOf() + inAuctionHouse = false + slotHighlightCache = mapOf() + searchingForCakes = false + } + + @SubscribeEvent + fun onSecondPassed(event: SecondPassedEvent) { + if (!isEnabled()) return + val sbTimeNow = SkyBlockTime.now() + if (currentYear == sbTimeNow.year) return + if (sbTimeNow.month == 12 && sbTimeNow.day >= 29) { + currentYear = sbTimeNow.year + recalculateMissingCakes() + } else currentYear = sbTimeNow.year - 1 + } + + private fun checkInventoryCakes() { + if (timeOpenedCakeInventory.passedSince() < 500.milliseconds) return + val currentYears = InventoryUtils.getItemsInOpenChest().mapNotNull { item -> + cakeNamePattern.matchGroup(item.stack.displayName, "year")?.toInt() + } + + val addedYears = currentYears.filter { it !in knownCakesInCurrentInventory } + val removedYears = knownCakesInCurrentInventory.filter { it !in currentYears } + + addedYears.forEach(::addCake) + removedYears.forEach(::removeCake) + + if (addedYears.isNotEmpty() || removedYears.isNotEmpty()) { + knownCakesInCurrentInventory = currentYears.toMutableList() + } + } + + private fun recalculateMissingCakes() { + val storage = storage ?: return + storage.missingCakes = (1..currentYear).toSet() - storage.ownedCakes + } + + private fun getCakePrice(year: Int): Double { + return cakePriceCache.getOrPut(year) { + val cakeItem = "NEW_YEAR_CAKE+$year".toInternalName() + cakeItem.getPrice() + } + } + + private fun getCakePriceString(year: Int): String { + return getCakePrice(year).takeIf { it > 0 }?.let { + "§6${it.addSeparators()}" + } ?: "§7Unknown (no auctions)" + } + + private data class CakeRange(var start: Int, var end: Int = 0) { + val isSingular = (start == end || end == 0) + + fun getRenderable(displayType: DisplayType): Renderable { + val colorCode = if (displayType == DisplayType.OWNED_CAKES) "§a" else "§c" + val baseRenderable = getHoverable(colorCode) + return if (displayType == DisplayType.MISSING_CAKES) Renderable.link( + baseRenderable, + { HypixelCommands.auctionSearch("New Year Cake (Year $start)") }, + ) else baseRenderable + } + + fun getHoverable(colorCode: String): Renderable { + val displayString = + if (isSingular) "§fYear $colorCode$start" + else "§fYears $colorCode$start§f-$colorCode$end" + + return if (!config.priceOnHover) Renderable.string(displayString) + else Renderable.hoverTips(displayString, getPriceHoverTooltip(colorCode)) + } + + fun getPriceHoverTooltip(colorCode: String): List { + return if (isSingular) { + listOf("${colorCode}Year $start§7: ${getCakePriceString(start)}") + } else buildList { + val largerNumber = if (start > end) start else end + val smallerNumber = if (start < end) start else end + val numericalRange = smallerNumber..largerNumber + val rangeLength = abs(end - start) + 1 + + numericalRange.take(5).forEach { year -> + add("${colorCode}Year $year§7: ${getCakePriceString(year)}") + } + if (rangeLength >= 5) add("§7§o... and ${rangeLength - 5} more") + add("") + add("§aTotal§7: §6${numericalRange.sumOf(::getCakePrice).addSeparators()}") + } + } + } + + private fun setDisplayType(type: DisplayType) { + config.displayType = type + lastKnownCakeDataHash = 0 + } + + private fun buildDisplayTypeToggle(): Renderable = Renderable.horizontalContainer( + buildList { + val ownedColor = if (config.displayType == DisplayType.OWNED_CAKES) "§a" else "§e" + val missingColor = if (config.displayType == DisplayType.MISSING_CAKES) "§a" else "§e" + + add( + Renderable.optionalLink( + "$ownedColor[Owned]", + { setDisplayType(DisplayType.OWNED_CAKES) }, + condition = { config.displayType != DisplayType.OWNED_CAKES }, + ), + ) + add(Renderable.string(" ")) + add( + Renderable.optionalLink( + "$missingColor[Missing]", + { setDisplayType(DisplayType.MISSING_CAKES) }, + condition = { config.displayType != DisplayType.MISSING_CAKES }, + ), + ) + }, + ) + + private fun setDisplayOrderType(type: DisplayOrder) { + config.displayOrderType = type + lastKnownCakeDataHash = 0 + } + + private fun buildOrderTypeToggle(): Renderable = Renderable.horizontalContainer( + buildList { + val newestColor = if (config.displayOrderType == DisplayOrder.NEWEST_FIRST) "§a" else "§e" + val oldestColor = if (config.displayOrderType == DisplayOrder.OLDEST_FIRST) "§a" else "§e" + + add( + Renderable.optionalLink( + "$newestColor[Newest First]", + { setDisplayOrderType(DisplayOrder.NEWEST_FIRST) }, + condition = { config.displayOrderType != DisplayOrder.NEWEST_FIRST }, + ), + ) + add(Renderable.string(" ")) + add( + Renderable.optionalLink( + "$oldestColor[Oldest First]", + { setDisplayOrderType(DisplayOrder.OLDEST_FIRST) }, + condition = { config.displayOrderType != DisplayOrder.OLDEST_FIRST }, + ), + ) + }, + ) + + private fun drawDisplay(data: CakeData): List = buildList { + val dataHash = data.hashCode() + if (dataHash != lastKnownCakeDataHash) { + cakeRenderables = buildCakeRenderables(data) + lastKnownCakeDataHash = dataHash + } + + addAll(cakeRenderables) + } + + private fun getHeaderTips(data: CakeData) = buildList { + val unknownOwned = data.ownedCakes.count { getCakePrice(it) == 0.0 } + val unknownMissing = data.missingCakes.count { getCakePrice(it) == 0.0 } + + add("§aHave§7: §a${data.ownedCakes.size}") + add("§6Total value§7: §6${data.ownedCakes.sumOf(::getCakePrice).addSeparators()}") + if (unknownOwned > 0) add(" §7§o* $unknownOwned unknown prices") + add("") + add("§cMissing§7: §c${data.missingCakes.size}") + add("§6Total cost§7: §6${data.missingCakes.sumOf(::getCakePrice).addSeparators()}") + if (unknownMissing > 0) add(" §7§o* $unknownMissing unknown prices") + add("") + add("§bPercent owned§7: §a${"%.2f".format(data.ownedCakes.size * 100.0 / currentYear)}%") + } + + private fun buildCakeRenderables(data: CakeData) = buildList { + add(Renderable.hoverTips("§c§lNew §f§lYear §c§lCake §f§lTracker", getHeaderTips(data))) + add(buildDisplayTypeToggle()) + add(buildOrderTypeToggle()) + + val cakeList = when (config.displayType) { + DisplayType.OWNED_CAKES -> data.ownedCakes + DisplayType.MISSING_CAKES -> data.missingCakes + null -> data.missingCakes + } + + if (cakeList.isEmpty()) { + val colorCode = if (config.displayType == DisplayType.OWNED_CAKES) "§c" else "§a" + val verbiage = if (config.displayType == DisplayType.OWNED_CAKES) "missing" else "owned" + add(Renderable.string("$colorCode§lAll cakes $verbiage!")) + } else addCakeRanges(cakeList, config.displayOrderType, config.displayType) + } + + private fun MutableList.addCakeRanges( + cakeList: Set, + orderType: DisplayOrder, + displayType: DisplayType, + ) { + val sortedCakes = when (orderType) { + DisplayOrder.OLDEST_FIRST -> cakeList.sorted() + DisplayOrder.NEWEST_FIRST -> cakeList.sortedDescending() + } + + // Combine consecutive years into ranges + // + 3 is to account for the header and selector boxes + val maxDisplayRows = config.maxDisplayRows.get() + 3 + var start = sortedCakes.first() + var end = start + var hiddenRows = 0 + + for (year in sortedCakes.drop(1)) { // Skip the first item to prevent duplicate addition + if ((orderType == DisplayOrder.OLDEST_FIRST && year == end + 1) || + (orderType == DisplayOrder.NEWEST_FIRST && year == end - 1) + ) { + end = year + } else { + if (this.size < maxDisplayRows) { + val range = if (start != end) CakeRange(start, end) else CakeRange(start) + add(range.getRenderable(displayType)) + } else { + hiddenRows++ + start = year + end = start + continue + } + start = year + end = start + } + } + + if (this.size < maxDisplayRows) { + val lastRange = if (start != end) CakeRange(start, end) else CakeRange(start) + add(lastRange.getRenderable(displayType)) + } else { + hiddenRows++ + } + + if (hiddenRows > 0) add( + Renderable.clickAndHover( + "§7§o($hiddenRows hidden rows)", + tips = listOf("§eClick to configure # of displayed rows"), + onClick = { config::maxDisplayRows.jumpToEditor() }, + ), + ) + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/utils/tracker/SkyHanniTracker.kt b/src/main/java/at/hannibal2/skyhanni/utils/tracker/SkyHanniTracker.kt index a86ffb001ed6..efe1c1627ced 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/tracker/SkyHanniTracker.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/tracker/SkyHanniTracker.kt @@ -104,9 +104,9 @@ open class SkyHanniTracker( if (isEmpty()) return@buildList if (inventoryOpen) { add(buildDisplayModeView()) - } - if (inventoryOpen && getDisplayMode() == DisplayMode.SESSION) { - add(buildSessionResetButton()) + if (getDisplayMode() == DisplayMode.SESSION) { + add(buildSessionResetButton()) + } } }