diff --git a/src/main/java/at/hannibal2/skyhanni/config/ConfigUpdaterMigrator.kt b/src/main/java/at/hannibal2/skyhanni/config/ConfigUpdaterMigrator.kt index 04ab9f69f891..d42dfbbbf670 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 = 51 + const val CONFIG_VERSION = 52 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/chat/FilterTypesConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/chat/FilterTypesConfig.java index c87102b5b9bc..0187af82eac6 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/chat/FilterTypesConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/chat/FilterTypesConfig.java @@ -2,11 +2,17 @@ import at.hannibal2.skyhanni.config.FeatureToggle; import com.google.gson.annotations.Expose; +import io.github.notenoughupdates.moulconfig.annotations.Accordion; import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean; import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; public class FilterTypesConfig { + @Expose + @ConfigOption(name = "Powder Mining", desc = "") + @Accordion + public PowderMiningFilterConfig powderMiningFilter = new PowderMiningFilterConfig(); + @Expose @ConfigOption(name = "Hypixel Lobbies", desc = "Hide announcements in Hypixel lobbies " + "(player joins, loot boxes, prototype lobby messages, radiating generosity, Hypixel tournaments)") @@ -50,13 +56,6 @@ public class FilterTypesConfig { @FeatureToggle public boolean winterGift = false; - @Expose - @ConfigOption(name = "Powder Mining", desc = "Hide messages while opening chests in the Crystal Hollows. " + - "(except powder numbers over 1k, essence numbers over 2, Prehistoric Eggs, and Automaton Parts)") - @ConfigEditorBoolean - @FeatureToggle - public boolean powderMining = false; - @Expose @ConfigOption(name = "Kill Combo", desc = "Hide messages about your Kill Combo from the Grandma Wolf pet.") @ConfigEditorBoolean diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/chat/PowderMiningFilterConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/chat/PowderMiningFilterConfig.java new file mode 100644 index 000000000000..7eb2f19b8a0f --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/chat/PowderMiningFilterConfig.java @@ -0,0 +1,116 @@ +package at.hannibal2.skyhanni.config.features.chat; + +import at.hannibal2.skyhanni.config.FeatureToggle; +import com.google.gson.annotations.Expose; +import io.github.notenoughupdates.moulconfig.annotations.Accordion; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorDraggableList; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorDropdown; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorSlider; +import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static at.hannibal2.skyhanni.config.features.chat.PowderMiningFilterConfig.SimplePowderMiningRewardTypes.ASCENSION_ROPE; +import static at.hannibal2.skyhanni.config.features.chat.PowderMiningFilterConfig.SimplePowderMiningRewardTypes.JUNGLE_HEART; +import static at.hannibal2.skyhanni.config.features.chat.PowderMiningFilterConfig.SimplePowderMiningRewardTypes.OIL_BARREL; +import static at.hannibal2.skyhanni.config.features.chat.PowderMiningFilterConfig.SimplePowderMiningRewardTypes.SLUDGE_JUICE; +import static at.hannibal2.skyhanni.config.features.chat.PowderMiningFilterConfig.SimplePowderMiningRewardTypes.TREASURITE; +import static at.hannibal2.skyhanni.config.features.chat.PowderMiningFilterConfig.SimplePowderMiningRewardTypes.WISHING_COMPASS; +import static at.hannibal2.skyhanni.config.features.chat.PowderMiningFilterConfig.SimplePowderMiningRewardTypes.YOGGIE; + +public class PowderMiningFilterConfig { + @Expose + @ConfigOption(name = "Enabled", desc = "Hide messages while opening chests in the Crystal Hollows.") + @ConfigEditorBoolean + @FeatureToggle + public boolean enabled = false; + + @Expose + @ConfigOption( + name = "Powder", desc = "Hide §dGemstone §7and §aMithril §7Powder rewards under a certain amount." + + "\n§a0§7: §aShow all\n§c60000§7: §cHide all" + ) + @ConfigEditorSlider(minValue = 0, maxValue = 60000, minStep = 500) + public int powderFilterThreshold = 1000; + + @Expose + @ConfigOption( + name = "Essence", desc = "Hide §6Gold §7and §bDiamond §7Essence rewards under a certain amount." + + "\n§a0§7: §aShow all\n§c20§7: §cHide all" + ) + @ConfigEditorSlider(minValue = 0, maxValue = 20, minStep = 1) + public int essenceFilterThreshold = 5; + + public enum SimplePowderMiningRewardTypes { + + ASCENSION_ROPE("§9Ascension Rope"), + WISHING_COMPASS("§aWishing Compass"), + OIL_BARREL("§aOil Barrel"), + PREHISTORIC_EGG("§fPrehistoric Egg"), + PICKONIMBUS("§5Pickonimbus 2000"), + JUNGLE_HEART("§6Jungle Heart"), + SLUDGE_JUICE("§aSludge Juice"), + YOGGIE("§aYoggie"), + ROBOT_PARTS("§9Robot Parts"), + TREASURITE("§5Treasurite"), + ; + + private final String name; + + SimplePowderMiningRewardTypes(String name) { + this.name = name; + } + + @Override + public String toString() { + return name; + } + } + + @Expose + @ConfigOption(name = "Common Items", desc = "Hide reward messages for listed items.") + @ConfigEditorDraggableList + public List simplePowderMiningTypes = new ArrayList<>(Arrays.asList( + ASCENSION_ROPE, + WISHING_COMPASS, + OIL_BARREL, + JUNGLE_HEART, + SLUDGE_JUICE, + YOGGIE, + TREASURITE + )); + + @Expose + @ConfigOption(name = "Goblin Egg", desc = "Hide Goblin Egg rewards that are below a certain rarity.") + @ConfigEditorDropdown + public GoblinEggFilterEntry goblinEggs = GoblinEggFilterEntry.YELLOW_UP; + + public enum GoblinEggFilterEntry { + SHOW_ALL("Show all"), + HIDE_ALL("Hide all"), + GREEN_UP("Show §aGreen §7and up"), + YELLOW_UP("Show §eYellow §7and up"), + RED_UP("Show §cRed §7and up"), + BLUE_ONLY("Show §3Blue §7only"); + + private final String name; + + GoblinEggFilterEntry(String name) { + this.name = name; + } + + @Override + public String toString() { + return name; + } + } + + @Expose + @ConfigOption(name = "Gemstones", desc = "") + @Accordion + public PowderMiningGemstoneFilterConfig gemstoneFilterConfig = new PowderMiningGemstoneFilterConfig(); + +} diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/chat/PowderMiningGemstoneFilterConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/chat/PowderMiningGemstoneFilterConfig.java new file mode 100644 index 000000000000..2b4936af1ecf --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/chat/PowderMiningGemstoneFilterConfig.java @@ -0,0 +1,62 @@ +package at.hannibal2.skyhanni.config.features.chat; + +import com.google.gson.annotations.Expose; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorDropdown; +import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; + +public class PowderMiningGemstoneFilterConfig { + + @Expose + @ConfigOption(name = "Stronger Tool Messages", desc = "Hide 'You need a stronger tool..' messages.") + @ConfigEditorBoolean + public boolean strongerToolMessages = true; + + @Expose + @ConfigOption(name = "Ruby", desc = "Hide Ruby gemstones under a certain quality.") + @ConfigEditorDropdown + public GemstoneFilterEntry rubyGemstones = GemstoneFilterEntry.FINE_ONLY; + + @Expose + @ConfigOption(name = "Sapphire", desc = "Hide Sapphire gemstones under a certain quality.") + @ConfigEditorDropdown + public GemstoneFilterEntry sapphireGemstones = GemstoneFilterEntry.FINE_ONLY; + + @Expose + @ConfigOption(name = "Amber", desc = "Hide Amber gemstones under a certain quality.") + @ConfigEditorDropdown + public GemstoneFilterEntry amberGemstones = GemstoneFilterEntry.FINE_ONLY; + + @Expose + @ConfigOption(name = "Amethyst", desc = "Hide Amethyst gemstones under a certain quality.") + @ConfigEditorDropdown + public GemstoneFilterEntry amethystGemstones = GemstoneFilterEntry.FINE_ONLY; + + @Expose + @ConfigOption(name = "Jade", desc = "Hide Jade gemstones under a certain quality.") + @ConfigEditorDropdown + public GemstoneFilterEntry jadeGemstones = GemstoneFilterEntry.FINE_ONLY; + + @Expose + @ConfigOption(name = "Topaz", desc = "Hide Topaz gemstones under a certain quality.") + @ConfigEditorDropdown + public GemstoneFilterEntry topazGemstones = GemstoneFilterEntry.FINE_ONLY; + + public enum GemstoneFilterEntry { + SHOW_ALL("Show All"), + HIDE_ALL("Hide all"), + FLAWED_UP("Show §aFlawed §7or higher"), + FINE_ONLY("Show §9Fine §7only"); + + private final String str; + + GemstoneFilterEntry(String str) { + this.str = str; + } + + @Override + public String toString() { + return str; + } + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/chat/ChatFilter.kt b/src/main/java/at/hannibal2/skyhanni/features/chat/ChatFilter.kt index bc14934abe2e..a4ffb7e7e4c6 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/chat/ChatFilter.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/chat/ChatFilter.kt @@ -4,13 +4,18 @@ import at.hannibal2.skyhanni.SkyHanniMod import at.hannibal2.skyhanni.config.ConfigUpdaterMigrator import at.hannibal2.skyhanni.data.HypixelData import at.hannibal2.skyhanni.events.LorenzChatEvent +import at.hannibal2.skyhanni.features.chat.PowderMiningChatFilter.genericMiningRewardMessage import at.hannibal2.skyhanni.features.dungeon.DungeonAPI import at.hannibal2.skyhanni.features.garden.GardenAPI import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.NumberUtil.formatInt +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.StringUtils import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern +import net.minecraft.util.ChatComponentText import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import java.util.regex.Pattern @@ -324,20 +329,6 @@ object ChatFilter { "§cThis gift is for §r.*§r§c, sorry!".toPattern(), ) - // Powder Mining - private val powderMiningPatterns = listOf( - "§cYou need a stronger tool to mine (Amethyst|Ruby|Jade|Amber|Sapphire|Topaz) Gemstone Block§r§c.".toPattern(), - "§aYou received §r§f\\d* §r§f[❤❈☘⸕✎✧] Rough (Ruby|Amethyst|Jade|Amber|Sapphire|Topaz) Gemstone§r§a\\.".toPattern(), - "§aYou received §r§f\\d §r§a[❤❈☘⸕✎✧] Flawed (Ruby|Amethyst|Jade|Amber|Sapphire|Topaz) Gemstone§r§a\\.".toPattern(), - - // Jungle - "§aYou received §r§f\\d* §r§aSludge Juice§r§a\\.".toPattern(), - - // Useful, maybe in another chat - "§aYou received §r§b\\+\\d{1,3} §r§a(Mithril|Gemstone) Powder.".toPattern(), - "§aYou received §r(§6|§b)\\+[1-2] (Diamond|Gold) Essence§r§a.".toPattern(), - ) - private val fireSalePattern by RepoPattern.pattern( "chat.firesale", "§6§k§lA§r §c§lFIRE SALE §r§6§k§lA(?:\\n|.)*", @@ -428,7 +419,6 @@ object ChatFilter { "winter_island" to winterIslandPatterns, "annoying_spam" to annoyingSpamPatterns, "winter_gift" to winterGiftPatterns, - "powder_mining" to powderMiningPatterns, "fire_sale" to fireSalePatterns, "event" to eventPatterns, "factory_upgrade" to factoryUpgradePatterns, @@ -469,7 +459,8 @@ object ChatFilter { @SubscribeEvent fun onChat(event: LorenzChatEvent) { - val blockReason = block(event.message) + var blockReason = block(event.message) + if (blockReason == "" && config.powderMiningFilter.enabled) blockReason = powderMiningBlock(event) if (blockReason == "") return event.blockedReason = blockReason @@ -494,7 +485,6 @@ object ChatFilter { config.others && isOthers(message) -> othersMsg config.winterGift && message.isPresent("winter_gift") -> "winter_gift" - config.powderMining && message.isPresent("powder_mining") -> "powder_mining" config.eventLevelUp && (message.isPresent("event") || StringUtils.isEmpty(message)) -> "event" config.fireSale && (fireSalePattern.matches(message) || message.isPresent("fire_sale")) -> "fire_sale" config.factoryUpgrade && message.isPresent("factory_upgrade") -> "factory_upgrade" @@ -509,6 +499,28 @@ object ChatFilter { else -> "" } + /** + * Checks if the message is a blocked powder mining message, as defined in PowderMiningChatFilter. + * Will modify un-filtered Mining rewards, or return a resultant blocking code + * @param event The event to check + * @return Block reason if applicable + * @see block + */ + private fun powderMiningBlock(event: LorenzChatEvent): String { + val powderMiningMatchResult = PowderMiningChatFilter.block(event.message) + if (powderMiningMatchResult == "no_filter") { + genericMiningRewardMessage.matchMatcher(event.message) { + val reward = groupOrNull("reward") ?: "" + val amountFormat = groupOrNull("amount")?.let { + "§a+ §b$it§r" + } ?: "§a+§r" + event.chatComponent = ChatComponentText("$amountFormat $reward") + } + return "" + } + return powderMiningMatchResult + } + private var othersMsg = "" /** @@ -565,5 +577,6 @@ object ChatFilter { event.move(3, "chat.killCombo", "chat.filterType.killCombo") event.move(3, "chat.profileJoin", "chat.filterType.profileJoin") event.move(3, "chat.others", "chat.filterType.others") + event.move(52, "chat.filterType.powderMining", "chat.filterType.powderMiningFilter.enabled") } } diff --git a/src/main/java/at/hannibal2/skyhanni/features/chat/PowderMiningChatFilter.kt b/src/main/java/at/hannibal2/skyhanni/features/chat/PowderMiningChatFilter.kt new file mode 100644 index 000000000000..600a615ae954 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/chat/PowderMiningChatFilter.kt @@ -0,0 +1,385 @@ +package at.hannibal2.skyhanni.features.chat + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.config.features.chat.PowderMiningFilterConfig +import at.hannibal2.skyhanni.config.features.chat.PowderMiningFilterConfig.SimplePowderMiningRewardTypes.ASCENSION_ROPE +import at.hannibal2.skyhanni.config.features.chat.PowderMiningFilterConfig.SimplePowderMiningRewardTypes.JUNGLE_HEART +import at.hannibal2.skyhanni.config.features.chat.PowderMiningFilterConfig.SimplePowderMiningRewardTypes.OIL_BARREL +import at.hannibal2.skyhanni.config.features.chat.PowderMiningFilterConfig.SimplePowderMiningRewardTypes.PICKONIMBUS +import at.hannibal2.skyhanni.config.features.chat.PowderMiningFilterConfig.SimplePowderMiningRewardTypes.PREHISTORIC_EGG +import at.hannibal2.skyhanni.config.features.chat.PowderMiningFilterConfig.SimplePowderMiningRewardTypes.ROBOT_PARTS +import at.hannibal2.skyhanni.config.features.chat.PowderMiningFilterConfig.SimplePowderMiningRewardTypes.SLUDGE_JUICE +import at.hannibal2.skyhanni.config.features.chat.PowderMiningFilterConfig.SimplePowderMiningRewardTypes.TREASURITE +import at.hannibal2.skyhanni.config.features.chat.PowderMiningFilterConfig.SimplePowderMiningRewardTypes.WISHING_COMPASS +import at.hannibal2.skyhanni.config.features.chat.PowderMiningFilterConfig.SimplePowderMiningRewardTypes.YOGGIE +import at.hannibal2.skyhanni.config.features.chat.PowderMiningGemstoneFilterConfig.GemstoneFilterEntry +import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule +import at.hannibal2.skyhanni.test.command.ErrorManager +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 + +@SkyHanniModule +object PowderMiningChatFilter { + + private val config get() = SkyHanniMod.feature.chat.filterType.powderMiningFilter + private val gemstoneConfig get() = config.gemstoneFilterConfig + + val patternGroup = RepoPattern.group("filter.powdermining") + + private var unclosedRewards = false + + /** + * REGEX-TEST: §aYou uncovered a treasure chest! + */ + private val uncoverChestPattern by patternGroup.pattern( + "warning.chestuncover", + "§aYou uncovered a treasure chest!", + ) + + /** + * REGEX-TEST: §6You have successfully picked the lock on this chest! + */ + private val successfulPickPattern by patternGroup.pattern( + "warning.successpick", + "§6You have successfully picked the lock on this chest!", + ) + + /** + * REGEX-TEST: §cYou need a tool with a §r§aBreaking Power §r§cof §r§66§r§c to mine Ruby Gemstone Block§r§c! Speak to §r§dFragilis §r§cby the entrance to the Crystal Hollows to learn more! + */ + private val breakingPowerPattern by patternGroup.pattern( + "warning.breakingpower", + "§cYou need a tool with a §r§aBreaking Power §r§cof (?:§.)*\\d+§r§c to mine (Ruby|Amethyst|Jade|Amber|Sapphire|Topaz) Gemstone Block§r§c!.+", + ) + + /** + * REGEX-TEST: §e§l▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬ + * REGEX-TEST: §d§l▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬ + */ + private val chestWrapperPattern by patternGroup.pattern( + "powder.chestwrapper", + "^§[ed]§l▬{64}\$", + ) + + /** + * REGEX-TEST: §r§6§lCHEST LOCKPICKED + */ + private val lockPickedPattern by patternGroup.pattern( + "powder.picked", + ".*§r§6§lCHEST LOCKPICKED.*", + ) + + /** + * REGEX-TEST: §r§5§lLOOT CHEST COLLECTED + */ + private val lootChestCollectedPattern by patternGroup.pattern( + "lootchest.collected", + ".*§r§5§lLOOT CHEST COLLECTED.*", + ) + + /** + * REGEX-TEST: §r§a§lREWARDS + */ + private val rewardHeaderPattern by patternGroup.pattern( + "reward.header", + ".*§r§[af]§lREWARDS.*", + ) + + /** + * REGEX-TEST: §r§a§r§aGreen Goblin Egg + * REGEX-TEST: §r§9Goblin Egg + * REGEX-TEST: §r§dDiamond Essence + * REGEX-TEST: §r§dGold Essence + * REGEX-TEST: §r§dGold Essence §r§8x3 + * REGEX-TEST: §r§dGemstone Powder §r§8x537 + * REGEX-TEST: §r§dDiamond Essence §r§8x2 + * REGEX-TEST: §r§2Mithril Powder §r§8x153 + * REGEX-TEST: §r§5Treasurite + * REGEX-TEST: §r§f⸕ Rough Amber Gemstone §r§8x24 + * REGEX-TEST: §r§f❤ Rough Ruby Gemstone §r§8x24 + * REGEX-TEST: §r§f❈ Rough Amethyst Gemstone §r§8x24 + * REGEX-TEST: §r§9§r§eYellow Goblin Egg + * REGEX-TEST: §r§a⸕ Flawed Amber Gemstone + * REGEX-TEST: §r§aWishing Compass §r§8x3 + * REGEX-TEST: §r§a⸕ Flawed Amber Gemstone §r§8x2 + */ + val genericMiningRewardMessage by patternGroup.pattern( + "reward.generic", + " {4}(?§.+?[^§]*)(?: §r§8x(?[\\d,]+))?\$", + ) + + /** + * REGEX-TEST: §r§2Mithril Powder §r§8x153 + * REGEX-TEST: §r§dGemstone Powder §r§8x537 + */ + private val powderRewardPattern by patternGroup.pattern( + "reward.powder", + "§r§[d2](?:Gemstone|Mithril) Powder( §r§8x(?[\\d,]+))?", + ) + + /** + * REGEX-TEST: §r§dGold Essence + * REGEX-TEST: §r§dGold Essence §r§8x3 + * REGEX-TEST: §r§dDiamond Essence §r§8x2 + * REGEX-TEST: §r§dDiamond Essence + */ + private val essenceRewardPattern by patternGroup.pattern( + "reward.essence", + "§r§d(?:Gold|Diamond) Essence( §r§8x(?[\\d,]+))?", + ) + + /** + * REGEX-TEST: §r§9Ascension Rope + */ + private val ascensionRopeRewardPattern by patternGroup.pattern( + "reward.ascensionrope", + "§r§9Ascension Rope( §r§8x(?[\\d,]+))?", + ) + + /** + * REGEX-TEST: §r§aWishing Compass + */ + private val wishingCompassRewardPattern by patternGroup.pattern( + "reward.wishingcompass", + "§r§aWishing Compass( §r§8x(?[\\d,]+))?", + ) + + /** + * REGEX-TEST: §r§aOil Barrel + */ + private val oilBarrelRewardPattern by patternGroup.pattern( + "reward.oilbarrel", + "§r§aOil Barrel( §r§8x(?[\\d,]+))?", + ) + + /** + * REGEX-TEST: §r§fPrehistoric Egg + */ + private val prehistoricEggPattern by patternGroup.pattern( + "reward.prehistoricegg", + "§r§fPrehistoric Egg( §r§8x(?[\\d,]+))?", + ) + + /** + * REGEX-TEST: §r§5Pickonimbus 2000 + */ + private val pickonimbusPattern by patternGroup.pattern( + "reward.pickonimbus", + "§r§5Pickonimbus 2000( §r§8x(?[\\d,]+))?", + ) + + /** + * REGEX-TEST: §r§6Jungle Heart + */ + private val jungleHeartPattern by patternGroup.pattern( + "reward.jungleheart", + "§r§6Jungle Heart( §r§8x(?[\\d,]+))?", + ) + + /** + * REGEX-TEST: §r§aSludge Juice + */ + private val sludgeJuicePattern by patternGroup.pattern( + "reward.sludgejuice", + "§r§aSludge Juice( §r§8x(?[\\d,]+))?", + ) + + /** + * REGEX-TEST: §r§aYoggie + */ + private val yoggiePattern by patternGroup.pattern( + "reward.yoggie", + "§r§aYoggie( §r§8x(?[\\d,]+))?", + ) + + /** + * REGEX-TEST: §r§9FTX 3070 + * REGEX-TEST: §r§9Synthetic Heart + * REGEX-TEST: §r§9Control Switch + * REGEX-TEST: §r§9Robotron Reflector + * REGEX-TEST: §r§9Electron Transmitter + * REGEX-TEST: §r§9Superlite Motor + */ + private val robotPartsPattern by patternGroup.pattern( + "reward.robotparts", + "§r§9(?:FTX 3070|Synthetic Heart|Control Switch|Robotron Reflector|Electron Transmitter|Superlite Motor)( §r§8x(?[\\d,]+))?", + ) + + /** + * REGEX-TEST: §r§5Treasurite + */ + private val treasuritePattern by patternGroup.pattern( + "reward.treasurite", + "§r§5Treasurite( §r§8x(?[\\d,]+))?", + ) + + /** + * REGEX-TEST: §r§9§r§cRed Goblin Egg + * REGEX-TEST: §r§9§r§3Blue Goblin Egg + * REGEX-TEST: §r§9Goblin Egg + * REGEX-TEST: §r§9Goblin Egg §r§8x2 + * REGEX-TEST: §r§a§r§aGreen Goblin Egg + * REGEX-TEST: §r§9§r§eYellow Goblin Egg + */ + private val goblinEggPattern by patternGroup.pattern( + "reward.goblineggs", + "(?:§.)*(?[a-zA-Z]+)? ?Goblin Egg( §r§8x(?[\\d,]+))?", + ) + + /** + * REGEX-TEST: §r§f❈ Rough Amethyst Gemstone §r§8x24 + * REGEX-TEST: §r§a❈ Flawed Amethyst Gemstone §r§8x4 + * REGEX-TEST: §r§9⸕ Fine Amber Gemstone + */ + private val gemstonePattern by patternGroup.pattern( + "reward.gemstone", + "§r§[fa9][❤❈☘⸕✎✧] (?Rough|Flawed|Fine) (?Ruby|Amethyst|Jade|Amber|Sapphire|Topaz) Gemstone( §r§8x(?[\\d,]+))?", + ) + + fun block(message: String): String { + // Generic "you uncovered a chest" message + if (uncoverChestPattern.matches(message)) return "powder_mining_chest" + if (successfulPickPattern.matches(message)) return "powder_mining_picked" + // Breaking power warning + if (breakingPowerPattern.matches(message) && gemstoneConfig.strongerToolMessages) return "stronger_tool" + // Closing or opening a reward 'loop' with the spam of ▬ + if (chestWrapperPattern.matches(message)) { + unclosedRewards = !unclosedRewards + return "reward_wrapper" + } + + if (!unclosedRewards) return "" + if (lockPickedPattern.matches(message)) return "powder_chest_lockpicked" + if (lootChestCollectedPattern.matches(message)) return "loot_chest_opened" + if (rewardHeaderPattern.matches((message))) return "powder_reward_header" + + // All powder and loot chest rewards start with 4 spaces + // To simplify regex statements, this check is done outside + val ssMessage = message.takeIf { it.startsWith(" ") }?.substring(4) ?: return "" + + //Powder + powderRewardPattern.matchMatcher(ssMessage) { + if (config.powderFilterThreshold == 60000) return "powder_mining_powder" + val amountStr = groupOrNull("amount") ?: "1" + if (amountStr.isNotEmpty() && config.powderFilterThreshold > 0) { + val amountParsed = amountStr.replace(",", "").toInt() + return if (amountParsed < config.powderFilterThreshold) "powder_mining_powder" + else "no_filter" + } + } + + //Essence + essenceRewardPattern.matchMatcher(ssMessage) { + if (config.essenceFilterThreshold == 20) return "powder_mining_essence" + val amountStr = groupOrNull("amount") ?: "1" + if (amountStr.isNotEmpty() && config.essenceFilterThreshold > 0) { + val amountParsed = amountStr.toInt() + return if (amountParsed < config.essenceFilterThreshold) "powder_mining_essence" + else "no_filter" + } + } + + blockSimpleRewards(ssMessage).takeIf { it.isNotEmpty() }?.let { return it } + blockGoblinEggs(ssMessage).takeIf { it.isNotEmpty() }?.let { return it } + blockGemstones(ssMessage).takeIf { it.isNotEmpty() }?.let { return it } + + //Fallback default + return "" + } + + private fun blockSimpleRewards(ssMessage: String): String { + val rewardPatterns = mapOf( + ascensionRopeRewardPattern to ASCENSION_ROPE to "powder_mining_ascension_rope", + wishingCompassRewardPattern to WISHING_COMPASS to "powder_mining_wishing_compass", + oilBarrelRewardPattern to OIL_BARREL to "powder_mining_oil_barrel", + prehistoricEggPattern to PREHISTORIC_EGG to "powder_mining_prehistoric_egg", + pickonimbusPattern to PICKONIMBUS to "powder_mining_pickonimbus", + jungleHeartPattern to JUNGLE_HEART to "powder_mining_jungle_heart", + sludgeJuicePattern to SLUDGE_JUICE to "powder_mining_sludge_juice", + yoggiePattern to YOGGIE to "powder_mining_yoggie", + robotPartsPattern to ROBOT_PARTS to "powder_mining_robot_parts", + treasuritePattern to TREASURITE to "powder_mining_treasurite", + ) + for ((patternToReward, returnReason) in rewardPatterns) { + if (patternToReward.first.matches(ssMessage)) { + return if (config.simplePowderMiningTypes.contains(patternToReward.second)) returnReason + else "no_filter" + } + } + return "" + } + + private fun blockGoblinEggs(ssMessage: String): String { + goblinEggPattern.matchMatcher(ssMessage) { + if (config.goblinEggs == PowderMiningFilterConfig.GoblinEggFilterEntry.SHOW_ALL) return "no_filter" + if (config.goblinEggs == PowderMiningFilterConfig.GoblinEggFilterEntry.HIDE_ALL) return "powder_mining_goblin_eggs" + + val colorStr = groupOrNull("color")?.lowercase() ?: "" + return when (colorStr) { + //'Colorless', base goblin eggs will never be shown in this code path + "" -> "powder_mining_goblin_eggs" + "green" -> if (config.goblinEggs > PowderMiningFilterConfig.GoblinEggFilterEntry.GREEN_UP) { + "powder_mining_goblin_eggs" + } else "no_filter" + "yellow" -> if (config.goblinEggs > PowderMiningFilterConfig.GoblinEggFilterEntry.YELLOW_UP) { + "powder_mining_goblin_eggs" + } else "no_filter" + "red" -> if (config.goblinEggs > PowderMiningFilterConfig.GoblinEggFilterEntry.RED_UP) { + "powder_mining_goblin_eggs" + } else "no_filter" + // BLUE_ONLY enum not explicitly used in comparison, as the only + // case that will block it is HIDE_ALL, which is covered above + "blue" -> "no_filter" + else -> { + ErrorManager.logErrorWithData( + NoSuchElementException(), + "Unknown Goblin Egg color detected in Powder Mining Filter: '${colorStr}' - please report this in the Discord!", + noStackTrace = true + ) + "no_filter" + } + } + } + return "" + } + + private fun blockGemstones(ssMessage: String): String { + gemstonePattern.matchMatcher(ssMessage) { + val gemStr = groupOrNull("gem")?.lowercase() ?: "" + val tierStr = groupOrNull("tier")?.lowercase() ?: "" + + //Theoretically impossible but ? + if (gemStr.isEmpty() || tierStr.isEmpty()) return "" + + val gemSpecificFilterEntry = when (gemStr) { + "ruby" -> gemstoneConfig.rubyGemstones + "sapphire" -> gemstoneConfig.sapphireGemstones + "amber" -> gemstoneConfig.amberGemstones + "amethyst" -> gemstoneConfig.amethystGemstones + "jade" -> gemstoneConfig.jadeGemstones + "topaz" -> gemstoneConfig.topazGemstones + //Failure case that should never be reached + else -> return "no_filter" + } + + if (gemSpecificFilterEntry == GemstoneFilterEntry.HIDE_ALL) return "powder_mining_gemstones" + + return when (tierStr) { + // Never allowed through, except for in SHOW_ALL, + // which is handled above + "rough" -> "powder_mining_gemstones" + "flawed" -> if (gemSpecificFilterEntry > GemstoneFilterEntry.FLAWED_UP) { + "powder_mining_gemstones" + } else "no_filter" + // FINE_ONLY enum not explicitly used in comparison, as the only + // case that will block it is HIDE_ALL, which is covered above + "fine" -> "no_filter" + // This should not be reachable + else -> "no_filter" + } + } + return "" + } +}