aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/at
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/at')
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/ConfigUpdaterMigrator.kt2
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/features/chat/FilterTypesConfig.java13
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/features/chat/PowderMiningFilterConfig.java116
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/features/chat/PowderMiningGemstoneFilterConfig.java62
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/chat/ChatFilter.kt47
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/chat/PowderMiningChatFilter.kt385
6 files changed, 600 insertions, 25 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/config/ConfigUpdaterMigrator.kt b/src/main/java/at/hannibal2/skyhanni/config/ConfigUpdaterMigrator.kt
index 04ab9f69f..d42dfbbbf 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<String>, 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 c87102b5b..0187af82e 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,12 +2,18 @@ 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.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)")
@ConfigEditorBoolean
@@ -51,13 +57,6 @@ public class FilterTypesConfig {
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
@FeatureToggle
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 000000000..7eb2f19b8
--- /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<SimplePowderMiningRewardTypes> 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 000000000..2b4936af1
--- /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 bc14934ab..a4ffb7e7e 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 000000000..600a615ae
--- /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}(?<reward>§.+?[^§]*)(?: §r§8x(?<amount>[\\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(?<amount>[\\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(?<amount>[\\d,]+))?",
+ )
+
+ /**
+ * REGEX-TEST: §r§9Ascension Rope
+ */
+ private val ascensionRopeRewardPattern by patternGroup.pattern(
+ "reward.ascensionrope",
+ "§r§9Ascension Rope( §r§8x(?<amount>[\\d,]+))?",
+ )
+
+ /**
+ * REGEX-TEST: §r§aWishing Compass
+ */
+ private val wishingCompassRewardPattern by patternGroup.pattern(
+ "reward.wishingcompass",
+ "§r§aWishing Compass( §r§8x(?<amount>[\\d,]+))?",
+ )
+
+ /**
+ * REGEX-TEST: §r§aOil Barrel
+ */
+ private val oilBarrelRewardPattern by patternGroup.pattern(
+ "reward.oilbarrel",
+ "§r§aOil Barrel( §r§8x(?<amount>[\\d,]+))?",
+ )
+
+ /**
+ * REGEX-TEST: §r§fPrehistoric Egg
+ */
+ private val prehistoricEggPattern by patternGroup.pattern(
+ "reward.prehistoricegg",
+ "§r§fPrehistoric Egg( §r§8x(?<amount>[\\d,]+))?",
+ )
+
+ /**
+ * REGEX-TEST: §r§5Pickonimbus 2000
+ */
+ private val pickonimbusPattern by patternGroup.pattern(
+ "reward.pickonimbus",
+ "§r§5Pickonimbus 2000( §r§8x(?<amount>[\\d,]+))?",
+ )
+
+ /**
+ * REGEX-TEST: §r§6Jungle Heart
+ */
+ private val jungleHeartPattern by patternGroup.pattern(
+ "reward.jungleheart",
+ "§r§6Jungle Heart( §r§8x(?<amount>[\\d,]+))?",
+ )
+
+ /**
+ * REGEX-TEST: §r§aSludge Juice
+ */
+ private val sludgeJuicePattern by patternGroup.pattern(
+ "reward.sludgejuice",
+ "§r§aSludge Juice( §r§8x(?<amount>[\\d,]+))?",
+ )
+
+ /**
+ * REGEX-TEST: §r§aYoggie
+ */
+ private val yoggiePattern by patternGroup.pattern(
+ "reward.yoggie",
+ "§r§aYoggie( §r§8x(?<amount>[\\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(?<amount>[\\d,]+))?",
+ )
+
+ /**
+ * REGEX-TEST: §r§5Treasurite
+ */
+ private val treasuritePattern by patternGroup.pattern(
+ "reward.treasurite",
+ "§r§5Treasurite( §r§8x(?<amount>[\\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",
+ "(?:§.)*(?<color>[a-zA-Z]+)? ?Goblin Egg( §r§8x(?<amount>[\\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][❤❈☘⸕✎✧] (?<tier>Rough|Flawed|Fine) (?<gem>Ruby|Amethyst|Jade|Amber|Sapphire|Topaz) Gemstone( §r§8x(?<amount>[\\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 ""
+ }
+}